| OLD | NEW |
| (Empty) |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 package org.chromium.chrome.browser.webapps; | |
| 6 | |
| 7 import android.annotation.SuppressLint; | |
| 8 import android.annotation.TargetApi; | |
| 9 import android.content.Context; | |
| 10 import android.content.Intent; | |
| 11 import android.content.IntentSender; | |
| 12 import android.content.pm.PackageManager; | |
| 13 import android.content.pm.ResolveInfo; | |
| 14 import android.graphics.Bitmap; | |
| 15 import android.graphics.drawable.Icon; | |
| 16 | |
| 17 import org.chromium.base.BuildInfo; | |
| 18 import org.chromium.base.ContextUtils; | |
| 19 import org.chromium.base.Log; | |
| 20 import org.chromium.chrome.browser.ShortcutHelper; | |
| 21 | |
| 22 import java.lang.reflect.Constructor; | |
| 23 import java.lang.reflect.InvocationTargetException; | |
| 24 import java.lang.reflect.Method; | |
| 25 import java.util.List; | |
| 26 | |
| 27 /** | |
| 28 * This class handles the adding of shortcuts to the Android Home Screen. | |
| 29 */ | |
| 30 public class ChromeShortcutManager { | |
| 31 private static final String TAG = "ChromeShortcutMgr"; | |
| 32 | |
| 33 // There is no public string defining this intent so if Home changes the val
ue, we | |
| 34 // have to update this string. | |
| 35 private static final String INSTALL_SHORTCUT = "com.android.launcher.action.
INSTALL_SHORTCUT"; | |
| 36 | |
| 37 private static ChromeShortcutManager sInstance; | |
| 38 | |
| 39 // True when Android O's ShortcutManager.requestPinShortcut() is supported. | |
| 40 private boolean mIsRequestPinShortcutSupported; | |
| 41 | |
| 42 // TODO(martiw): Use 'ShortcutInfo' instead of 'Object' below when compileSd
k is bumped to O. | |
| 43 private Object mShortcutManager; | |
| 44 | |
| 45 /** | |
| 46 * Returns the singleton instance of ChromeShortcutManager, creating it if n
eeded. | |
| 47 */ | |
| 48 // TODO(martiw): change this to private when ChromeShortcutManagerInternal i
s gone. | |
| 49 public static ChromeShortcutManager getInstance() { | |
| 50 if (sInstance == null) { | |
| 51 sInstance = new ChromeShortcutManager(); | |
| 52 } | |
| 53 return sInstance; | |
| 54 } | |
| 55 | |
| 56 /** | |
| 57 * Creates an intent that will add a shortcut to the home screen. | |
| 58 * @param title Title of the shortcut. | |
| 59 * @param icon Image that represents the shortcut. | |
| 60 * @param shortcutIntent Intent to fire when the shortcut is activated. | |
| 61 * @return Intent for the shortcut. | |
| 62 */ | |
| 63 public static Intent createAddToHomeIntent(String title, Bitmap icon, Intent
shortcutIntent) { | |
| 64 Intent i = new Intent(INSTALL_SHORTCUT); | |
| 65 i.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); | |
| 66 i.putExtra(Intent.EXTRA_SHORTCUT_NAME, title); | |
| 67 i.putExtra(Intent.EXTRA_SHORTCUT_ICON, icon); | |
| 68 return i; | |
| 69 } | |
| 70 | |
| 71 // TODO(martiw): Make this private when ChromeShortcutManagerInternal is rem
oved. | |
| 72 public ChromeShortcutManager() { | |
| 73 if (BuildInfo.isAtLeastO()) { | |
| 74 checkIfRequestPinShortcutSupported(); | |
| 75 } | |
| 76 } | |
| 77 | |
| 78 // TODO(martiw): Use Build.VERSION_CODES.O instead of hardcoded number when
it is available. | |
| 79 @TargetApi(26) | |
| 80 private void checkIfRequestPinShortcutSupported() { | |
| 81 // The code in the try-block uses reflection in order to compile as it c
alls APIs newer than | |
| 82 // our target version of Android. The equivalent code without reflection
is as follows: | |
| 83 // mShortcutManager = | |
| 84 // ContextUtils.getApplicationContext().getSystemService(Shortc
utManager.class); | |
| 85 // mIsRequestPinShortcutSupported = mShortcutManager.isRequestPinShortc
utSupported(); | |
| 86 // TODO(martiw): Remove the following reflection once compileSdk is bump
ed to O. | |
| 87 try { | |
| 88 Class<?> ShortcutManagerClass = Class.forName("android.content.pm.Sh
ortcutManager"); | |
| 89 mShortcutManager = | |
| 90 ContextUtils.getApplicationContext().getSystemService(Shortc
utManagerClass); | |
| 91 | |
| 92 Method isRequestPinShortcutSupported = | |
| 93 ShortcutManagerClass.getMethod("isRequestPinShortcutSupporte
d"); | |
| 94 mIsRequestPinShortcutSupported = | |
| 95 (boolean) isRequestPinShortcutSupported.invoke(mShortcutMana
ger); | |
| 96 } catch (ClassNotFoundException | NoSuchMethodException | InvocationTarg
etException | |
| 97 | IllegalAccessException e) { | |
| 98 Log.e(TAG, "Error checking if RequestPinShortcut is supported:", e); | |
| 99 } | |
| 100 } | |
| 101 | |
| 102 /** | |
| 103 * Add a shortcut to the home screen. | |
| 104 * @param title Title of the shortcut. | |
| 105 * @param icon Image that represents the shortcut. | |
| 106 * @param shortcutIntent Intent to fire when the shortcut is activated. | |
| 107 */ | |
| 108 public void addShortcutToHomeScreen(String title, Bitmap icon, Intent shortc
utIntent) { | |
| 109 if (mIsRequestPinShortcutSupported) { | |
| 110 addShortcutWithShortcutManager(title, icon, shortcutIntent); | |
| 111 return; | |
| 112 } | |
| 113 Intent intent = createAddToHomeIntent(title, icon, shortcutIntent); | |
| 114 ContextUtils.getApplicationContext().sendBroadcast(intent); | |
| 115 } | |
| 116 | |
| 117 // TODO(martiw): Use Build.VERSION_CODES.O instead of hardcoded number when
it is available. | |
| 118 @TargetApi(26) | |
| 119 private void addShortcutWithShortcutManager(String title, Bitmap icon, Inten
t shortcutIntent) { | |
| 120 String id = shortcutIntent.getStringExtra(ShortcutHelper.EXTRA_ID); | |
| 121 Context context = ContextUtils.getApplicationContext(); | |
| 122 | |
| 123 // The code in the try-block uses reflection in order to compile as it c
alls APIs newer than | |
| 124 // our compileSdkVersion of Android. The equivalent code without reflect
ion looks like this: | |
| 125 // ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(context, id) | |
| 126 // .setShortLabel(title) | |
| 127 // .setLongLabel(title) | |
| 128 // .setIcon(Icon.createWithBitmap(icon)
) | |
| 129 // .setIntent(shortcutIntent) | |
| 130 // .build(); | |
| 131 // mShortcutManager.requestPinShortcut(shortcutInfo, null); | |
| 132 // TODO(martiw): Remove the following reflection once compileSdk is bump
ed to O. | |
| 133 try { | |
| 134 Class<?> builderClass = Class.forName("android.content.pm.ShortcutIn
fo$Builder"); | |
| 135 Constructor<?> builderConstructor = | |
| 136 builderClass.getDeclaredConstructor(Context.class, String.cl
ass); | |
| 137 Object shortcutBuilder = builderConstructor.newInstance(context, id)
; | |
| 138 | |
| 139 Method setShortLabel = builderClass.getMethod("setShortLabel", CharS
equence.class); | |
| 140 setShortLabel.invoke(shortcutBuilder, title); | |
| 141 | |
| 142 Method setLongLabel = builderClass.getMethod("setLongLabel", CharSeq
uence.class); | |
| 143 setLongLabel.invoke(shortcutBuilder, title); | |
| 144 | |
| 145 Method setIcon = builderClass.getMethod("setIcon", Icon.class); | |
| 146 setIcon.invoke(shortcutBuilder, Icon.createWithBitmap(icon)); | |
| 147 | |
| 148 Method setIntent = builderClass.getMethod("setIntent", Intent.class)
; | |
| 149 setIntent.invoke(shortcutBuilder, shortcutIntent); | |
| 150 | |
| 151 Method build = builderClass.getMethod("build"); | |
| 152 Object shortcutInfo = build.invoke(shortcutBuilder); | |
| 153 | |
| 154 Class<?> ShortcutInfoClass = Class.forName("android.content.pm.Short
cutInfo"); | |
| 155 Method requestPinShortcut = mShortcutManager.getClass().getMethod( | |
| 156 "requestPinShortcut", ShortcutInfoClass, IntentSender.class)
; | |
| 157 requestPinShortcut.invoke(mShortcutManager, shortcutInfo, null); | |
| 158 } catch (ClassNotFoundException | NoSuchMethodException | InstantiationE
xception | |
| 159 | InvocationTargetException | IllegalAccessException e) { | |
| 160 Log.e(TAG, "Error adding shortcut with ShortcutManager:", e); | |
| 161 } | |
| 162 } | |
| 163 | |
| 164 // TODO(crbug.com/635567): Fix this properly. | |
| 165 @SuppressLint("WrongConstant") | |
| 166 public boolean canAddShortcutToHomescreen() { | |
| 167 if (mIsRequestPinShortcutSupported) return true; | |
| 168 PackageManager pm = ContextUtils.getApplicationContext().getPackageManag
er(); | |
| 169 Intent i = new Intent(INSTALL_SHORTCUT); | |
| 170 List<ResolveInfo> receivers = | |
| 171 pm.queryBroadcastReceivers(i, PackageManager.GET_INTENT_FILTERS)
; | |
| 172 return !receivers.isEmpty(); | |
| 173 } | |
| 174 | |
| 175 public boolean shouldShowToastWhenAddingShortcut() { | |
| 176 return !mIsRequestPinShortcutSupported; | |
| 177 } | |
| 178 } | |
| OLD | NEW |