Removing support for adding legacy shortcuts.
All existing legacy shortcuts will be migrated one-time to deep shortcuts
This shortcuts are pinned under the Launcher package, with custom badging
Bug: 275875209
Test: Updated unit tests
Flag: N/A
Change-Id: I7da001f724776ad8d6c807517b7e4e259de626c2
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 4f7380a..59f56ff 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -82,7 +82,6 @@
import android.content.Intent;
import android.content.IntentSender;
import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Color;
@@ -92,7 +91,6 @@
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Parcelable;
-import android.os.Process;
import android.os.StrictMode;
import android.os.SystemClock;
import android.os.Trace;
@@ -115,7 +113,6 @@
import android.view.WindowManager.LayoutParams;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.OvershootInterpolator;
-import android.widget.Toast;
import android.window.BackEvent;
import android.window.OnBackAnimationCallback;
@@ -160,7 +157,6 @@
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.BgDataModel.Callbacks;
import com.android.launcher3.model.ItemInstallQueue;
-import com.android.launcher3.model.ModelUtils;
import com.android.launcher3.model.ModelWriter;
import com.android.launcher3.model.StringCache;
import com.android.launcher3.model.WidgetsModel;
@@ -192,7 +188,6 @@
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.OnboardingPrefs;
-import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.PendingRequestArgs;
import com.android.launcher3.util.RunnableList;
@@ -263,8 +258,6 @@
public static final int REQUEST_BIND_PENDING_APPWIDGET = 12;
public static final int REQUEST_RECONFIGURE_APPWIDGET = 13;
- private static final int REQUEST_PERMISSION_CALL_PHONE = 14;
-
private static final float BOUNCE_ANIMATION_TENSION = 1.3f;
/**
@@ -975,33 +968,6 @@
handleActivityResult(requestCode, resultCode, data);
}
- @Override
- public void onRequestPermissionsResult(int requestCode, String[] permissions,
- int[] grantResults) {
- PendingRequestArgs pendingArgs = mPendingRequestArgs;
- if (requestCode == REQUEST_PERMISSION_CALL_PHONE && pendingArgs != null
- && pendingArgs.getRequestCode() == REQUEST_PERMISSION_CALL_PHONE) {
- setWaitingForResult(null);
-
- View v = null;
- CellPos cellPos = getCellPosMapper().mapModelToPresenter(pendingArgs);
- CellLayout layout = getCellLayout(pendingArgs.container, cellPos.screenId);
- if (layout != null) {
- v = layout.getChildAt(cellPos.cellX, cellPos.cellY);
- }
- Intent intent = pendingArgs.getPendingIntent();
-
- if (grantResults.length > 0
- && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
- startActivitySafely(v, intent, null);
- } else {
- // TODO: Show a snack bar with link to settings
- Toast.makeText(this, getString(R.string.msg_no_phone_permission,
- getString(R.string.derived_app_name)), Toast.LENGTH_SHORT).show();
- }
- }
- }
-
/**
* Check to see if a given screen id exists. If not, create it at the end, return the new id.
*
@@ -1417,21 +1383,9 @@
WorkspaceItemInfo info = PinRequestHelper.createWorkspaceItemFromPinItemRequest(
this, PinRequestHelper.getPinItemRequest(data), 0);
-
if (info == null) {
- // Legacy shortcuts are only supported for primary profile.
- info = Process.myUserHandle().equals(args.user)
- ? ModelUtils.fromLegacyShortcutIntent(this, data) : null;
-
- if (info == null) {
- Log.e(TAG, "Unable to parse a valid custom shortcut result");
- return;
- } else if (!new PackageManagerHelper(this).hasPermissionForActivity(
- info.intent, args.getPendingIntent().getComponent().getPackageName())) {
- // The app is trying to add a shortcut without sufficient permissions
- Log.e(TAG, "Ignoring malicious intent " + info.intent.toUri(0));
- return;
- }
+ Log.e(TAG, "Unable to parse a valid shortcut result");
+ return;
}
if (container < 0) {
@@ -2151,27 +2105,6 @@
}
}
- @TargetApi(Build.VERSION_CODES.M)
- @Override
- public boolean onErrorStartingShortcut(Intent intent, ItemInfo info) {
- // Due to legacy reasons, direct call shortcuts require Launchers to have the
- // corresponding permission. Show the appropriate permission prompt if that
- // is the case.
- if (intent.getComponent() == null
- && Intent.ACTION_CALL.equals(intent.getAction())
- && checkSelfPermission(android.Manifest.permission.CALL_PHONE) !=
- PackageManager.PERMISSION_GRANTED) {
-
- setWaitingForResult(PendingRequestArgs
- .forIntent(REQUEST_PERMISSION_CALL_PHONE, intent, info));
- requestPermissions(new String[]{android.Manifest.permission.CALL_PHONE},
- REQUEST_PERMISSION_CALL_PHONE);
- return true;
- } else {
- return false;
- }
- }
-
@Override
public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
if (!hasBeenResumed()) {
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index 1cd2a30..1bbb09a 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -131,18 +131,6 @@
public static final int ITEM_TYPE_SEARCH_ACTION = 9;
/**
- * The icon package name in Intent.ShortcutIconResource
- * <P>Type: TEXT</P>
- */
- public static final String ICON_PACKAGE = "iconPackage";
-
- /**
- * The icon resource name in Intent.ShortcutIconResource
- * <P>Type: TEXT</P>
- */
- public static final String ICON_RESOURCE = "iconResource";
-
- /**
* The custom icon bitmap.
* <P>Type: BLOB</P>
*/
@@ -357,8 +345,6 @@
"spanY INTEGER," +
"itemType INTEGER," +
"appWidgetId INTEGER NOT NULL DEFAULT -1," +
- "iconPackage TEXT," +
- "iconResource TEXT," +
"icon BLOB," +
"appWidgetProvider TEXT," +
"modified INTEGER NOT NULL DEFAULT 0," +
diff --git a/src/com/android/launcher3/model/DatabaseHelper.java b/src/com/android/launcher3/model/DatabaseHelper.java
index 3578b67..1840b75 100644
--- a/src/com/android/launcher3/model/DatabaseHelper.java
+++ b/src/com/android/launcher3/model/DatabaseHelper.java
@@ -72,7 +72,7 @@
* Represents the schema of the database. Changes in scheme need not be backwards compatible.
* When increasing the scheme version, ensure that downgrade_schema.json is updated
*/
- public static final int SCHEMA_VERSION = 31;
+ public static final int SCHEMA_VERSION = 32;
private static final String TAG = "DatabaseHelper";
private static final boolean LOGD = false;
@@ -327,6 +327,10 @@
return;
}
case 31: {
+ LauncherDbUtils.migrateLegacyShortcuts(mContext, db);
+ }
+ // Fall through
+ case 32: {
// DB Upgraded successfully
return;
}
diff --git a/src/com/android/launcher3/model/DbDowngradeHelper.java b/src/com/android/launcher3/model/DbDowngradeHelper.java
index e5c44d1..006a9b7 100644
--- a/src/com/android/launcher3/model/DbDowngradeHelper.java
+++ b/src/com/android/launcher3/model/DbDowngradeHelper.java
@@ -72,8 +72,18 @@
}
}
+ /**
+ * Creates a helper from the provided file
+ */
public static DbDowngradeHelper parse(File file) throws JSONException, IOException {
- JSONObject obj = new JSONObject(new String(IOUtils.toByteArray(file)));
+ return parse(IOUtils.toByteArray(file));
+ }
+
+ /**
+ * Creates a helper from the provided bytes
+ */
+ public static DbDowngradeHelper parse(byte[] fileData) throws JSONException {
+ JSONObject obj = new JSONObject(new String(fileData));
DbDowngradeHelper helper = new DbDowngradeHelper(obj.getInt(KEY_VERSION));
for (int version = helper.version - 1; version > 0; version--) {
if (obj.has(KEY_DOWNGRADE_TO + version)) {
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index 855a69d..c237f5b 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -75,8 +75,6 @@
private final IntArray mRestoredRows = new IntArray();
private final IntSparseArrayMap<GridOccupancy> mOccupied = new IntSparseArrayMap<>();
- private final int mIconPackageIndex;
- private final int mIconResourceIndex;
private final int mIconIndex;
public final int mTitleIndex;
@@ -122,8 +120,6 @@
// Init column indices
mIconIndex = getColumnIndexOrThrow(Favorites.ICON);
- mIconPackageIndex = getColumnIndexOrThrow(Favorites.ICON_PACKAGE);
- mIconResourceIndex = getColumnIndexOrThrow(Favorites.ICON_RESOURCE);
mTitleIndex = getColumnIndexOrThrow(Favorites.TITLE);
mIdIndex = getColumnIndexOrThrow(Favorites._ID);
@@ -200,23 +196,25 @@
public IconRequestInfo<WorkspaceItemInfo> createIconRequestInfo(
WorkspaceItemInfo wai, boolean useLowResIcon) {
- String packageName = itemType == Favorites.ITEM_TYPE_SHORTCUT
- ? getString(mIconPackageIndex) : null;
- String resourceName = itemType == Favorites.ITEM_TYPE_SHORTCUT
- ? getString(mIconResourceIndex) : null;
byte[] iconBlob = itemType == Favorites.ITEM_TYPE_SHORTCUT
|| itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT
|| restoreFlag != 0
- ? getBlob(mIconIndex) : null;
+ ? getIconBlob() : null;
- return new IconRequestInfo<>(
- wai, mActivityInfo, packageName, resourceName, iconBlob, useLowResIcon);
+ return new IconRequestInfo<>(wai, mActivityInfo, iconBlob, useLowResIcon);
+ }
+
+ /**
+ * Returns the icon data for at the current position
+ */
+ public byte[] getIconBlob() {
+ return getBlob(mIconIndex);
}
/**
* Returns the title or empty string
*/
- private String getTitle() {
+ public String getTitle() {
return Utilities.trim(getString(mTitleIndex));
}
diff --git a/src/com/android/launcher3/model/ModelUtils.java b/src/com/android/launcher3/model/ModelUtils.java
index c21fc38..48fb537 100644
--- a/src/com/android/launcher3/model/ModelUtils.java
+++ b/src/com/android/launcher3/model/ModelUtils.java
@@ -15,18 +15,10 @@
*/
package com.android.launcher3.model;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.os.Process;
import android.util.Log;
import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.icons.BitmapInfo;
-import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
@@ -99,60 +91,4 @@
IntStream.range(0, len).filter(i -> !seen.contains(i)).forEach(result::add);
return result;
}
-
-
- /**
- * Creates a workspace item info for the legacy shortcut intent
- */
- @SuppressWarnings("deprecation")
- public static WorkspaceItemInfo fromLegacyShortcutIntent(Context context, Intent data) {
- if (!isValidExtraType(data, Intent.EXTRA_SHORTCUT_INTENT, Intent.class)
- || !(isValidExtraType(data, Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
- Intent.ShortcutIconResource.class))
- || !(isValidExtraType(data, Intent.EXTRA_SHORTCUT_ICON, Bitmap.class))) {
-
- Log.e(TAG, "Invalid install shortcut intent");
- return null;
- }
-
- Intent launchIntent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
- String label = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
- if (launchIntent == null || label == null) {
- Log.e(TAG, "Invalid install shortcut intent");
- return null;
- }
-
- final WorkspaceItemInfo info = new WorkspaceItemInfo();
- info.user = Process.myUserHandle();
-
- BitmapInfo iconInfo = null;
- try (LauncherIcons li = LauncherIcons.obtain(context)) {
- Bitmap bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);
- if (bitmap != null) {
- iconInfo = li.createIconBitmap(bitmap);
- } else {
- info.iconResource = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);
- if (info.iconResource != null) {
- iconInfo = li.createIconBitmap(info.iconResource);
- }
- }
- }
-
- if (iconInfo == null) {
- Log.e(TAG, "Invalid icon by the app");
- return null;
- }
- info.bitmap = iconInfo;
- info.contentDescription = info.title = Utilities.trim(label);
- info.intent = launchIntent;
- return info;
- }
-
- /**
- * @return true if the extra is either null or is of type {@param type}
- */
- private static boolean isValidExtraType(Intent intent, String key, Class type) {
- Object extra = intent.getParcelableExtra(key);
- return extra == null || type.isInstance(extra);
- }
}
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 3d9d81f..1ab64df 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -36,9 +36,7 @@
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.IconCache;
-import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -204,18 +202,6 @@
boolean infoUpdated = false;
boolean shortcutUpdated = false;
- // Update shortcuts which use iconResource.
- if ((si.iconResource != null)
- && packageSet.contains(si.iconResource.packageName)) {
- LauncherIcons li = LauncherIcons.obtain(context);
- BitmapInfo iconInfo = li.createIconBitmap(si.iconResource);
- li.recycle();
- if (iconInfo != null) {
- si.bitmap = iconInfo;
- infoUpdated = true;
- }
- }
-
ComponentName cn = si.getTargetComponent();
if (cn != null && matcher.test(si)) {
String packageName = cn.getPackageName();
diff --git a/src/com/android/launcher3/model/data/IconRequestInfo.java b/src/com/android/launcher3/model/data/IconRequestInfo.java
index fbf01e5..e77e527 100644
--- a/src/com/android/launcher3/model/data/IconRequestInfo.java
+++ b/src/com/android/launcher3/model/data/IconRequestInfo.java
@@ -18,16 +18,12 @@
import static android.graphics.BitmapFactory.decodeByteArray;
import android.content.Context;
-import android.content.Intent;
import android.content.pm.LauncherActivityInfo;
-import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.LauncherIcons;
/**
@@ -42,8 +38,6 @@
@NonNull public final T itemInfo;
@Nullable public final LauncherActivityInfo launcherActivityInfo;
- @Nullable public final String packageName;
- @Nullable public final String resourceName;
@Nullable public final byte[] iconBlob;
public final boolean useLowResIcon;
@@ -54,8 +48,6 @@
this(
itemInfo,
launcherActivityInfo,
- /* packageName= */ null,
- /* resourceName= */ null,
/* iconBlob= */ null,
useLowResIcon);
}
@@ -63,14 +55,10 @@
public IconRequestInfo(
@NonNull T itemInfo,
@Nullable LauncherActivityInfo launcherActivityInfo,
- @Nullable String packageName,
- @Nullable String resourceName,
@Nullable byte[] iconBlob,
boolean useLowResIcon) {
this.itemInfo = itemInfo;
this.launcherActivityInfo = launcherActivityInfo;
- this.packageName = packageName;
- this.resourceName = resourceName;
this.iconBlob = iconBlob;
this.useLowResIcon = useLowResIcon;
}
@@ -87,31 +75,16 @@
try (LauncherIcons li = LauncherIcons.obtain(context)) {
WorkspaceItemInfo info = (WorkspaceItemInfo) itemInfo;
- if (itemInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
- if (!TextUtils.isEmpty(packageName) || !TextUtils.isEmpty(resourceName)) {
- info.iconResource = new Intent.ShortcutIconResource();
- info.iconResource.packageName = packageName;
- info.iconResource.resourceName = resourceName;
- BitmapInfo iconInfo = li.createIconBitmap(info.iconResource);
- if (iconInfo != null) {
- info.bitmap = iconInfo;
- return true;
- }
- }
- }
-
// Failed to load from resource, try loading from DB.
- try {
- if (iconBlob == null) {
- return false;
- }
- info.bitmap = li.createIconBitmap(decodeByteArray(
- iconBlob, 0, iconBlob.length));
- return true;
- } catch (Exception e) {
- Log.e(TAG, "Failed to decode byte array for info " + info, e);
+ if (iconBlob == null) {
return false;
}
+ info.bitmap = li.createIconBitmap(decodeByteArray(
+ iconBlob, 0, iconBlob.length));
+ return true;
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to decode byte array for info " + itemInfo, e);
+ return false;
}
}
}
diff --git a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
index 59ef320..01606d4 100644
--- a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
+++ b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
@@ -79,12 +79,6 @@
public Intent intent;
/**
- * If isShortcut=true and customIcon=false, this contains a reference to the
- * shortcut icon as an application's resource.
- */
- public Intent.ShortcutIconResource iconResource;
-
- /**
* A message to display when the user tries to start a disabled shortcut.
* This is currently only used for deep shortcuts.
*/
@@ -109,7 +103,6 @@
super(info);
title = info.title;
intent = new Intent(info.intent);
- iconResource = info.iconResource;
status = info.status;
personKeys = info.personKeys.clone();
}
@@ -141,10 +134,6 @@
if (!usingLowResIcon()) {
writer.putIcon(bitmap, user);
}
- if (iconResource != null) {
- writer.put(Favorites.ICON_PACKAGE, iconResource.packageName)
- .put(Favorites.ICON_RESOURCE, iconResource.resourceName);
- }
}
@Override
diff --git a/src/com/android/launcher3/pm/PinRequestHelper.java b/src/com/android/launcher3/pm/PinRequestHelper.java
index 179061f..667136a 100644
--- a/src/com/android/launcher3/pm/PinRequestHelper.java
+++ b/src/com/android/launcher3/pm/PinRequestHelper.java
@@ -24,8 +24,10 @@
import android.content.pm.LauncherApps;
import android.content.pm.LauncherApps.PinItemRequest;
import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutManager;
import android.os.Build;
import android.os.Parcelable;
+import android.os.SystemClock;
import androidx.annotation.Nullable;
@@ -63,17 +65,10 @@
}
} else {
// Block the worker thread until the accept() is called.
- MODEL_EXECUTOR.execute(new Runnable() {
- @Override
- public void run() {
- try {
- Thread.sleep(acceptDelay);
- } catch (InterruptedException e) {
- // Ignore
- }
- if (request.isValid()) {
- request.accept();
- }
+ MODEL_EXECUTOR.execute(() -> {
+ SystemClock.sleep(acceptDelay);
+ if (request.isValid()) {
+ request.accept();
}
});
}
@@ -95,4 +90,13 @@
Parcelable extra = intent.getParcelableExtra(LauncherApps.EXTRA_PIN_ITEM_REQUEST);
return extra instanceof PinItemRequest ? (PinItemRequest) extra : null;
}
+
+ /**
+ * Returns a PinItemRequest corresponding to the provided ShortcutInfo
+ */
+ public static PinItemRequest createRequestForShortcut(Context context, ShortcutInfo info) {
+ return context.getSystemService(LauncherApps.class)
+ .getPinItemRequest(context.getSystemService(ShortcutManager.class)
+ .createShortcutResultIntent(info));
+ }
}
diff --git a/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java b/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java
index 14e67b2..b24ee34 100644
--- a/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java
+++ b/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java
@@ -151,8 +151,6 @@
public static List<ShortcutConfigActivityInfo> queryList(
Context context, @Nullable PackageUserKey packageUser) {
List<ShortcutConfigActivityInfo> result = new ArrayList<>();
- UserHandle myUser = Process.myUserHandle();
-
final List<UserHandle> users;
final String packageName;
if (packageUser == null) {
@@ -164,11 +162,9 @@
}
LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
for (UserHandle user : users) {
- boolean ignoreTargetSdk = myUser.equals(user);
for (LauncherActivityInfo activityInfo :
launcherApps.getShortcutConfigActivityList(packageName, user)) {
- if (ignoreTargetSdk || activityInfo.getApplicationInfo().targetSdkVersion
- >= Build.VERSION_CODES.O) {
+ if (activityInfo.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.O) {
result.add(new ShortcutConfigActivityInfoVO(activityInfo));
}
}
diff --git a/src/com/android/launcher3/provider/LauncherDbUtils.java b/src/com/android/launcher3/provider/LauncherDbUtils.java
index b510378..48969fc 100644
--- a/src/com/android/launcher3/provider/LauncherDbUtils.java
+++ b/src/com/android/launcher3/provider/LauncherDbUtils.java
@@ -16,15 +16,34 @@
package com.android.launcher3.provider;
+import static com.android.launcher3.icons.IconCache.EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE;
+
+import android.content.ContentValues;
import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ShortcutInfo;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.Icon;
import android.os.Binder;
+import android.os.PersistableBundle;
import android.os.Process;
+import android.os.UserManager;
+import android.text.TextUtils;
+import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.model.LoaderCursor;
+import com.android.launcher3.model.UserManagerState;
+import com.android.launcher3.pm.PinRequestHelper;
import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.IntArray;
+import com.android.launcher3.util.IntSet;
/**
* A set of utility methods for Launcher DB used for DB updates and migration.
@@ -73,6 +92,78 @@
}
/**
+ * Migrates the legacy shortcuts to deep shortcuts pinned under Launcher.
+ * Removes any invalid shortcut or any shortcut which requires some permission to launch
+ */
+ public static void migrateLegacyShortcuts(Context context, SQLiteDatabase db) {
+ Cursor c = db.query(
+ Favorites.TABLE_NAME, null, "itemType = 1", null, null, null, null);
+ UserManagerState ums = new UserManagerState();
+ ums.init(UserCache.INSTANCE.get(context),
+ context.getSystemService(UserManager.class));
+ LoaderCursor lc = new LoaderCursor(c, null, LauncherAppState.getInstance(context), ums);
+ IntSet deletedShortcuts = new IntSet();
+
+ while (lc.moveToNext()) {
+ if (lc.user != Process.myUserHandle()) {
+ deletedShortcuts.add(lc.id);
+ continue;
+ }
+ Intent intent = lc.parseIntent();
+ if (intent == null) {
+ deletedShortcuts.add(lc.id);
+ continue;
+ }
+
+ // Make sure the target intent can be launched without any permissions. Otherwise remove
+ // the shortcut
+ ResolveInfo ri = context.getPackageManager().resolveActivity(intent, 0);
+ if (ri == null || !TextUtils.isEmpty(ri.activityInfo.permission)) {
+ deletedShortcuts.add(lc.id);
+ continue;
+ }
+ PersistableBundle extras = new PersistableBundle();
+ extras.putString(EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE, ri.activityInfo.packageName);
+ ShortcutInfo.Builder infoBuilder = new ShortcutInfo.Builder(
+ context, "migrated_shortcut-" + lc.id)
+ .setIntent(intent)
+ .setExtras(extras)
+ .setShortLabel(lc.getTitle());
+
+ Bitmap bitmap = null;
+ byte[] iconData = lc.getIconBlob();
+ if (iconData != null) {
+ bitmap = BitmapFactory.decodeByteArray(iconData, 0, iconData.length);
+ }
+ if (bitmap != null) {
+ infoBuilder.setIcon(Icon.createWithBitmap(bitmap));
+ }
+
+ ShortcutInfo info = infoBuilder.build();
+ if (!PinRequestHelper.createRequestForShortcut(context, info).accept()) {
+ deletedShortcuts.add(lc.id);
+ continue;
+ }
+ ContentValues update = new ContentValues();
+ update.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_DEEP_SHORTCUT);
+ update.put(Favorites.INTENT,
+ ShortcutKey.makeIntent(info.getId(), context.getPackageName()).toUri(0));
+ db.update(Favorites.TABLE_NAME, update, "_id = ?",
+ new String[] {Integer.toString(lc.id)});
+ }
+ lc.close();
+ if (!deletedShortcuts.isEmpty()) {
+ db.delete(Favorites.TABLE_NAME,
+ Utilities.createDbSelectionQuery(Favorites._ID, deletedShortcuts.getArray()),
+ null);
+ }
+
+ // Drop the unused columns
+ db.execSQL("ALTER TABLE " + Favorites.TABLE_NAME + " DROP COLUMN iconPackage;");
+ db.execSQL("ALTER TABLE " + Favorites.TABLE_NAME + " DROP COLUMN iconResource;");
+ }
+
+ /**
* Utility class to simplify managing sqlite transactions
*/
public static class SQLiteTransaction extends Binder implements AutoCloseable {
diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java
index a6a2751..1d6bc25 100644
--- a/src/com/android/launcher3/util/PackageManagerHelper.java
+++ b/src/com/android/launcher3/util/PackageManagerHelper.java
@@ -16,7 +16,6 @@
package com.android.launcher3.util;
-import android.app.AppOpsManager;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
@@ -30,7 +29,6 @@
import android.content.pm.ResolveInfo;
import android.graphics.Rect;
import android.net.Uri;
-import android.os.Build;
import android.os.Bundle;
import android.os.UserHandle;
import android.text.TextUtils;
@@ -139,48 +137,6 @@
return (info.flags & ApplicationInfo.FLAG_SUSPENDED) != 0;
}
- /**
- * Returns true if {@param srcPackage} has the permission required to start the activity from
- * {@param intent}. If {@param srcPackage} is null, then the activity should not need
- * any permissions
- */
- public boolean hasPermissionForActivity(Intent intent, String srcPackage) {
- ResolveInfo target = mPm.resolveActivity(intent, 0);
- if (target == null) {
- // Not a valid target
- return false;
- }
- if (TextUtils.isEmpty(target.activityInfo.permission)) {
- // No permission is needed
- return true;
- }
- if (TextUtils.isEmpty(srcPackage)) {
- // The activity requires some permission but there is no source.
- return false;
- }
-
- // Source does not have sufficient permissions.
- if(mPm.checkPermission(target.activityInfo.permission, srcPackage) !=
- PackageManager.PERMISSION_GRANTED) {
- return false;
- }
-
- // On M and above also check AppOpsManager for compatibility mode permissions.
- if (TextUtils.isEmpty(AppOpsManager.permissionToOp(target.activityInfo.permission))) {
- // There is no app-op for this permission, which could have been disabled.
- return true;
- }
-
- // There is no direct way to check if the app-op is allowed for a particular app. Since
- // app-op is only enabled for apps running in compatibility mode, simply block such apps.
-
- try {
- return mPm.getApplicationInfo(srcPackage, 0).targetSdkVersion >= Build.VERSION_CODES.M;
- } catch (NameNotFoundException e) { }
-
- return false;
- }
-
public Intent getMarketIntent(String packageName) {
return new Intent(Intent.ACTION_VIEW)
.setData(new Uri.Builder()
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index a6744fb..79d4df0 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -437,9 +437,7 @@
StrictMode.setVmPolicy(oldPolicy);
}
} catch (SecurityException e) {
- if (!onErrorStartingShortcut(intent, info)) {
- throw e;
- }
+ throw e;
}
}
@@ -459,16 +457,6 @@
}
}
- /**
- * Invoked when a shortcut fails to launch.
- * @param intent Shortcut intent that failed to start.
- * @param info Shortcut information.
- * @return {@code true} if the error is handled by this callback.
- */
- default boolean onErrorStartingShortcut(Intent intent, ItemInfo info) {
- return false;
- }
-
default CellPosMapper getCellPosMapper() {
return CellPosMapper.DEFAULT;
}