From 40fc690cd431c81c998db66ec4d69e63ab7513ec Mon Sep 17 00:00:00 2001 From: Makoto Onuki Date: Wed, 27 Apr 2016 12:00:37 -0700 Subject: [PATCH] ShortcutManager sample update: - Don't use content: URI icons. - Add a service to allow publishing a shortcut in background. Bug 27923857 Change-Id: Ib17afdd76a6e122d14a22d331b0a47916c7d584d --- samples/ShortcutDemo/publisher/Android.mk | 2 - .../{manifest1 => }/AndroidManifest.xml | 7 +- .../publisher/manifest2/AndroidManifest.xml | 37 ------- .../android/pm/shortcutdemo/IconProvider.java | 102 ------------------ .../pm/shortcutdemo/ShortcutPublisher.java | 73 +++++-------- .../ShortcutPublishingService.java | 57 ++++++++++ 6 files changed, 91 insertions(+), 187 deletions(-) rename samples/ShortcutDemo/publisher/{manifest1 => }/AndroidManifest.xml (87%) delete mode 100644 samples/ShortcutDemo/publisher/manifest2/AndroidManifest.xml delete mode 100644 samples/ShortcutDemo/publisher/src/com/example/android/pm/shortcutdemo/IconProvider.java create mode 100644 samples/ShortcutDemo/publisher/src/com/example/android/pm/shortcutdemo/ShortcutPublishingService.java diff --git a/samples/ShortcutDemo/publisher/Android.mk b/samples/ShortcutDemo/publisher/Android.mk index 177c04c98..75f3bb6a2 100644 --- a/samples/ShortcutDemo/publisher/Android.mk +++ b/samples/ShortcutDemo/publisher/Android.mk @@ -25,7 +25,6 @@ LOCAL_PACKAGE_NAME := ShortcutDemo LOCAL_MODULE_TAGS := samples tests -LOCAL_MANIFEST_FILE := manifest1/AndroidManifest.xml LOCAL_AAPT_FLAGS += --rename-manifest-package com.example.android.pm.shortcutdemo LOCAL_SRC_FILES := $(call all-java-files-under, src) @@ -46,7 +45,6 @@ LOCAL_PACKAGE_NAME := ShortcutDemo2 LOCAL_MODULE_TAGS := samples tests -LOCAL_MANIFEST_FILE := manifest2/AndroidManifest.xml LOCAL_AAPT_FLAGS += --rename-manifest-package com.example.android.pm.shortcutdemo2 LOCAL_SRC_FILES := $(call all-java-files-under, src) diff --git a/samples/ShortcutDemo/publisher/manifest1/AndroidManifest.xml b/samples/ShortcutDemo/publisher/AndroidManifest.xml similarity index 87% rename from samples/ShortcutDemo/publisher/manifest1/AndroidManifest.xml rename to samples/ShortcutDemo/publisher/AndroidManifest.xml index 83171eab3..baa9ea720 100644 --- a/samples/ShortcutDemo/publisher/manifest1/AndroidManifest.xml +++ b/samples/ShortcutDemo/publisher/AndroidManifest.xml @@ -31,7 +31,10 @@ - + + + + + diff --git a/samples/ShortcutDemo/publisher/manifest2/AndroidManifest.xml b/samples/ShortcutDemo/publisher/manifest2/AndroidManifest.xml deleted file mode 100644 index 724e27f21..000000000 --- a/samples/ShortcutDemo/publisher/manifest2/AndroidManifest.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/samples/ShortcutDemo/publisher/src/com/example/android/pm/shortcutdemo/IconProvider.java b/samples/ShortcutDemo/publisher/src/com/example/android/pm/shortcutdemo/IconProvider.java deleted file mode 100644 index e2c525440..000000000 --- a/samples/ShortcutDemo/publisher/src/com/example/android/pm/shortcutdemo/IconProvider.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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.pm.shortcutdemo; - -import android.content.ContentProvider; -import android.content.ContentProvider.PipeDataWriter; -import android.content.ContentValues; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.os.ParcelFileDescriptor; -import android.util.Log; - -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; - -public class IconProvider extends ContentProvider implements PipeDataWriter { - @Override - public boolean onCreate() { - return true; - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, - String[] selectionArgs, String sortOrder) { - return null; - } - - @Override - public String getType(Uri uri) { - return null; - } - - @Override - public Uri insert(Uri uri, ContentValues values) { - return null; - } - - @Override - public int delete(Uri uri, String selection, - String[] selectionArgs) { - return 0; - } - - @Override - public int update(Uri uri, ContentValues values, String selection, - String[] selectionArgs) { - return 0; - } - - @Override - public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { - if (!"r".equals(mode)) { - throw new IllegalArgumentException("Only read is supported"); - } - final int resId = Integer.parseInt(uri.getPath().substring(1) /* to remove the slash */); - - // Try to open an asset with the given name. - try { - return new ParcelFileDescriptor(openPipeHelper(uri, null, null, - getContext().getResources().openRawResource(resId), this)); - } catch (IOException e) { - FileNotFoundException fnf = new FileNotFoundException("Unable to open " + uri); - throw fnf; - } - } - - @Override - public void writeDataToPipe(ParcelFileDescriptor output, Uri uri, String mimeType, - Bundle opts, InputStream args) { - // Transfer data from the asset to the pipe the client is reading. - byte[] buffer = new byte[8192]; - int n; - try (FileOutputStream fout = new FileOutputStream(output.getFileDescriptor())) { - while ((n=args.read(buffer)) >= 0) { - fout.write(buffer, 0, n); - } - } catch (IOException e) { - Log.i("IconProvider", "Failed transferring", e); - } finally { - try { - args.close(); - } catch (IOException e) { - } - } - } -} diff --git a/samples/ShortcutDemo/publisher/src/com/example/android/pm/shortcutdemo/ShortcutPublisher.java b/samples/ShortcutDemo/publisher/src/com/example/android/pm/shortcutdemo/ShortcutPublisher.java index 68f7cce54..040488177 100644 --- a/samples/ShortcutDemo/publisher/src/com/example/android/pm/shortcutdemo/ShortcutPublisher.java +++ b/samples/ShortcutDemo/publisher/src/com/example/android/pm/shortcutdemo/ShortcutPublisher.java @@ -51,7 +51,7 @@ public class ShortcutPublisher extends Activity { private ListView mList; private MyAdapter mAdapter; - private final Random mRandom = new Random(); + private static final Random sRandom = new Random(); @Override public void onCreate(Bundle savedInstanceState) { @@ -124,27 +124,27 @@ public class ShortcutPublisher extends Activity { } } - private void showToast(String message) { - Toast.makeText(this, message, Toast.LENGTH_SHORT).show(); + private static void showToast(Context context, String message) { + Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); } - private void showThrottledToast() { - showToast("Throttled, use \"adb shell cmd shortcut reset-throttling\" to reset counters"); + private static void showThrottledToast(Context context) { + showToast(context, + "Throttled, use \"adb shell cmd shortcut reset-throttling\" to reset counters"); } - private void callApi(BooleanSupplier call) { + public static void callApi(Context context, BooleanSupplier call) { try { if (!call.getAsBoolean()) { - showThrottledToast(); + showThrottledToast(context); } - refreshList(); } catch (RuntimeException r) { Log.w(TAG, r.getMessage(), r); - showToast(r.getMessage()); + showToast(context, r.getMessage()); } } - private List> mIntentList = Arrays.asList( + private static List> sIntentList = Arrays.asList( Pair.create("Google Search", "http://www.google.com"), Pair.create("Google Mail", "http://mail.google.com"), Pair.create("Google Maps", "http://maps.google.com"), @@ -154,11 +154,11 @@ public class ShortcutPublisher extends Activity { Pair.create("Google+", "http://plus.google.com") ); - public ShortcutInfo.Builder addRandomIntents(ShortcutInfo.Builder b) { - final int i = mRandom.nextInt(mIntentList.size()); - b.setTitle(mIntentList.get(i).first); - b.setIntent(new Intent(Intent.ACTION_VIEW, Uri.parse(mIntentList.get(i).second))); - b.setIcon(Icon.createWithResource(this, R.drawable.icon2)); + public static ShortcutInfo.Builder addRandomIntents(Context context, ShortcutInfo.Builder b) { + final int i = sRandom.nextInt(sIntentList.size()); + b.setTitle(sIntentList.get(i).first); + b.setIntent(new Intent(Intent.ACTION_VIEW, Uri.parse(sIntentList.get(i).second))); + b.setIcon(Icon.createWithResource(context, R.drawable.icon2)); return b; } @@ -166,8 +166,7 @@ public class ShortcutPublisher extends Activity { dumpCurrentShortcuts(); final Icon icon2 = Icon.createWithBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.icon_large_2)); - final Icon icon3 = Icon.createWithContentUri( - Uri.parse("content://" + getPackageName() + "/" + R.drawable.icon_large_3)); + final Icon icon3 = Icon.createWithResource(this, R.drawable.icon_large_3); final Intent intent2 = new Intent(Intent.ACTION_VIEW); intent2.setClass(this, ShortcutPublisher.class); @@ -178,7 +177,7 @@ public class ShortcutPublisher extends Activity { intent3.putExtra("nest", new Bundle()); intent3.getBundleExtra("nest").putInt("int", 123); - final ShortcutInfo si1 = addRandomIntents(new ShortcutInfo.Builder(this) + final ShortcutInfo si1 = addRandomIntents(this, new ShortcutInfo.Builder(this) .setId("shortcut1") .setWeight(10)).build(); @@ -198,22 +197,16 @@ public class ShortcutPublisher extends Activity { .setIntent(intent3) .build(); - callApi(new BooleanSupplier() { - @Override - public boolean getAsBoolean() { - return mShortcutManager.setDynamicShortcuts(Arrays.asList(si1, si2, si3)); - } - }); + callApi(this, () -> mShortcutManager.setDynamicShortcuts(Arrays.asList(si1, si2, si3))); + refreshList(); } public void onDeleteAllPressed(View view) { - callApi(new BooleanSupplier() { - @Override - public boolean getAsBoolean() { - mShortcutManager.removeAllDynamicShortcuts(); - return true; - } + callApi(this, () -> { + mShortcutManager.removeAllDynamicShortcuts(); + return true; }); + refreshList(); } static String formatTime(long time) { @@ -223,15 +216,11 @@ public class ShortcutPublisher extends Activity { } public void onAddPressed(View view) { - final ShortcutInfo si = addRandomIntents(new ShortcutInfo.Builder(this) + final ShortcutInfo si = addRandomIntents(this, new ShortcutInfo.Builder(this) .setId("shortcut-" + formatTime(System.currentTimeMillis())) .setWeight(10)).build(); - callApi(new BooleanSupplier() { - @Override - public boolean getAsBoolean() { - return mShortcutManager.addDynamicShortcuts(Arrays.asList(si)); - } - }); + callApi(this, () -> mShortcutManager.addDynamicShortcuts(Arrays.asList(si))); + refreshList(); } public void onUpdatePressed(View view) { @@ -239,16 +228,12 @@ public class ShortcutPublisher extends Activity { for (ShortcutInfo si : getAllShortcuts()) { if (SETUP_SHORTCUT_ID.equals(si.getId())) continue; - updateList.add(addRandomIntents(new ShortcutInfo.Builder(this) + updateList.add(addRandomIntents(this, new ShortcutInfo.Builder(this) .setId(si.getId())) .build()); } - callApi(new BooleanSupplier() { - @Override - public boolean getAsBoolean() { - return mShortcutManager.updateShortcuts(updateList); - } - }); + callApi(this, () -> mShortcutManager.updateShortcuts(updateList)); + refreshList(); } void launch(ShortcutInfo si) { diff --git a/samples/ShortcutDemo/publisher/src/com/example/android/pm/shortcutdemo/ShortcutPublishingService.java b/samples/ShortcutDemo/publisher/src/com/example/android/pm/shortcutdemo/ShortcutPublishingService.java new file mode 100644 index 000000000..18e6b8de2 --- /dev/null +++ b/samples/ShortcutDemo/publisher/src/com/example/android/pm/shortcutdemo/ShortcutPublishingService.java @@ -0,0 +1,57 @@ +/* + * 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.pm.shortcutdemo; + +import android.app.IntentService; +import android.content.Intent; +import android.content.pm.ShortcutInfo; +import android.content.pm.ShortcutManager; + +import java.util.Arrays; + +/** + * This allows to create a shortcut in background. + * + * Usage: + adb shell am startservice -a com.example.android.pm.shortcutdemo.ADD \ + com.example.android.pm.shortcutdemo/com.example.android.pm.shortcutdemo.ShortcutPublishingService + * Or for package 2, + adb shell am startservice -a com.example.android.pm.shortcutdemo.ADD \ + com.example.android.pm.shortcutdemo2/com.example.android.pm.shortcutdemo.ShortcutPublishingService + + */ +public class ShortcutPublishingService extends IntentService { + public ShortcutPublishingService() { + super("ShortcutPublishingService"); + } + + @Override + protected void onHandleIntent(Intent intent) { + if (intent.getAction().endsWith(".ADD")) { + addShortcut(); + return; + } + } + + private void addShortcut() { + final ShortcutInfo si1 = ShortcutPublisher.addRandomIntents( + this, new ShortcutInfo.Builder(this) + .setId("shortcut-" + System.currentTimeMillis()) + .setWeight(10)).build(); + ShortcutPublisher.callApi(this, () -> + getSystemService(ShortcutManager.class).addDynamicShortcuts(Arrays.asList(si1))); + } +}