Add sample for enqueuing work in a job.

am: 5229a90146

Change-Id: Idc0461e19fd7e14e2a41940b0db8a64f995d6db2
This commit is contained in:
Dianne Hackborn
2017-04-22 00:37:41 +00:00
committed by android-build-merger
5 changed files with 327 additions and 0 deletions

View File

@@ -595,6 +595,18 @@
</intent-filter>
</activity>
<service android:name=".app.JobWorkService"
android:permission="android.permission.BIND_JOB_SERVICE"/>
<activity android:name=".app.JobWorkServiceActivity"
android:label="@string/activity_job_work_service"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.SAMPLE_CODE" />
</intent-filter>
</activity>
<service android:name=".app.ForegroundService" />
<service android:name=".app.ForegroundService2" />

View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- Demonstrates enqueueing work into a job.
See corresponding Java code com.android.sdk.app.JobWorkServiceActivity.java. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:padding="4dip"
android:gravity="center_horizontal"
android:layout_width="match_parent" android:layout_height="match_parent">
<TextView
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_weight="0" android:paddingBottom="4dip"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/job_work_service_controller"/>
<Button android:id="@+id/enqueue1"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="@string/enqueue1_job">
<requestFocus />
</Button>
<Button android:id="@+id/enqueue2"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="@string/enqueue2_job">
</Button>
<Button android:id="@+id/enqueue3"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="@string/enqueue3_job">
</Button>
<Button android:id="@+id/kill"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="@string/kill_process">
</Button>
</LinearLayout>

View File

@@ -302,6 +302,19 @@
<string name="service_created">Service created.</string>
<string name="service_destroyed">Service destroyed.</string>
<string name="job_work_service_label">Job Work Service</string>
<string name="activity_job_work_service">App/Job/Job Work Service Controller</string>
<string name="job_work_service_controller">This demonstrates how
work can be enqueued and executed by a job, running work in the job until
everything is complete.
</string>
<string name="enqueue1_job">Enqueue \"One\"</string>
<string name="enqueue2_job">Enqueue \"Two\"</string>
<string name="enqueue3_job">Enqueue \"Three\"</string>
<string name="job_service_created">JobService created.</string>
<string name="job_service_destroyed">JobService destroyed.</string>
<string name="foreground_service_started">Service is in the foreground</string>
<string name="foreground_service_label">Sample Foreground Service</string>

View File

@@ -0,0 +1,161 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.apis.app;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.app.job.JobParameters;
import android.app.job.JobService;
import android.app.job.JobWorkItem;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
import com.example.android.apis.R;
/**
* This is an example of implementing a {@link JobService} that dispatches work enqueued in
* to it. The {@link JobWorkServiceActivity} class shows how to interact with the service.
*/
//BEGIN_INCLUDE(service)
public class JobWorkService extends JobService {
private NotificationManager mNM;
private CommandProcessor mCurProcessor;
/**
* This is a task to dequeue and process work in the background.
*/
final class CommandProcessor extends AsyncTask<Void, Void, Void> {
private final JobParameters mParams;
CommandProcessor(JobParameters params) {
mParams = params;
}
@Override
protected Void doInBackground(Void... params) {
boolean cancelled;
JobWorkItem work;
/**
* Iterate over available work. Once dequeueWork() returns null, the
* job's work queue is empty and the job has stopped, so we can let this
* async task complete.
*/
while (!(cancelled=isCancelled()) && (work=mParams.dequeueWork()) != null) {
String txt = work.getIntent().getStringExtra("name");
Log.i("JobWorkService", "Processing work: " + work + ", msg: " + txt);
showNotification(txt);
// Process work here... we'll pretend by sleeping.
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
hideNotification();
// Tell system we have finished processing the work.
Log.i("JobWorkService", "Done with: " + work);
mParams.completeWork(work);
}
if (cancelled) {
Log.i("JobWorkService", "CANCELLED!");
}
return null;
}
}
@Override
public void onCreate() {
mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
Toast.makeText(this, R.string.service_created, Toast.LENGTH_SHORT).show();
}
@Override
public void onDestroy() {
hideNotification();
Toast.makeText(this, R.string.service_destroyed, Toast.LENGTH_SHORT).show();
}
@Override
public boolean onStartJob(JobParameters params) {
// Start task to pull work out of the queue and process it.
mCurProcessor = new CommandProcessor(params);
mCurProcessor.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
// Allow the job to continue running while we process work.
return true;
}
@Override
public boolean onStopJob(JobParameters params) {
// Have the processor cancel its current work.
mCurProcessor.cancel(true);
// Tell the system to reschedule the job -- the only reason we would be here is
// because the job needs to stop for some reason before it has completed all of
// its work, so we would like it to remain to finish that work in the future.
return true;
}
/**
* Show a notification while this service is running.
*/
private void showNotification(String text) {
// The PendingIntent to launch our activity if the user selects this notification
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, JobWorkServiceActivity.class), 0);
// Set the info for the views that show in the notification panel.
Notification.Builder noteBuilder = new Notification.Builder(this)
.setSmallIcon(R.drawable.stat_sample) // the status icon
.setTicker(text) // the status text
.setWhen(System.currentTimeMillis()) // the time stamp
.setContentTitle(getText(R.string.service_start_arguments_label)) // the label
.setContentText(text) // the contents of the entry
.setContentIntent(contentIntent); // The intent to send when the entry is clicked
// We show this for as long as our service is processing a command.
noteBuilder.setOngoing(true);
// Send the notification.
// We use a string id because it is a unique number. We use it later to cancel.
mNM.notify(R.string.job_service_created, noteBuilder.build());
}
private void hideNotification() {
mNM.cancel(R.string.service_created);
}
}
//END_INCLUDE(service)

View File

@@ -0,0 +1,88 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.apis.app;
import android.app.Activity;
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.app.job.JobWorkItem;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
import android.os.Process;
import android.view.View;
import android.widget.Button;
import com.example.android.apis.R;
/**
* Example of interacting with {@link JobWorkService}.
*/
public class JobWorkServiceActivity extends Activity {
JobScheduler mJobScheduler;
JobInfo mJobInfo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mJobScheduler = (JobScheduler)getSystemService(JOB_SCHEDULER_SERVICE);
mJobInfo = new JobInfo.Builder(R.string.job_service_created,
new ComponentName(this, JobWorkService.class)).setOverrideDeadline(0).build();
setContentView(R.layout.job_work_service_activity);
// Watch for button clicks.
Button button = findViewById(R.id.enqueue1);
button.setOnClickListener(mEnqueue1Listener);
button = findViewById(R.id.enqueue2);
button.setOnClickListener(mEnqueue2Listener);
button = findViewById(R.id.enqueue3);
button.setOnClickListener(mEnqueue3Listener);
button = findViewById(R.id.kill);
button.setOnClickListener(mKillListener);
}
private View.OnClickListener mEnqueue1Listener = new View.OnClickListener() {
public void onClick(View v) {
mJobScheduler.enqueue(mJobInfo, new JobWorkItem(
new Intent("com.example.android.apis.ONE").putExtra("name", "One")));
}
};
private View.OnClickListener mEnqueue2Listener = new View.OnClickListener() {
public void onClick(View v) {
mJobScheduler.enqueue(mJobInfo, new JobWorkItem(
new Intent("com.example.android.apis.TWO").putExtra("name", "Two")));
}
};
private View.OnClickListener mEnqueue3Listener = new View.OnClickListener() {
public void onClick(View v) {
mJobScheduler.enqueue(mJobInfo, new JobWorkItem(
new Intent("com.example.android.apis.THREE").putExtra("name", "Three")));
}
};
private View.OnClickListener mKillListener = new View.OnClickListener() {
public void onClick(View v) {
// This is to simulate the service being killed while it is
// running in the background.
Process.killProcess(Process.myPid());
}
};
}