Add sample for observing only photos changes.
Change-Id: I954fb466fb21d73f88b1dd1bc86eac617a628073
This commit is contained in:
@@ -1275,6 +1275,9 @@
|
|||||||
<service android:name=".content.MediaContentJob"
|
<service android:name=".content.MediaContentJob"
|
||||||
android:permission="android.permission.BIND_JOB_SERVICE" />
|
android:permission="android.permission.BIND_JOB_SERVICE" />
|
||||||
|
|
||||||
|
<service android:name=".content.PhotosContentJob"
|
||||||
|
android:permission="android.permission.BIND_JOB_SERVICE" />
|
||||||
|
|
||||||
<activity android:name=".content.InstallApk" android:label="@string/activity_install_apk"
|
<activity android:name=".content.InstallApk" android:label="@string/activity_install_apk"
|
||||||
android:enabled="@bool/atLeastHoneycombMR2">
|
android:enabled="@bool/atLeastHoneycombMR2">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
|
|||||||
@@ -21,13 +21,25 @@
|
|||||||
<LinearLayout android:layout_width="match_parent"
|
<LinearLayout android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
<Button android:id="@+id/schedule_job"
|
<Button android:id="@+id/schedule_media_job"
|
||||||
android:layout_width="wrap_content" android:layout_height="wrap_content"
|
android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||||
android:text="Schedule job">
|
android:text="Schedule media job">
|
||||||
</Button>
|
</Button>
|
||||||
<Button android:id="@+id/cancel_job"
|
<Button android:id="@+id/cancel_media_job"
|
||||||
android:layout_width="wrap_content" android:layout_height="wrap_content"
|
android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||||
android:text="Cancel job">
|
android:text="Cancel media job">
|
||||||
|
</Button>
|
||||||
|
</LinearLayout>
|
||||||
|
<LinearLayout android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
<Button android:id="@+id/schedule_photos_job"
|
||||||
|
android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||||
|
android:text="Schedule photos job">
|
||||||
|
</Button>
|
||||||
|
<Button android:id="@+id/cancel_photos_job"
|
||||||
|
android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||||
|
android:text="Cancel photos job">
|
||||||
</Button>
|
</Button>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import android.content.Context;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.provider.MediaStore;
|
import android.provider.MediaStore;
|
||||||
|
import android.util.Log;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.example.android.apis.R;
|
import com.example.android.apis.R;
|
||||||
@@ -49,11 +50,12 @@ public class MediaContentJob extends JobService {
|
|||||||
|
|
||||||
public static void scheduleJob(Context context) {
|
public static void scheduleJob(Context context) {
|
||||||
JobScheduler js = context.getSystemService(JobScheduler.class);
|
JobScheduler js = context.getSystemService(JobScheduler.class);
|
||||||
JobInfo.Builder builder = new JobInfo.Builder(R.id.schedule_job,
|
JobInfo.Builder builder = new JobInfo.Builder(R.id.schedule_media_job,
|
||||||
new ComponentName(context, MediaContentJob.class));
|
new ComponentName(context, MediaContentJob.class));
|
||||||
builder.addTriggerContentUri(new JobInfo.TriggerContentUri(MEDIA_URI,
|
builder.addTriggerContentUri(new JobInfo.TriggerContentUri(MEDIA_URI,
|
||||||
JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS));
|
JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS));
|
||||||
js.schedule(builder.build());
|
js.schedule(builder.build());
|
||||||
|
Log.i("MediaContentJob", "JOB SCHEDULED!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isScheduled(Context context) {
|
public static boolean isScheduled(Context context) {
|
||||||
@@ -63,7 +65,7 @@ public class MediaContentJob extends JobService {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (int i=0; i<jobs.size(); i++) {
|
for (int i=0; i<jobs.size(); i++) {
|
||||||
if (jobs.get(i).getId() == R.id.schedule_job) {
|
if (jobs.get(i).getId() == R.id.schedule_media_job) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -72,11 +74,12 @@ public class MediaContentJob extends JobService {
|
|||||||
|
|
||||||
public static void cancelJob(Context context) {
|
public static void cancelJob(Context context) {
|
||||||
JobScheduler js = context.getSystemService(JobScheduler.class);
|
JobScheduler js = context.getSystemService(JobScheduler.class);
|
||||||
js.cancel(R.id.schedule_job);
|
js.cancel(R.id.schedule_media_job);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onStartJob(JobParameters params) {
|
public boolean onStartJob(JobParameters params) {
|
||||||
|
Log.i("MediaContentJob", "JOB STARTED!");
|
||||||
mRunningParams = params;
|
mRunningParams = params;
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append("Media content has changed:\n");
|
sb.append("Media content has changed:\n");
|
||||||
@@ -102,7 +105,7 @@ public class MediaContentJob extends JobService {
|
|||||||
}
|
}
|
||||||
Toast.makeText(this, sb.toString(), Toast.LENGTH_LONG).show();
|
Toast.makeText(this, sb.toString(), Toast.LENGTH_LONG).show();
|
||||||
// We will emulate taking some time to do this work, so we can see batching happen.
|
// We will emulate taking some time to do this work, so we can see batching happen.
|
||||||
mHandler.postDelayed(mWorker, 20*1000);
|
mHandler.postDelayed(mWorker, 10*1000);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,8 +29,10 @@ import com.example.android.apis.R;
|
|||||||
|
|
||||||
public class MediaContentObserver extends Activity {
|
public class MediaContentObserver extends Activity {
|
||||||
ContentObserver mContentObserver;
|
ContentObserver mContentObserver;
|
||||||
View mScheduleJob;
|
View mScheduleMediaJob;
|
||||||
View mCancelJob;
|
View mCancelMediaJob;
|
||||||
|
View mSchedulePhotosJob;
|
||||||
|
View mCancelPhotosJob;
|
||||||
TextView mDataText;
|
TextView mDataText;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -49,24 +51,40 @@ public class MediaContentObserver extends Activity {
|
|||||||
// See res/any/layout/resources.xml for this view layout definition.
|
// See res/any/layout/resources.xml for this view layout definition.
|
||||||
setContentView(R.layout.media_content_observer);
|
setContentView(R.layout.media_content_observer);
|
||||||
|
|
||||||
mScheduleJob = findViewById(R.id.schedule_job);
|
mScheduleMediaJob = findViewById(R.id.schedule_media_job);
|
||||||
mCancelJob = findViewById(R.id.cancel_job);
|
mCancelMediaJob = findViewById(R.id.cancel_media_job);
|
||||||
|
mSchedulePhotosJob = findViewById(R.id.schedule_photos_job);
|
||||||
|
mCancelPhotosJob = findViewById(R.id.cancel_photos_job);
|
||||||
mDataText = (TextView)findViewById(R.id.changes_text);
|
mDataText = (TextView)findViewById(R.id.changes_text);
|
||||||
|
|
||||||
mScheduleJob.setOnClickListener(new View.OnClickListener() {
|
mScheduleMediaJob.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
MediaContentJob.scheduleJob(MediaContentObserver.this);
|
MediaContentJob.scheduleJob(MediaContentObserver.this);
|
||||||
updateButtons();
|
updateButtons();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mCancelJob.setOnClickListener(new View.OnClickListener() {
|
mCancelMediaJob.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
MediaContentJob.cancelJob(MediaContentObserver.this);
|
MediaContentJob.cancelJob(MediaContentObserver.this);
|
||||||
updateButtons();
|
updateButtons();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
mSchedulePhotosJob.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
PhotosContentJob.scheduleJob(MediaContentObserver.this);
|
||||||
|
updateButtons();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mCancelPhotosJob.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
PhotosContentJob.cancelJob(MediaContentObserver.this);
|
||||||
|
updateButtons();
|
||||||
|
}
|
||||||
|
});
|
||||||
updateButtons();
|
updateButtons();
|
||||||
|
|
||||||
getContentResolver().registerContentObserver(MediaContentJob.MEDIA_URI, true,
|
getContentResolver().registerContentObserver(MediaContentJob.MEDIA_URI, true,
|
||||||
@@ -75,11 +93,18 @@ public class MediaContentObserver extends Activity {
|
|||||||
|
|
||||||
void updateButtons() {
|
void updateButtons() {
|
||||||
if (MediaContentJob.isScheduled(this)) {
|
if (MediaContentJob.isScheduled(this)) {
|
||||||
mScheduleJob.setEnabled(false);
|
mScheduleMediaJob.setEnabled(false);
|
||||||
mCancelJob.setEnabled(true);
|
mCancelMediaJob.setEnabled(true);
|
||||||
} else {
|
} else {
|
||||||
mScheduleJob.setEnabled(true);
|
mScheduleMediaJob.setEnabled(true);
|
||||||
mCancelJob.setEnabled(false);
|
mCancelMediaJob.setEnabled(false);
|
||||||
|
}
|
||||||
|
if (PhotosContentJob.isScheduled(this)) {
|
||||||
|
mSchedulePhotosJob.setEnabled(false);
|
||||||
|
mCancelPhotosJob.setEnabled(true);
|
||||||
|
} else {
|
||||||
|
mSchedulePhotosJob.setEnabled(true);
|
||||||
|
mCancelPhotosJob.setEnabled(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,116 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2016, 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.content;
|
||||||
|
|
||||||
|
import android.app.job.JobInfo;
|
||||||
|
import android.app.job.JobParameters;
|
||||||
|
import android.app.job.JobScheduler;
|
||||||
|
import android.app.job.JobService;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.provider.MediaStore;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.example.android.apis.R;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stub job to execute when there is a change to photos in the media provider.
|
||||||
|
*/
|
||||||
|
public class PhotosContentJob extends JobService {
|
||||||
|
final Handler mHandler = new Handler();
|
||||||
|
final Runnable mWorker = new Runnable() {
|
||||||
|
@Override public void run() {
|
||||||
|
scheduleJob(PhotosContentJob.this);
|
||||||
|
jobFinished(mRunningParams, false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
JobParameters mRunningParams;
|
||||||
|
|
||||||
|
public static void scheduleJob(Context context) {
|
||||||
|
JobScheduler js = context.getSystemService(JobScheduler.class);
|
||||||
|
JobInfo.Builder builder = new JobInfo.Builder(R.id.schedule_photos_job,
|
||||||
|
new ComponentName(context, PhotosContentJob.class));
|
||||||
|
builder.addTriggerContentUri(new JobInfo.TriggerContentUri(
|
||||||
|
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
|
||||||
|
JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS));
|
||||||
|
js.schedule(builder.build());
|
||||||
|
Log.i("PhotosContentJob", "JOB SCHEDULED!");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isScheduled(Context context) {
|
||||||
|
JobScheduler js = context.getSystemService(JobScheduler.class);
|
||||||
|
List<JobInfo> jobs = js.getAllPendingJobs();
|
||||||
|
if (jobs == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i=0; i<jobs.size(); i++) {
|
||||||
|
if (jobs.get(i).getId() == R.id.schedule_photos_job) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void cancelJob(Context context) {
|
||||||
|
JobScheduler js = context.getSystemService(JobScheduler.class);
|
||||||
|
js.cancel(R.id.schedule_photos_job);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onStartJob(JobParameters params) {
|
||||||
|
Log.i("PhotosContentJob", "JOB STARTED!");
|
||||||
|
mRunningParams = params;
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("Photos content has changed:\n");
|
||||||
|
if (params.getTriggeredContentAuthorities() != null) {
|
||||||
|
sb.append("Authorities: ");
|
||||||
|
boolean first = true;
|
||||||
|
for (String auth : params.getTriggeredContentAuthorities()) {
|
||||||
|
if (first) {
|
||||||
|
first = false;
|
||||||
|
} else {
|
||||||
|
sb.append(", ");
|
||||||
|
}
|
||||||
|
sb.append(auth);
|
||||||
|
}
|
||||||
|
if (params.getTriggeredContentUris() != null) {
|
||||||
|
for (Uri uri : params.getTriggeredContentUris()) {
|
||||||
|
sb.append("\n");
|
||||||
|
sb.append(uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sb.append("(No content)");
|
||||||
|
}
|
||||||
|
Toast.makeText(this, sb.toString(), Toast.LENGTH_LONG).show();
|
||||||
|
// We will emulate taking some time to do this work, so we can see batching happen.
|
||||||
|
mHandler.postDelayed(mWorker, 10*1000);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onStopJob(JobParameters params) {
|
||||||
|
mHandler.removeCallbacks(mWorker);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user