diff --git a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java index ca7ce746b6..a53dc1545f 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java +++ b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java @@ -17,10 +17,15 @@ package com.android.launcher3.uioverrides; import android.app.Person; +import android.content.Context; +import android.content.pm.LauncherActivityInfo; +import android.content.pm.LauncherApps; import android.content.pm.ShortcutInfo; import com.android.launcher3.Utilities; +import java.util.Map; + /** * A wrapper for the hidden API calls */ @@ -32,4 +37,8 @@ public class ApiWrapper { Person[] persons = si.getPersons(); return persons == null ? Utilities.EMPTY_PERSON_ARRAY : persons; } + + public static Map getActivityOverrides(Context context) { + return context.getSystemService(LauncherApps.class).getActivityOverrides(); + } } diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java index 55ede6cecb..27c41c2fcd 100644 --- a/src/com/android/launcher3/AutoInstallsLayout.java +++ b/src/com/android/launcher3/AutoInstallsLayout.java @@ -16,11 +16,14 @@ package com.android.launcher3; +import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; + import android.content.ComponentName; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; +import android.content.pm.LauncherActivityInfo; import android.content.pm.PackageManager; import android.content.res.Resources; import android.database.sqlite.SQLiteDatabase; @@ -40,9 +43,12 @@ import com.android.launcher3.LauncherProvider.SqlArguments; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.icons.GraphicsUtils; import com.android.launcher3.icons.LauncherIcons; +import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.LauncherAppWidgetInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; +import com.android.launcher3.pm.UserCache; import com.android.launcher3.qsb.QsbContainerView; +import com.android.launcher3.uioverrides.ApiWrapper; import com.android.launcher3.util.IntArray; import com.android.launcher3.util.Partner; import com.android.launcher3.util.Thunk; @@ -53,6 +59,7 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.util.Locale; +import java.util.Map; import java.util.function.Supplier; /** @@ -162,7 +169,7 @@ public class AutoInstallsLayout { private final InvariantDeviceProfile mIdp; private final int mRowCount; private final int mColumnCount; - + private final Map mActivityOverride; private final int[] mTemp = new int[2]; @Thunk final ContentValues mValues; @@ -193,6 +200,7 @@ public class AutoInstallsLayout { mIdp = LauncherAppState.getIDP(context); mRowCount = mIdp.numRows; mColumnCount = mIdp.numColumns; + mActivityOverride = ApiWrapper.getActivityOverrides(context); } /** @@ -299,6 +307,9 @@ public class AutoInstallsLayout { mValues.put(Favorites.SPANX, 1); mValues.put(Favorites.SPANY, 1); mValues.put(Favorites._ID, id); + + maybeReplaceShortcut(intent.getComponent().getPackageName(), type); + if (mCallback.insertAndCheck(mDb, mValues) < 0) { return -1; } else { @@ -364,7 +375,7 @@ public class AutoInstallsLayout { | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); return addShortcut(info.loadLabel(mPackageManager).toString(), - intent, Favorites.ITEM_TYPE_APPLICATION); + intent, ITEM_TYPE_APPLICATION); } catch (PackageManager.NameNotFoundException e) { Log.e(TAG, "Favorite not found: " + packageName + "/" + className); } @@ -404,7 +415,7 @@ public class AutoInstallsLayout { .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); return addShortcut(mContext.getString(R.string.package_state_unknown), intent, - Favorites.ITEM_TYPE_APPLICATION); + ITEM_TYPE_APPLICATION); } } @@ -573,8 +584,7 @@ public class AutoInstallsLayout { } @Override - public int parseAndAdd(XmlPullParser parser) - throws XmlPullParserException, IOException { + public int parseAndAdd(XmlPullParser parser) throws XmlPullParserException, IOException { final String title; final int titleResId = getAttributeResourceValue(parser, ATTR_TITLE, 0); if (titleResId != 0) { @@ -717,4 +727,13 @@ public class AutoInstallsLayout { static void copyInteger(ContentValues from, ContentValues to, String key) { to.put(key, from.getAsInteger(key)); } + + private void maybeReplaceShortcut(String packageName, int type) { + if (mActivityOverride.containsKey(packageName) && type == ITEM_TYPE_APPLICATION) { + LauncherActivityInfo replacementInfo = mActivityOverride.get(packageName); + mValues.put(Favorites.PROFILE_ID, UserCache.INSTANCE.get(mContext) + .getSerialNumberForUser(replacementInfo.getUser())); + mValues.put(Favorites.INTENT, AppInfo.makeLaunchIntent(replacementInfo).toUri(0)); + } + } } diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java index 2a452be8dd..5789a6c9c8 100644 --- a/src/com/android/launcher3/provider/RestoreDbTask.java +++ b/src/com/android/launcher3/provider/RestoreDbTask.java @@ -20,15 +20,19 @@ import static com.android.launcher3.InvariantDeviceProfile.TYPE_MULTI_DISPLAY; import static com.android.launcher3.LauncherPrefs.APP_WIDGET_IDS; import static com.android.launcher3.LauncherPrefs.OLD_APP_WIDGET_IDS; import static com.android.launcher3.LauncherPrefs.RESTORE_DEVICE; +import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; import static com.android.launcher3.provider.LauncherDbUtils.dropTable; import android.app.backup.BackupManager; import android.content.ContentValues; import android.content.Context; +import android.content.Intent; +import android.content.pm.LauncherActivityInfo; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.os.UserHandle; import android.text.TextUtils; +import android.util.Log; import android.util.LongSparseArray; import android.util.SparseLongArray; @@ -44,15 +48,21 @@ import com.android.launcher3.Utilities; import com.android.launcher3.logging.FileLog; import com.android.launcher3.model.DeviceGridState; import com.android.launcher3.model.GridBackupTable; +import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.LauncherAppWidgetInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; +import com.android.launcher3.pm.UserCache; import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction; +import com.android.launcher3.uioverrides.ApiWrapper; import com.android.launcher3.util.IntArray; import com.android.launcher3.util.LogConfig; import com.android.launcher3.widget.LauncherWidgetHolder; import java.io.InvalidObjectException; import java.util.Arrays; +import java.util.Collection; +import java.util.Map; +import java.util.stream.Collectors; /** * Utility class to update DB schema after it has been restored. @@ -159,6 +169,7 @@ public class RestoreDbTask { * 3. If the user serial for any restored profile is different than that of the previous * device, update the entries to the new profile id. * 4. If restored from a single display backup, remove gaps between screenIds + * 5. Override shortcuts that need to be replaced. * * @return number of items deleted. */ @@ -245,6 +256,9 @@ public class RestoreDbTask { removeScreenIdGaps(db); } + // Override shortcuts + maybeOverrideShortcuts(context, db, myProfileId); + return itemsDeleted; } @@ -374,4 +388,48 @@ public class RestoreDbTask { APP_WIDGET_IDS.to(IntArray.wrap(newIds).toConcatString())); } + protected static void maybeOverrideShortcuts(Context context, SQLiteDatabase db, + long currentUser) { + Map activityOverrides = ApiWrapper.getActivityOverrides( + context); + + if (activityOverrides == null || activityOverrides.isEmpty()) { + return; + } + + try (Cursor c = db.query(Favorites.TABLE_NAME, + new String[]{Favorites._ID, Favorites.INTENT}, + String.format("%s=? AND %s=? AND ( %s )", Favorites.ITEM_TYPE, Favorites.PROFILE_ID, + getTelephonyIntentSQLLiteSelection(activityOverrides.keySet())), + new String[]{String.valueOf(ITEM_TYPE_APPLICATION), String.valueOf(currentUser)}, + null, null, null); + SQLiteTransaction t = new SQLiteTransaction(db)) { + final int idIndex = c.getColumnIndexOrThrow(Favorites._ID); + final int intentIndex = c.getColumnIndexOrThrow(Favorites.INTENT); + while (c.moveToNext()) { + LauncherActivityInfo override = activityOverrides.get(Intent.parseUri( + c.getString(intentIndex), 0).getComponent().getPackageName()); + if (override != null) { + ContentValues values = new ContentValues(); + values.put(Favorites.PROFILE_ID, + UserCache.INSTANCE.get(context).getSerialNumberForUser( + override.getUser())); + values.put(Favorites.INTENT, AppInfo.makeLaunchIntent(override).toUri(0)); + db.update(Favorites.TABLE_NAME, values, String.format("%s=?", Favorites._ID), + new String[]{String.valueOf(c.getInt(idIndex))}); + } + } + t.commit(); + } catch (Exception ex) { + Log.e(TAG, "Error while overriding shortcuts", ex); + } + } + + private static String getTelephonyIntentSQLLiteSelection(Collection packages) { + return packages.stream().map( + packageToChange -> String.format("intent LIKE '%%' || '%s' || '%%' ", + packageToChange)).collect( + Collectors.joining(" OR ")); + } + } diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java b/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java index 47bf135cee..d6b41c9c60 100644 --- a/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java +++ b/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java @@ -17,10 +17,15 @@ package com.android.launcher3.uioverrides; import android.app.Person; +import android.content.Context; +import android.content.pm.LauncherActivityInfo; import android.content.pm.ShortcutInfo; import com.android.launcher3.Utilities; +import java.util.Collections; +import java.util.Map; + /** * A wrapper for the hidden API calls */ @@ -31,4 +36,8 @@ public class ApiWrapper { public static Person[] getPersons(ShortcutInfo si) { return Utilities.EMPTY_PERSON_ARRAY; } + + public static Map getActivityOverrides(Context context) { + return Collections.emptyMap(); + } }