summaryrefslogtreecommitdiffstats
path: root/src/com/android/launcher3/InstallShortcutReceiver.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/launcher3/InstallShortcutReceiver.java')
-rw-r--r--src/com/android/launcher3/InstallShortcutReceiver.java377
1 files changed, 212 insertions, 165 deletions
diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java
index e9fb499ad..9103fad77 100644
--- a/src/com/android/launcher3/InstallShortcutReceiver.java
+++ b/src/com/android/launcher3/InstallShortcutReceiver.java
@@ -27,14 +27,18 @@ import android.graphics.BitmapFactory;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
-import android.widget.Toast;
+import com.android.launcher3.compat.LauncherActivityInfoCompat;
+import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.compat.UserManagerCompat;
+import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONStringer;
import org.json.JSONTokener;
+import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
@@ -47,73 +51,49 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
private static final String ACTION_INSTALL_SHORTCUT =
"com.android.launcher.action.INSTALL_SHORTCUT";
- private static final String DATA_INTENT_KEY = "intent.data";
private static final String LAUNCH_INTENT_KEY = "intent.launch";
private static final String NAME_KEY = "name";
private static final String ICON_KEY = "icon";
private static final String ICON_RESOURCE_NAME_KEY = "iconResource";
private static final String ICON_RESOURCE_PACKAGE_NAME_KEY = "iconResourcePackage";
+
+ private static final String APP_SHORTCUT_TYPE_KEY = "isAppShortcut";
+ private static final String USER_HANDLE_KEY = "userHandle";
+
// The set of shortcuts that are pending install
private static final String APPS_PENDING_INSTALL = "apps_to_install";
public static final int NEW_SHORTCUT_BOUNCE_DURATION = 450;
public static final int NEW_SHORTCUT_STAGGER_DELAY = 85;
- private static final int INSTALL_SHORTCUT_SUCCESSFUL = 0;
- private static final int INSTALL_SHORTCUT_IS_DUPLICATE = -1;
-
- private static Object sLock = new Object();
-
- private static void addToStringSet(SharedPreferences sharedPrefs,
- SharedPreferences.Editor editor, String key, String value) {
- Set<String> strings = sharedPrefs.getStringSet(key, null);
- if (strings == null) {
- strings = new HashSet<String>(1);
- } else {
- strings = new HashSet<String>(strings);
- }
- strings.add(value);
- editor.putStringSet(key, strings);
- }
+ private static final Object sLock = new Object();
private static void addToInstallQueue(
SharedPreferences sharedPrefs, PendingInstallShortcutInfo info) {
synchronized(sLock) {
- try {
- JSONStringer json = new JSONStringer()
- .object()
- .key(DATA_INTENT_KEY).value(info.data.toUri(0))
- .key(LAUNCH_INTENT_KEY).value(info.launchIntent.toUri(0))
- .key(NAME_KEY).value(info.name);
- if (info.icon != null) {
- byte[] iconByteArray = ItemInfo.flattenBitmap(info.icon);
- json = json.key(ICON_KEY).value(
- Base64.encodeToString(
- iconByteArray, 0, iconByteArray.length, Base64.DEFAULT));
+ String encoded = info.encodeToString();
+ if (encoded != null) {
+ Set<String> strings = sharedPrefs.getStringSet(APPS_PENDING_INSTALL, null);
+ if (strings == null) {
+ strings = new HashSet<String>(1);
+ } else {
+ strings = new HashSet<String>(strings);
}
- if (info.iconResource != null) {
- json = json.key(ICON_RESOURCE_NAME_KEY).value(info.iconResource.resourceName);
- json = json.key(ICON_RESOURCE_PACKAGE_NAME_KEY)
- .value(info.iconResource.packageName);
- }
- json = json.endObject();
- SharedPreferences.Editor editor = sharedPrefs.edit();
- if (DBG) Log.d(TAG, "Adding to APPS_PENDING_INSTALL: " + json);
- addToStringSet(sharedPrefs, editor, APPS_PENDING_INSTALL, json.toString());
- editor.commit();
- } catch (org.json.JSONException e) {
- Log.d(TAG, "Exception when adding shortcut: " + e);
+ strings.add(encoded);
+ sharedPrefs.edit().putStringSet(APPS_PENDING_INSTALL, strings).commit();
}
}
}
- public static void removeFromInstallQueue(SharedPreferences sharedPrefs,
- ArrayList<String> packageNames) {
+ public static void removeFromInstallQueue(Context context, ArrayList<String> packageNames,
+ UserHandleCompat user) {
if (packageNames.isEmpty()) {
return;
}
+ String spKey = LauncherAppState.getSharedPreferencesKey();
+ SharedPreferences sp = context.getSharedPreferences(spKey, Context.MODE_PRIVATE);
synchronized(sLock) {
- Set<String> strings = sharedPrefs.getStringSet(APPS_PENDING_INSTALL, null);
+ Set<String> strings = sp.getStringSet(APPS_PENDING_INSTALL, null);
if (DBG) {
Log.d(TAG, "APPS_PENDING_INSTALL: " + strings
+ ", removing packages: " + packageNames);
@@ -122,34 +102,20 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
Set<String> newStrings = new HashSet<String>(strings);
Iterator<String> newStringsIter = newStrings.iterator();
while (newStringsIter.hasNext()) {
- String json = newStringsIter.next();
- try {
- JSONObject object = (JSONObject) new JSONTokener(json).nextValue();
- Intent launchIntent = Intent.parseUri(object.getString(LAUNCH_INTENT_KEY), 0);
- String pn = launchIntent.getPackage();
- if (pn == null) {
- if (launchIntent.getComponent() == null) {
- continue;
- }
- pn = launchIntent.getComponent().getPackageName();
- }
- if (packageNames.contains(pn)) {
- newStringsIter.remove();
- }
- } catch (org.json.JSONException e) {
- Log.d(TAG, "Exception reading shortcut to remove: " + e);
- } catch (java.net.URISyntaxException e) {
- Log.d(TAG, "Exception reading shortcut to remove: " + e);
+ String encoded = newStringsIter.next();
+ PendingInstallShortcutInfo info = decode(encoded, context);
+ if (info == null || (packageNames.contains(info.getTargetPackage())
+ && user.equals(info.user))) {
+ newStringsIter.remove();
}
}
- sharedPrefs.edit().putStringSet(APPS_PENDING_INSTALL,
- new HashSet<String>(newStrings)).commit();
+ sp.edit().putStringSet(APPS_PENDING_INSTALL, newStrings).commit();
}
}
}
private static ArrayList<PendingInstallShortcutInfo> getAndClearInstallQueue(
- SharedPreferences sharedPrefs) {
+ SharedPreferences sharedPrefs, Context context) {
synchronized(sLock) {
Set<String> strings = sharedPrefs.getStringSet(APPS_PENDING_INSTALL, null);
if (DBG) Log.d(TAG, "Getting and clearing APPS_PENDING_INSTALL: " + strings);
@@ -158,36 +124,10 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
}
ArrayList<PendingInstallShortcutInfo> infos =
new ArrayList<PendingInstallShortcutInfo>();
- for (String json : strings) {
- try {
- JSONObject object = (JSONObject) new JSONTokener(json).nextValue();
- Intent data = Intent.parseUri(object.getString(DATA_INTENT_KEY), 0);
- Intent launchIntent =
- Intent.parseUri(object.getString(LAUNCH_INTENT_KEY), 0);
- String name = object.getString(NAME_KEY);
- String iconBase64 = object.optString(ICON_KEY);
- String iconResourceName = object.optString(ICON_RESOURCE_NAME_KEY);
- String iconResourcePackageName =
- object.optString(ICON_RESOURCE_PACKAGE_NAME_KEY);
- if (iconBase64 != null && !iconBase64.isEmpty()) {
- byte[] iconArray = Base64.decode(iconBase64, Base64.DEFAULT);
- Bitmap b = BitmapFactory.decodeByteArray(iconArray, 0, iconArray.length);
- data.putExtra(Intent.EXTRA_SHORTCUT_ICON, b);
- } else if (iconResourceName != null && !iconResourceName.isEmpty()) {
- Intent.ShortcutIconResource iconResource =
- new Intent.ShortcutIconResource();
- iconResource.resourceName = iconResourceName;
- iconResource.packageName = iconResourcePackageName;
- data.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, iconResource);
- }
- data.putExtra(Intent.EXTRA_SHORTCUT_INTENT, launchIntent);
- PendingInstallShortcutInfo info =
- new PendingInstallShortcutInfo(data, name, launchIntent);
+ for (String encoded : strings) {
+ PendingInstallShortcutInfo info = decode(encoded, context);
+ if (info != null) {
infos.add(info);
- } catch (org.json.JSONException e) {
- Log.d(TAG, "Exception reading shortcut to add: " + e);
- } catch (java.net.URISyntaxException e) {
- Log.d(TAG, "Exception reading shortcut to add: " + e);
}
}
sharedPrefs.edit().putStringSet(APPS_PENDING_INSTALL, new HashSet<String>()).commit();
@@ -199,49 +139,26 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
// processAllPendingInstalls() is called.
private static boolean mUseInstallQueue = false;
- private static class PendingInstallShortcutInfo {
- Intent data;
- Intent launchIntent;
- String name;
- Bitmap icon;
- Intent.ShortcutIconResource iconResource;
-
- public PendingInstallShortcutInfo(Intent rawData, String shortcutName,
- Intent shortcutIntent) {
- data = rawData;
- name = shortcutName;
- launchIntent = shortcutIntent;
- }
- }
-
public void onReceive(Context context, Intent data) {
if (!ACTION_INSTALL_SHORTCUT.equals(data.getAction())) {
return;
}
if (DBG) Log.d(TAG, "Got INSTALL_SHORTCUT: " + data.toUri(0));
+ PendingInstallShortcutInfo info = new PendingInstallShortcutInfo(data, context);
- Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
- if (intent == null) {
- return;
- }
+ queuePendingShortcutInfo(info, context);
+ }
- // This name is only used for comparisons and notifications, so fall back to activity name
- // if not supplied
- String name = ensureValidName(context, intent,
- data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME)).toString();
- Bitmap icon = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);
- Intent.ShortcutIconResource iconResource =
- data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);
+ static void queueInstallShortcut(LauncherActivityInfoCompat info, Context context) {
+ queuePendingShortcutInfo(new PendingInstallShortcutInfo(info, context), context);
+ }
+ private static void queuePendingShortcutInfo(PendingInstallShortcutInfo info, Context context) {
// Queue the item up for adding if launcher has not loaded properly yet
LauncherAppState.setApplicationContext(context.getApplicationContext());
LauncherAppState app = LauncherAppState.getInstance();
- boolean launcherNotLoaded = (app.getDynamicGrid() == null);
-
- PendingInstallShortcutInfo info = new PendingInstallShortcutInfo(data, name, intent);
- info.icon = icon;
- info.iconResource = iconResource;
+ boolean launcherNotLoaded = app.getModel().getCallback() == null;
String spKey = LauncherAppState.getSharedPreferencesKey();
SharedPreferences sp = context.getSharedPreferences(spKey, Context.MODE_PRIVATE);
@@ -261,33 +178,22 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
static void flushInstallQueue(Context context) {
String spKey = LauncherAppState.getSharedPreferencesKey();
SharedPreferences sp = context.getSharedPreferences(spKey, Context.MODE_PRIVATE);
- ArrayList<PendingInstallShortcutInfo> installQueue = getAndClearInstallQueue(sp);
+ ArrayList<PendingInstallShortcutInfo> installQueue = getAndClearInstallQueue(sp, context);
if (!installQueue.isEmpty()) {
Iterator<PendingInstallShortcutInfo> iter = installQueue.iterator();
ArrayList<ItemInfo> addShortcuts = new ArrayList<ItemInfo>();
- int result = INSTALL_SHORTCUT_SUCCESSFUL;
- String duplicateName = "";
while (iter.hasNext()) {
final PendingInstallShortcutInfo pendingInfo = iter.next();
- //final Intent data = pendingInfo.data;
final Intent intent = pendingInfo.launchIntent;
- final String name = pendingInfo.name;
if (LauncherAppState.isDisableAllApps() && !isValidShortcutLaunchIntent(intent)) {
if (DBG) Log.d(TAG, "Ignoring shortcut with launchIntent:" + intent);
continue;
}
- final boolean exists = LauncherModel.shortcutExists(context, name, intent);
- //final boolean allowDuplicate = data.getBooleanExtra(Launcher.EXTRA_SHORTCUT_DUPLICATE, true);
-
// If the intent specifies a package, make sure the package exists
- String packageName = intent.getPackage();
- if (packageName == null) {
- packageName = intent.getComponent() == null ? null :
- intent.getComponent().getPackageName();
- }
- if (packageName != null && !packageName.isEmpty()) {
+ String packageName = pendingInfo.getTargetPackage();
+ if (TextUtils.isEmpty(packageName)) {
UserHandleCompat myUserHandle = UserHandleCompat.myUserHandle();
if (!LauncherModel.isValidPackage(context, packageName, myUserHandle)) {
if (DBG) Log.d(TAG, "Ignoring shortcut for absent package:" + intent);
@@ -295,19 +201,12 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
}
}
+ final boolean exists = LauncherModel.shortcutExists(context, pendingInfo.label,
+ intent, pendingInfo.user);
if (!exists) {
// Generate a shortcut info to add into the model
- ShortcutInfo info = getShortcutInfo(context, pendingInfo.data,
- pendingInfo.launchIntent);
- addShortcuts.add(info);
+ addShortcuts.add(pendingInfo.getShortcutInfo());
}
-
- }
-
- // Notify the user once if we weren't able to place any duplicates
- if (result == INSTALL_SHORTCUT_IS_DUPLICATE) {
- Toast.makeText(context, context.getString(R.string.shortcut_duplicate,
- duplicateName), Toast.LENGTH_SHORT).show();
}
// Add the new apps to the model and bind them
@@ -342,22 +241,6 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
return true;
}
- private static ShortcutInfo getShortcutInfo(Context context, Intent data,
- Intent launchIntent) {
- if (launchIntent.getAction() == null) {
- launchIntent.setAction(Intent.ACTION_VIEW);
- } else if (launchIntent.getAction().equals(Intent.ACTION_MAIN) &&
- launchIntent.getCategories() != null &&
- launchIntent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {
- launchIntent.addFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- }
- LauncherAppState app = LauncherAppState.getInstance();
- ShortcutInfo info = app.getModel().infoFromShortcutIntent(context, data);
- info.title = ensureValidName(context, launchIntent, info.title);
- return info;
- }
-
/**
* Ensures that we have a valid, non-null name. If the provided name is null, we will return
* the application name instead.
@@ -374,4 +257,168 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
}
return name;
}
+
+ private static class PendingInstallShortcutInfo {
+
+ final LauncherActivityInfoCompat activityInfo;
+
+ final Intent data;
+ final Context mContext;
+ final Intent launchIntent;
+ final String label;
+ final UserHandleCompat user;
+
+ /**
+ * Initializes a PendingInstallShortcutInfo received from a different app.
+ */
+ public PendingInstallShortcutInfo(Intent data, Context context) {
+ this.data = data;
+ mContext = context;
+
+ launchIntent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
+ label = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
+ user = UserHandleCompat.myUserHandle();
+ activityInfo = null;
+ }
+
+ /**
+ * Initializes a PendingInstallShortcutInfo to represent a launcher target.
+ */
+ public PendingInstallShortcutInfo(LauncherActivityInfoCompat info, Context context) {
+ this.data = null;
+ mContext = context;
+ activityInfo = info;
+ user = info.getUser();
+
+ launchIntent = AppInfo.makeLaunchIntent(context, info, user);
+ label = info.getLabel().toString();
+ }
+
+ public String encodeToString() {
+ if (activityInfo != null) {
+ try {
+ // If it a launcher target, we only need component name, and user to
+ // recreate this.
+ return new JSONStringer()
+ .object()
+ .key(LAUNCH_INTENT_KEY).value(launchIntent.toUri(0))
+ .key(APP_SHORTCUT_TYPE_KEY).value(true)
+ .key(USER_HANDLE_KEY).value(UserManagerCompat.getInstance(mContext)
+ .getSerialNumberForUser(user))
+ .endObject().toString();
+ } catch (JSONException e) {
+ Log.d(TAG, "Exception when adding shortcut: " + e);
+ return null;
+ }
+ }
+
+ if (launchIntent.getAction() == null) {
+ launchIntent.setAction(Intent.ACTION_VIEW);
+ } else if (launchIntent.getAction().equals(Intent.ACTION_MAIN) &&
+ launchIntent.getCategories() != null &&
+ launchIntent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {
+ launchIntent.addFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ }
+
+ // This name is only used for comparisons and notifications, so fall back to activity
+ // name if not supplied
+ String name = ensureValidName(mContext, launchIntent, label).toString();
+ Bitmap icon = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);
+ Intent.ShortcutIconResource iconResource =
+ data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);
+
+ // Only encode the parameters which are supported by the API.
+ try {
+ JSONStringer json = new JSONStringer()
+ .object()
+ .key(LAUNCH_INTENT_KEY).value(launchIntent.toUri(0))
+ .key(NAME_KEY).value(name);
+ if (icon != null) {
+ byte[] iconByteArray = ItemInfo.flattenBitmap(icon);
+ json = json.key(ICON_KEY).value(
+ Base64.encodeToString(
+ iconByteArray, 0, iconByteArray.length, Base64.DEFAULT));
+ }
+ if (iconResource != null) {
+ json = json.key(ICON_RESOURCE_NAME_KEY).value(iconResource.resourceName);
+ json = json.key(ICON_RESOURCE_PACKAGE_NAME_KEY)
+ .value(iconResource.packageName);
+ }
+ return json.endObject().toString();
+ } catch (JSONException e) {
+ Log.d(TAG, "Exception when adding shortcut: " + e);
+ }
+ return null;
+ }
+
+ public ShortcutInfo getShortcutInfo() {
+ if (activityInfo != null) {
+ final ShortcutInfo info = new ShortcutInfo();
+ info.user = user;
+ info.title = label;
+ info.contentDescription = label;
+ info.customIcon = false;
+ info.intent = launchIntent;
+ info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
+ info.flags = AppInfo.initFlags(activityInfo);
+ info.firstInstallTime = activityInfo.getFirstInstallTime();
+ return info;
+ } else {
+ return LauncherAppState.getInstance().getModel().infoFromShortcutIntent(mContext, data);
+ }
+ }
+
+ public String getTargetPackage() {
+ String packageName = launchIntent.getPackage();
+ if (packageName == null) {
+ packageName = launchIntent.getComponent() == null ? null :
+ launchIntent.getComponent().getPackageName();
+ }
+ return packageName;
+ }
+ }
+
+ private static PendingInstallShortcutInfo decode(String encoded, Context context) {
+ try {
+ JSONObject object = (JSONObject) new JSONTokener(encoded).nextValue();
+ Intent launcherIntent = Intent.parseUri(object.getString(LAUNCH_INTENT_KEY), 0);
+
+ if (object.optBoolean(APP_SHORTCUT_TYPE_KEY)) {
+ // The is an internal launcher target shortcut.
+ UserHandleCompat user = UserManagerCompat.getInstance(context)
+ .getUserForSerialNumber(object.getLong(USER_HANDLE_KEY));
+
+ LauncherActivityInfoCompat info = LauncherAppsCompat.getInstance(context)
+ .resolveActivity(launcherIntent, user);
+ return info == null ? null : new PendingInstallShortcutInfo(info, context);
+ }
+
+ Intent data = new Intent();
+ data.putExtra(Intent.EXTRA_SHORTCUT_INTENT, launcherIntent);
+ data.putExtra(Intent.EXTRA_SHORTCUT_NAME, object.getString(NAME_KEY));
+
+ String iconBase64 = object.optString(ICON_KEY);
+ String iconResourceName = object.optString(ICON_RESOURCE_NAME_KEY);
+ String iconResourcePackageName = object.optString(ICON_RESOURCE_PACKAGE_NAME_KEY);
+ if (iconBase64 != null && !iconBase64.isEmpty()) {
+ byte[] iconArray = Base64.decode(iconBase64, Base64.DEFAULT);
+ Bitmap b = BitmapFactory.decodeByteArray(iconArray, 0, iconArray.length);
+ data.putExtra(Intent.EXTRA_SHORTCUT_ICON, b);
+ } else if (iconResourceName != null && !iconResourceName.isEmpty()) {
+ Intent.ShortcutIconResource iconResource =
+ new Intent.ShortcutIconResource();
+ iconResource.resourceName = iconResourceName;
+ iconResource.packageName = iconResourcePackageName;
+ data.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, iconResource);
+ }
+
+ return new PendingInstallShortcutInfo(data, context);
+ } catch (JSONException e) {
+ Log.d(TAG, "Exception reading shortcut to add: " + e);
+ } catch (URISyntaxException e) {
+ Log.d(TAG, "Exception reading shortcut to add: " + e);
+ }
+ return null;
+ }
}