Add API demo for monitoring media content.

Both the classic ContentObserver API, and the new
JobScheduler API.

Change-Id: I2011389abb2f863e810ccc9012fb3c53c93c76fd
This commit is contained in:
Dianne Hackborn
2016-01-07 18:03:54 -08:00
parent e89bdbceb2
commit e3ad7fa9ac
5 changed files with 273 additions and 0 deletions

View File

@@ -0,0 +1,114 @@
/**
* 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.widget.Toast;
import com.example.android.apis.R;
import java.util.List;
/**
* Stub job to execute when there is a change to any media: content URI.
*/
public class MediaContentJob extends JobService {
static final Uri MEDIA_URI = Uri.parse("content://" + MediaStore.AUTHORITY + "/");
final Handler mHandler = new Handler();
final Runnable mWorker = new Runnable() {
@Override public void run() {
scheduleJob(MediaContentJob.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_job,
new ComponentName(context, MediaContentJob.class));
builder.addTriggerContentUri(new JobInfo.TriggerContentUri(MEDIA_URI,
JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS));
js.schedule(builder.build());
}
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_job) {
return true;
}
}
return false;
}
public static void cancelJob(Context context) {
JobScheduler js = context.getSystemService(JobScheduler.class);
js.cancel(R.id.schedule_job);
}
@Override
public boolean onStartJob(JobParameters params) {
mRunningParams = params;
StringBuilder sb = new StringBuilder();
sb.append("Media 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, 20*1000);
return true;
}
@Override
public boolean onStopJob(JobParameters params) {
mHandler.removeCallbacks(mWorker);
return false;
}
}

View File

@@ -0,0 +1,92 @@
/**
* 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.Activity;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import com.example.android.apis.R;
public class MediaContentObserver extends Activity {
ContentObserver mContentObserver;
View mScheduleJob;
View mCancelJob;
TextView mDataText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContentObserver = new ContentObserver(new Handler()) {
public void onChange(boolean selfChange, Uri uri) {
mDataText.append(uri.toString());
mDataText.append("\n");
}
};
Log.d("foo", "Observing: " + MediaContentJob.MEDIA_URI);
// 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);
mDataText = (TextView)findViewById(R.id.changes_text);
mScheduleJob.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MediaContentJob.scheduleJob(MediaContentObserver.this);
updateButtons();
}
});
mCancelJob.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MediaContentJob.cancelJob(MediaContentObserver.this);
updateButtons();
}
});
updateButtons();
getContentResolver().registerContentObserver(MediaContentJob.MEDIA_URI, true,
mContentObserver);
}
void updateButtons() {
if (MediaContentJob.isScheduled(this)) {
mScheduleJob.setEnabled(false);
mCancelJob.setEnabled(true);
} else {
mScheduleJob.setEnabled(true);
mCancelJob.setEnabled(false);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
getContentResolver().unregisterContentObserver(mContentObserver);
}
}