1 /** 2 * Copyright (c) 2016, 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.content; 18 19 import android.app.job.JobInfo; 20 import android.app.job.JobParameters; 21 import android.app.job.JobScheduler; 22 import android.app.job.JobService; 23 import android.content.ComponentName; 24 import android.content.Context; 25 import android.net.Uri; 26 import android.os.Handler; 27 import android.provider.MediaStore; 28 import android.util.Log; 29 import android.widget.Toast; 30 31 import com.example.android.apis.R; 32 33 import java.util.List; 34 35 /** 36 * Example stub job to monitor when there is a change to any media: content URI. 37 */ 38 public class MediaContentJob extends JobService { 39 static final Uri MEDIA_URI = Uri.parse("content://" + MediaStore.AUTHORITY + "/"); 40 41 final Handler mHandler = new Handler(); 42 final Runnable mWorker = new Runnable() { 43 @Override public void run() { 44 scheduleJob(MediaContentJob.this); 45 jobFinished(mRunningParams, false); 46 } 47 }; 48 49 JobParameters mRunningParams; 50 51 public static void scheduleJob(Context context) { 52 JobScheduler js = context.getSystemService(JobScheduler.class); 53 JobInfo.Builder builder = new JobInfo.Builder(JobIds.MEDIA_CONTENT_JOB, 54 new ComponentName(context, MediaContentJob.class)); 55 builder.addTriggerContentUri(new JobInfo.TriggerContentUri(MEDIA_URI, 56 JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS)); 57 js.schedule(builder.build()); 58 Log.i("MediaContentJob", "JOB SCHEDULED!"); 59 } 60 61 public static boolean isScheduled(Context context) { 62 JobScheduler js = context.getSystemService(JobScheduler.class); 63 List<JobInfo> jobs = js.getAllPendingJobs(); 64 if (jobs == null) { 65 return false; 66 } 67 for (int i=0; i<jobs.size(); i++) { 68 if (jobs.get(i).getId() == JobIds.MEDIA_CONTENT_JOB) { 69 return true; 70 } 71 } 72 return false; 73 } 74 75 public static void cancelJob(Context context) { 76 JobScheduler js = context.getSystemService(JobScheduler.class); 77 js.cancel(JobIds.MEDIA_CONTENT_JOB); 78 } 79 80 @Override 81 public boolean onStartJob(JobParameters params) { 82 Log.i("MediaContentJob", "JOB STARTED!"); 83 mRunningParams = params; 84 StringBuilder sb = new StringBuilder(); 85 sb.append("Media content has changed:\n"); 86 if (params.getTriggeredContentAuthorities() != null) { 87 sb.append("Authorities: "); 88 boolean first = true; 89 for (String auth : params.getTriggeredContentAuthorities()) { 90 if (first) { 91 first = false; 92 } else { 93 sb.append(", "); 94 } 95 sb.append(auth); 96 } 97 if (params.getTriggeredContentUris() != null) { 98 for (Uri uri : params.getTriggeredContentUris()) { 99 sb.append("\n"); 100 sb.append(uri); 101 } 102 } 103 } else { 104 sb.append("(No content)"); 105 } 106 Toast.makeText(this, sb.toString(), Toast.LENGTH_LONG).show(); 107 // We will emulate taking some time to do this work, so we can see batching happen. 108 mHandler.postDelayed(mWorker, 10*1000); 109 return true; 110 } 111 112 @Override 113 public boolean onStopJob(JobParameters params) { 114 mHandler.removeCallbacks(mWorker); 115 return false; 116 } 117 } 118