Merge "Add API demo for monitoring media content."

This commit is contained in:
Dianne Hackborn
2016-01-25 20:34:46 +00:00
committed by Android (Google) Code Review
5 changed files with 273 additions and 0 deletions

View File

@@ -1253,6 +1253,17 @@
</intent-filter>
</activity>
<activity android:name=".content.MediaContentObserver"
android:label="@string/activity_media_content_observer">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.SAMPLE_CODE"/>
</intent-filter>
</activity>
<service android:name=".content.MediaContentJob"
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

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button android:id="@+id/schedule_job"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="Schedule job">
</Button>
<Button android:id="@+id/cancel_job"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="Cancel job">
</Button>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Directly observed content changes:" />
<ScrollView android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:id="@+id/changes_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ff303030"
android:padding="4dp"
android:textAppearance="?android:attr/textAppearanceMedium"
/>
</ScrollView>
</LinearLayout>

View File

@@ -469,6 +469,8 @@
<string name="activity_changed_contact">Content/Provider/Changed Contacts</string>
<string name="activity_media_content_observer">Content/Provider/Media Content Observer</string>
<string name="activity_install_apk">Content/Packages/Install Apk</string>
<string name="ir_send">Send IR</string>

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