Add sample for observing only photos changes.

Change-Id: I954fb466fb21d73f88b1dd1bc86eac617a628073
This commit is contained in:
Dianne Hackborn
2016-03-21 13:31:34 -07:00
parent d1731fc950
commit a4a1bb7dca
5 changed files with 177 additions and 18 deletions

View File

@@ -1275,6 +1275,9 @@
<service android:name=".content.MediaContentJob"
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"
android:enabled="@bool/atLeastHoneycombMR2">
<intent-filter>

View File

@@ -21,13 +21,25 @@
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
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:text="Schedule job">
android:text="Schedule media job">
</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: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>
</LinearLayout>

View File

@@ -25,6 +25,7 @@ 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;
@@ -49,11 +50,12 @@ public class MediaContentJob extends JobService {
public static void scheduleJob(Context context) {
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));
builder.addTriggerContentUri(new JobInfo.TriggerContentUri(MEDIA_URI,
JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS));
js.schedule(builder.build());
Log.i("MediaContentJob", "JOB SCHEDULED!");
}
public static boolean isScheduled(Context context) {
@@ -63,7 +65,7 @@ public class MediaContentJob extends JobService {
return false;
}
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;
}
}
@@ -72,11 +74,12 @@ public class MediaContentJob extends JobService {
public static void cancelJob(Context context) {
JobScheduler js = context.getSystemService(JobScheduler.class);
js.cancel(R.id.schedule_job);
js.cancel(R.id.schedule_media_job);
}
@Override
public boolean onStartJob(JobParameters params) {
Log.i("MediaContentJob", "JOB STARTED!");
mRunningParams = params;
StringBuilder sb = new StringBuilder();
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();
// 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;
}

View File

@@ -29,8 +29,10 @@ import com.example.android.apis.R;
public class MediaContentObserver extends Activity {
ContentObserver mContentObserver;
View mScheduleJob;
View mCancelJob;
View mScheduleMediaJob;
View mCancelMediaJob;
View mSchedulePhotosJob;
View mCancelPhotosJob;
TextView mDataText;
@Override
@@ -49,24 +51,40 @@ public class MediaContentObserver extends Activity {
// See res/any/layout/resources.xml for this view layout definition.
setContentView(R.layout.media_content_observer);
mScheduleJob = findViewById(R.id.schedule_job);
mCancelJob = findViewById(R.id.cancel_job);
mScheduleMediaJob = findViewById(R.id.schedule_media_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);
mScheduleJob.setOnClickListener(new View.OnClickListener() {
mScheduleMediaJob.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MediaContentJob.scheduleJob(MediaContentObserver.this);
updateButtons();
}
});
mCancelJob.setOnClickListener(new View.OnClickListener() {
mCancelMediaJob.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MediaContentJob.cancelJob(MediaContentObserver.this);
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();
getContentResolver().registerContentObserver(MediaContentJob.MEDIA_URI, true,
@@ -75,11 +93,18 @@ public class MediaContentObserver extends Activity {
void updateButtons() {
if (MediaContentJob.isScheduled(this)) {
mScheduleJob.setEnabled(false);
mCancelJob.setEnabled(true);
mScheduleMediaJob.setEnabled(false);
mCancelMediaJob.setEnabled(true);
} else {
mScheduleJob.setEnabled(true);
mCancelJob.setEnabled(false);
mScheduleMediaJob.setEnabled(true);
mCancelMediaJob.setEnabled(false);
}
if (PhotosContentJob.isScheduled(this)) {
mSchedulePhotosJob.setEnabled(false);
mCancelPhotosJob.setEnabled(true);
} else {
mSchedulePhotosJob.setEnabled(true);
mCancelPhotosJob.setEnabled(false);
}
}

View File

@@ -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;
}
}