summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/com/android/launcher3/AppInfo.java19
-rw-r--r--src/com/android/launcher3/InstallShortcutReceiver.java377
-rw-r--r--src/com/android/launcher3/LauncherAppState.java15
-rw-r--r--src/com/android/launcher3/LauncherModel.java137
4 files changed, 331 insertions, 217 deletions
diff --git a/src/com/android/launcher3/AppInfo.java b/src/com/android/launcher3/AppInfo.java
index 674d8e819..6d1350a59 100644
--- a/src/com/android/launcher3/AppInfo.java
+++ b/src/com/android/launcher3/AppInfo.java
@@ -88,16 +88,11 @@ public class AppInfo extends ItemInfo {
flags = initFlags(info);
firstInstallTime = info.getFirstInstallTime();
iconCache.getTitleAndIcon(this, info, labelCache);
- intent = new Intent(Intent.ACTION_MAIN);
- intent.addCategory(Intent.CATEGORY_LAUNCHER);
- intent.setComponent(info.getComponentName());
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- long serialNumber = UserManagerCompat.getInstance(context).getSerialNumberForUser(user);
- intent.putExtra(EXTRA_PROFILE, serialNumber);
+ intent = makeLaunchIntent(context, info, user);
this.user = user;
}
- private static int initFlags(LauncherActivityInfoCompat info) {
+ public static int initFlags(LauncherActivityInfoCompat info) {
int appFlags = info.getApplicationInfo().flags;
int flags = 0;
if ((appFlags & android.content.pm.ApplicationInfo.FLAG_SYSTEM) == 0) {
@@ -154,4 +149,14 @@ public class AppInfo extends ItemInfo {
public ShortcutInfo makeShortcut() {
return new ShortcutInfo(this);
}
+
+ public static Intent makeLaunchIntent(Context context, LauncherActivityInfoCompat info,
+ UserHandleCompat user) {
+ long serialNumber = UserManagerCompat.getInstance(context).getSerialNumberForUser(user);
+ return new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_LAUNCHER)
+ .setComponent(info.getComponentName())
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
+ .putExtra(EXTRA_PROFILE, serialNumber);
+ }
}
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;
+ }
}
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 29c88fa79..5b03ad433 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -46,12 +46,14 @@ public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks {
private final AppFilter mAppFilter;
private final BuildInfo mBuildInfo;
- private LauncherModel mModel;
- private IconCache mIconCache;
+ private final LauncherModel mModel;
+ private final IconCache mIconCache;
+
+ private final boolean mIsScreenLarge;
+ private final float mScreenDensity;
+ private final int mLongPressTimeout = 300;
+
private WidgetPreviewLoader.CacheDb mWidgetPreviewCacheDb;
- private boolean mIsScreenLarge;
- private float mScreenDensity;
- private int mLongPressTimeout = 300;
private boolean mWallpaperChangedSinceLastCheck;
private static WeakReference<LauncherProvider> sLauncherProvider;
@@ -158,9 +160,6 @@ public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks {
};
LauncherModel setLauncher(Launcher launcher) {
- if (mModel == null) {
- throw new IllegalStateException("setLauncher() called before init()");
- }
mModel.initialize(launcher);
return mModel;
}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 7f7dbc93c..f3da7c49c 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -30,6 +30,7 @@ import android.content.Intent;
import android.content.Intent.ShortcutIconResource;
import android.content.IntentFilter;
import android.content.SharedPreferences;
+import android.content.pm.LauncherApps.Callback;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
@@ -78,7 +79,6 @@ import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
-import java.util.concurrent.atomic.AtomicBoolean;
/**
* Maintains in-memory state of the Launcher. It is expected that there should be only one
@@ -115,6 +115,11 @@ public class LauncherModel extends BroadcastReceiver
private boolean mIsLoaderTaskRunning;
private volatile boolean mFlushingWorkerThread;
+ /**
+ * Maintain a set of packages per user, for which we added a shortcut on the workspace.
+ */
+ private static final String INSTALLED_SHORTCUTS_SET_PREFIX = "installed_shortcuts_set_for_user_";
+
// Specific runnable types that are run on the main thread deferred handler, this allows us to
// clear all queued binding runnables when the Launcher activity is destroyed.
private static final int MAIN_THREAD_NORMAL_RUNNABLE = 0;
@@ -403,7 +408,7 @@ public class LauncherModel extends BroadcastReceiver
// Process the updated package state
Runnable r = new Runnable() {
public void run() {
- Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;
+ Callbacks callbacks = getCallback();
if (callbacks != null) {
callbacks.updatePackageState(installInfo);
}
@@ -416,7 +421,7 @@ public class LauncherModel extends BroadcastReceiver
// Process the updated package badge
Runnable r = new Runnable() {
public void run() {
- Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;
+ Callbacks callbacks = getCallback();
if (callbacks != null) {
callbacks.updatePackageBadge(packageName);
}
@@ -426,7 +431,7 @@ public class LauncherModel extends BroadcastReceiver
}
public void addAppsToAllApps(final Context ctx, final ArrayList<AppInfo> allAppsApps) {
- final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;
+ final Callbacks callbacks = getCallback();
if (allAppsApps == null) {
throw new RuntimeException("allAppsApps must not be null");
@@ -440,7 +445,7 @@ public class LauncherModel extends BroadcastReceiver
public void run() {
runOnMainThread(new Runnable() {
public void run() {
- Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;
+ Callbacks cb = getCallback();
if (callbacks == cb && cb != null) {
callbacks.bindAppsAdded(null, null, null, allAppsApps);
}
@@ -453,7 +458,7 @@ public class LauncherModel extends BroadcastReceiver
public void addAndBindAddedWorkspaceApps(final Context context,
final ArrayList<ItemInfo> workspaceApps) {
- final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;
+ final Callbacks callbacks = getCallback();
if (workspaceApps == null) {
throw new RuntimeException("workspaceApps and allAppsApps must not be null");
@@ -485,7 +490,7 @@ public class LauncherModel extends BroadcastReceiver
final Intent launchIntent = a.getIntent();
// Short-circuit this logic if the icon exists somewhere on the workspace
- if (shortcutExists(context, name, launchIntent)) {
+ if (shortcutExists(context, name, launchIntent, a.user)) {
continue;
}
@@ -544,7 +549,7 @@ public class LauncherModel extends BroadcastReceiver
if (!addedShortcutsFinal.isEmpty()) {
runOnMainThread(new Runnable() {
public void run() {
- Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;
+ Callbacks cb = getCallback();
if (callbacks == cb && cb != null) {
final ArrayList<ItemInfo> addAnimated = new ArrayList<ItemInfo>();
final ArrayList<ItemInfo> addNotAnimated = new ArrayList<ItemInfo>();
@@ -904,7 +909,8 @@ public class LauncherModel extends BroadcastReceiver
* Returns true if the shortcuts already exists in the database.
* we identify a shortcut by its title and intent.
*/
- static boolean shortcutExists(Context context, String title, Intent intent) {
+ static boolean shortcutExists(Context context, String title, Intent intent,
+ UserHandleCompat user) {
final ContentResolver cr = context.getContentResolver();
final Intent intentWithPkg, intentWithoutPkg;
@@ -923,16 +929,18 @@ public class LauncherModel extends BroadcastReceiver
intentWithPkg = intent;
intentWithoutPkg = intent;
}
+ String userSerial = Long.toString(UserManagerCompat.getInstance(context)
+ .getSerialNumberForUser(user));
Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,
- new String[]{"title", "intent"}, "title=? and (intent=? or intent=?)",
- new String[]{title, intentWithPkg.toUri(0), intentWithoutPkg.toUri(0) }, null);
- boolean result = false;
+ new String[] { "title", "intent", "profileId" },
+ "title=? and (intent=? or intent=?) and profileId=?",
+ new String[] { title, intentWithPkg.toUri(0), intentWithoutPkg.toUri(0), userSerial },
+ null);
try {
- result = c.moveToFirst();
+ return c.moveToFirst();
} finally {
c.close();
}
- return result;
}
/**
@@ -1374,11 +1382,9 @@ public class LauncherModel extends BroadcastReceiver
mPreviousConfigMcc = currentConfig.mcc;
} else if (SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED.equals(action) ||
SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED.equals(action)) {
- if (mCallbacks != null) {
- Callbacks callbacks = mCallbacks.get();
- if (callbacks != null) {
- callbacks.bindSearchablesChanged();
- }
+ Callbacks callbacks = getCallback();
+ if (callbacks != null) {
+ callbacks.bindSearchablesChanged();
}
} else if (ACTION_UNREAD_CHANGED.equals(action)) {
ComponentName componentName = intent.getParcelableExtra("component_name");
@@ -1425,13 +1431,11 @@ public class LauncherModel extends BroadcastReceiver
*/
public void startLoaderFromBackground() {
boolean runLoader = false;
- if (mCallbacks != null) {
- Callbacks callbacks = mCallbacks.get();
- if (callbacks != null) {
- // Only actually run the loader if they're not paused.
- if (!callbacks.setLoadOnResume()) {
- runLoader = true;
- }
+ Callbacks callbacks = getCallback();
+ if (callbacks != null) {
+ // Only actually run the loader if they're not paused.
+ if (!callbacks.setLoadOnResume()) {
+ runLoader = true;
}
}
if (runLoader) {
@@ -3149,6 +3153,8 @@ public class LauncherModel extends BroadcastReceiver
// Clear the list of apps
mBgAllAppsList.clear();
+ SharedPreferences prefs = mContext.getSharedPreferences(
+ LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);
for (UserHandleCompat user : profiles) {
// Query for the set of apps
final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
@@ -3159,6 +3165,7 @@ public class LauncherModel extends BroadcastReceiver
Log.d(TAG, "getActivityList got " + apps.size() + " apps for user " + user);
}
// Fail if we don't have any apps
+ // TODO: Fix this. Only fail for the current user.
if (apps == null || apps.isEmpty()) {
return;
}
@@ -3177,6 +3184,25 @@ public class LauncherModel extends BroadcastReceiver
// This builds the icon bitmaps.
mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache, mLabelCache));
}
+
+ if (!user.equals(UserHandleCompat.myUserHandle())) {
+ // Add shortcuts for packages which were installed while launcher was dead.
+ String shortcutsSetKey = INSTALLED_SHORTCUTS_SET_PREFIX
+ + mUserManager.getSerialNumberForUser(user);
+ Set<String> packagesAdded = prefs.getStringSet(shortcutsSetKey, Collections.EMPTY_SET);
+ HashSet<String> newPackageSet = new HashSet<String>();
+
+ for (LauncherActivityInfoCompat info : apps) {
+ String packageName = info.getComponentName().getPackageName();
+ if (!packagesAdded.contains(packageName)
+ && !newPackageSet.contains(packageName)) {
+ InstallShortcutReceiver.queueInstallShortcut(info, mContext);
+ }
+ newPackageSet.add(packageName);
+ }
+
+ prefs.edit().putStringSet(shortcutsSetKey, newPackageSet).commit();
+ }
}
// Huh? Shouldn't this be inside the Runnable below?
final ArrayList<AppInfo> added = mBgAllAppsList.added;
@@ -3349,6 +3375,30 @@ public class LauncherModel extends BroadcastReceiver
mIconCache.remove(packages[i], mUser);
mBgAllAppsList.addPackage(context, packages[i], mUser);
}
+
+ // Auto add shortcuts for added packages.
+ if (!UserHandleCompat.myUserHandle().equals(mUser)) {
+ SharedPreferences prefs = context.getSharedPreferences(
+ LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);
+ String shortcutsSetKey = INSTALLED_SHORTCUTS_SET_PREFIX
+ + mUserManager.getSerialNumberForUser(mUser);
+ Set<String> shortcutSet = new HashSet<String>(
+ prefs.getStringSet(shortcutsSetKey,Collections.EMPTY_SET));
+
+ for (int i=0; i<N; i++) {
+ if (!shortcutSet.contains(packages[i])) {
+ shortcutSet.add(packages[i]);
+ List<LauncherActivityInfoCompat> activities =
+ mLauncherApps.getActivityList(packages[i], mUser);
+ if (activities != null && !activities.isEmpty()) {
+ InstallShortcutReceiver.queueInstallShortcut(
+ activities.get(0), context);
+ }
+ }
+ }
+
+ prefs.edit().putStringSet(shortcutsSetKey, shortcutSet).commit();
+ }
break;
case OP_UPDATE:
for (int i=0; i<N; i++) {
@@ -3359,6 +3409,19 @@ public class LauncherModel extends BroadcastReceiver
}
break;
case OP_REMOVE:
+ // Remove the packageName for the set of auto-installed shortcuts. This
+ // will ensure that the shortcut when the app is installed again.
+ if (!UserHandleCompat.myUserHandle().equals(mUser)) {
+ SharedPreferences prefs = context.getSharedPreferences(
+ LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);
+ String shortcutsSetKey = INSTALLED_SHORTCUTS_SET_PREFIX
+ + mUserManager.getSerialNumberForUser(mUser);
+ HashSet<String> shortcutSet = new HashSet<String>(
+ prefs.getStringSet(shortcutsSetKey, Collections.EMPTY_SET));
+ shortcutSet.removeAll(Arrays.asList(mPackages));
+ prefs.edit().putStringSet(shortcutsSetKey, shortcutSet).commit();
+ }
+ // Fall through
case OP_UNAVAILABLE:
boolean clearCache = mOp == OP_REMOVE;
for (int i=0; i<N; i++) {
@@ -3387,7 +3450,7 @@ public class LauncherModel extends BroadcastReceiver
mBgAllAppsList.removed.clear();
}
- final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;
+ final Callbacks callbacks = getCallback();
if (callbacks == null) {
Log.w(TAG, "Nobody to tell about the new app. Launcher is probably loading.");
return;
@@ -3417,7 +3480,7 @@ public class LauncherModel extends BroadcastReceiver
mHandler.post(new Runnable() {
public void run() {
- Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;
+ Callbacks cb = getCallback();
if (callbacks == cb && cb != null) {
callbacks.bindAppsUpdated(modifiedFinal);
}
@@ -3530,7 +3593,7 @@ public class LauncherModel extends BroadcastReceiver
mHandler.post(new Runnable() {
public void run() {
- Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;
+ Callbacks cb = getCallback();
if (callbacks == cb && cb != null) {
callbacks.bindShortcutsChanged(
updatedShortcuts, removedShortcuts, mUser);
@@ -3544,7 +3607,7 @@ public class LauncherModel extends BroadcastReceiver
if (!widgets.isEmpty()) {
mHandler.post(new Runnable() {
public void run() {
- Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;
+ Callbacks cb = getCallback();
if (callbacks == cb && cb != null) {
callbacks.bindWidgetsRestored(widgets);
}
@@ -3585,14 +3648,11 @@ public class LauncherModel extends BroadcastReceiver
}
// Remove any queued items from the install queue
- String spKey = LauncherAppState.getSharedPreferencesKey();
- SharedPreferences sp =
- context.getSharedPreferences(spKey, Context.MODE_PRIVATE);
- InstallShortcutReceiver.removeFromInstallQueue(sp, removedPackageNames);
+ InstallShortcutReceiver.removeFromInstallQueue(context, removedPackageNames, mUser);
// Call the components-removed callback
mHandler.post(new Runnable() {
public void run() {
- Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;
+ Callbacks cb = getCallback();
if (callbacks == cb && cb != null) {
callbacks.bindComponentsRemoved(
removedPackageNames, removedApps, mUser, removeReason);
@@ -3606,7 +3666,7 @@ public class LauncherModel extends BroadcastReceiver
mHandler.post(new Runnable() {
@Override
public void run() {
- Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;
+ Callbacks cb = getCallback();
if (callbacks == cb && cb != null) {
callbacks.bindPackagesUpdated(widgetsAndShortcuts);
}
@@ -3616,7 +3676,7 @@ public class LauncherModel extends BroadcastReceiver
// Write all the logs to disk
mHandler.post(new Runnable() {
public void run() {
- Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;
+ Callbacks cb = getCallback();
if (callbacks == cb && cb != null) {
callbacks.dumpLogsToLocalData();
}
@@ -4179,4 +4239,7 @@ public class LauncherModel extends BroadcastReceiver
return null;
}
+ public Callbacks getCallback() {
+ return mCallbacks != null ? mCallbacks.get() : null;
+ }
}