1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.example.android.apis.app;
18 
19 import android.app.Activity;
20 import android.app.Notification;
21 import android.app.NotificationManager;
22 import android.app.PendingIntent;
23 import android.app.Service;
24 import android.app.job.JobParameters;
25 import android.app.job.JobService;
26 import android.app.job.JobWorkItem;
27 import android.content.Intent;
28 import android.os.AsyncTask;
29 import android.os.Bundle;
30 import android.os.Handler;
31 import android.os.HandlerThread;
32 import android.os.IBinder;
33 import android.os.Looper;
34 import android.os.Message;
35 import android.os.Process;
36 import android.util.Log;
37 import android.view.View;
38 import android.view.View.OnClickListener;
39 import android.widget.Button;
40 import android.widget.Toast;
41 
42 import com.example.android.apis.R;
43 
44 /**
45  * This is an example of implementing a {@link JobService} that dispatches work enqueued in
46  * to it.  The {@link JobWorkServiceActivity} class shows how to interact with the service.
47  */
48 //BEGIN_INCLUDE(service)
49 public class JobWorkService extends JobService {
50     private NotificationManager mNM;
51     private CommandProcessor mCurProcessor;
52 
53     /**
54      * This is a task to dequeue and process work in the background.
55      */
56     final class CommandProcessor extends AsyncTask<Void, Void, Void> {
57         private final JobParameters mParams;
58 
CommandProcessor(JobParameters params)59         CommandProcessor(JobParameters params) {
60             mParams = params;
61         }
62 
63         @Override
doInBackground(Void... params)64         protected Void doInBackground(Void... params) {
65             boolean cancelled;
66             JobWorkItem work;
67 
68             /**
69              * Iterate over available work.  Once dequeueWork() returns null, the
70              * job's work queue is empty and the job has stopped, so we can let this
71              * async task complete.
72              */
73             while (!(cancelled=isCancelled()) && (work=mParams.dequeueWork()) != null) {
74                 String txt = work.getIntent().getStringExtra("name");
75                 Log.i("JobWorkService", "Processing work: " + work + ", msg: " + txt);
76                 showNotification(txt);
77 
78                 // Process work here...  we'll pretend by sleeping.
79                 try {
80                     Thread.sleep(5000);
81                 } catch (InterruptedException e) {
82                 }
83 
84                 hideNotification();
85 
86                 // Tell system we have finished processing the work.
87                 Log.i("JobWorkService", "Done with: " + work);
88                 mParams.completeWork(work);
89             }
90 
91             if (cancelled) {
92                 Log.i("JobWorkService", "CANCELLED!");
93             }
94 
95             return null;
96         }
97     }
98 
99     @Override
onCreate()100     public void onCreate() {
101         mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
102         Toast.makeText(this, R.string.service_created, Toast.LENGTH_SHORT).show();
103     }
104 
105     @Override
onDestroy()106     public void onDestroy() {
107         hideNotification();
108         Toast.makeText(this, R.string.service_destroyed, Toast.LENGTH_SHORT).show();
109     }
110 
111     @Override
onStartJob(JobParameters params)112     public boolean onStartJob(JobParameters params) {
113         // Start task to pull work out of the queue and process it.
114         mCurProcessor = new CommandProcessor(params);
115         mCurProcessor.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
116 
117         // Allow the job to continue running while we process work.
118         return true;
119     }
120 
121     @Override
onStopJob(JobParameters params)122     public boolean onStopJob(JobParameters params) {
123         // Have the processor cancel its current work.
124         mCurProcessor.cancel(true);
125 
126         // Tell the system to reschedule the job -- the only reason we would be here is
127         // because the job needs to stop for some reason before it has completed all of
128         // its work, so we would like it to remain to finish that work in the future.
129         return true;
130     }
131 
132     /**
133      * Show a notification while this service is running.
134      */
showNotification(String text)135     private void showNotification(String text) {
136         // The PendingIntent to launch our activity if the user selects this notification
137         PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
138                 new Intent(this, JobWorkServiceActivity.class), 0);
139 
140         // Set the info for the views that show in the notification panel.
141         Notification.Builder noteBuilder = new Notification.Builder(this)
142                 .setSmallIcon(R.drawable.stat_sample)  // the status icon
143                 .setTicker(text)  // the status text
144                 .setWhen(System.currentTimeMillis())  // the time stamp
145                 .setContentTitle(getText(R.string.service_start_arguments_label))  // the label
146                 .setContentText(text)  // the contents of the entry
147                 .setContentIntent(contentIntent);  // The intent to send when the entry is clicked
148 
149         // We show this for as long as our service is processing a command.
150         noteBuilder.setOngoing(true);
151 
152         // Send the notification.
153         // We use a string id because it is a unique number.  We use it later to cancel.
154         mNM.notify(R.string.job_service_created, noteBuilder.build());
155     }
156 
hideNotification()157     private void hideNotification() {
158         mNM.cancel(R.string.service_created);
159     }
160 }
161 //END_INCLUDE(service)
162