From 81e44914500c7cc6204d25390f5999fa53559044 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Sat, 14 Jan 2017 15:05:14 -0800 Subject: [PATCH] Fixing loadWorkspace > Adding checks on legacy shortcuts > Checking restore status based on package and not componentName Bug: 34123342 Change-Id: I442699e4ebb34ae66aa25c512bfcdc1b4fd5ae2a --- src/com/android/launcher3/LauncherModel.java | 217 +++++++++--------- .../android/launcher3/LauncherSettings.java | 2 +- .../android/launcher3/model/LoaderCursor.java | 14 ++ .../launcher3/model/LoaderCursorTest.java | 3 +- 4 files changed, 126 insertions(+), 110 deletions(-) diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index 247a295d65..79f9792ac6 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -1144,8 +1144,6 @@ public class LauncherModel extends BroadcastReceiver HashMap widgetProvidersMap = null; try { - final int intentIndex = c.getColumnIndexOrThrow - (LauncherSettings.Favorites.INTENT); final int appWidgetIdIndex = c.getColumnIndexOrThrow( LauncherSettings.Favorites.APPWIDGET_ID); final int appWidgetProviderIndex = c.getColumnIndexOrThrow( @@ -1192,7 +1190,7 @@ public class LauncherModel extends BroadcastReceiver String intentDescription; LauncherAppWidgetInfo appWidgetInfo; Intent intent; - String targetPackage; + String targetPkg; while (!mStopped && c.moveToNext()) { try { @@ -1204,116 +1202,126 @@ public class LauncherModel extends BroadcastReceiver boolean allowMissingTarget = false; switch (c.itemType) { - case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: { - if (!Process.myUserHandle().equals(c.user)) { - c.markDeleted("Legacy shortcuts are only allowed for default user"); - continue; - } - // Follow through. - } + case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT: - intentDescription = c.getString(intentIndex); - int disabledState = 0; - targetPackage = null; + intent = c.parseIntent(); + if (intent == null) { + c.markDeleted("Invalid or null intent"); + continue; + } - try { - intent = Intent.parseUri(intentDescription, 0); - ComponentName cn = intent.getComponent(); - if (cn != null && cn.getPackageName() != null) { - boolean validPkg = launcherApps.isPackageEnabledForProfile( - cn.getPackageName(), c.user); - boolean validComponent = validPkg && - launcherApps.isActivityEnabledForProfile(cn, c.user); - if (validPkg) { - targetPackage = cn.getPackageName(); - } + int disabledState = quietMode.get(c.serialNumber) ? + ShortcutInfo.FLAG_DISABLED_QUIET_USER : 0; + ComponentName cn = intent.getComponent(); + targetPkg = cn == null ? intent.getPackage() : cn.getPackageName(); - if (validComponent) { - // no special handling necessary for this item - c.markRestored(); - if (quietMode.get(c.serialNumber)) { - disabledState = ShortcutInfo.FLAG_DISABLED_QUIET_USER; - } - } else if (validPkg) { - intent = null; - if (c.hasRestoreFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) { - // We allow auto install apps to have their intent - // updated after an install. - intent = manager.getLaunchIntentForPackage( - cn.getPackageName()); - if (intent != null) { - c.updater().put( - LauncherSettings.Favorites.INTENT, - intent.toUri(0)).commit(); - } - } + if (!Process.myUserHandle().equals(c.user)) { + if (c.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) { + c.markDeleted("Legacy shortcuts are only allowed for default user"); + continue; + } else if (c.restoreFlag != 0) { + // Don't restore items for other profiles. + c.markDeleted("Restore from managed profile not supported"); + continue; + } + } + if (TextUtils.isEmpty(targetPkg) && + c.itemType != LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) { + c.markDeleted("Only legacy shortcuts can have null package"); + continue; + } - if (intent == null) { - // The app is installed but the component is no - // longer available. - c.markDeleted("Invalid component removed: " + cn); - continue; - } else { - // no special handling necessary for this item - c.markRestored(); - } - } else if (c.restoreFlag != 0) { - // Package is not yet available but might be - // installed later. - FileLog.d(TAG, "package not yet restored: " + cn); + // If there is no target package, its an implicit intent + // (legacy shortcut) which is always valid + boolean validTarget = TextUtils.isEmpty(targetPkg) || + launcherApps.isPackageEnabledForProfile(targetPkg, c.user); - if (c.hasRestoreFlag(ShortcutInfo.FLAG_RESTORE_STARTED)) { - // Restore has started once. - } else if (installingPkgs.containsKey(cn.getPackageName())) { - // App restore has started. Update the flag - c.restoreFlag |= ShortcutInfo.FLAG_RESTORE_STARTED; + if (cn != null && validTarget) { + // If the apk is present and the shortcut points to a specific + // component. + + // If the component is already present + if (launcherApps.isActivityEnabledForProfile(cn, c.user)) { + // no special handling necessary for this item + c.markRestored(); + } else { + if (c.hasRestoreFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) { + // We allow auto install apps to have their intent + // updated after an install. + intent = manager.getLaunchIntentForPackage(targetPkg); + if (intent != null) { + c.restoreFlag = 0; c.updater().put( - LauncherSettings.Favorites.RESTORED, - c.restoreFlag).commit(); + LauncherSettings.Favorites.INTENT, + intent.toUri(0)).commit(); + cn = intent.getComponent(); } else { - c.markDeleted("Unrestored package removed: " + cn); + c.markDeleted("Unable to find a launch target"); continue; } - } else if (PackageManagerHelper.isAppOnSdcard( - manager, cn.getPackageName())) { - // Package is present but not available. - allowMissingTarget = true; - disabledState = ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE; - } else if (!isSdCardReady) { - // SdCard is not ready yet. Package might get available, - // once it is ready. - Log.d(TAG, "Invalid package: " + cn + " (check again later)"); - pendingPackages.addToList(c.user, cn.getPackageName()); - allowMissingTarget = true; - // Add the icon on the workspace anyway. - } else { - // Do not wait for external media load anymore. - // Log the invalid package, and remove it - c.markDeleted("Invalid package removed: " + cn); + // The app is installed but the component is no + // longer available. + c.markDeleted("Invalid component removed: " + cn); continue; } - } else if (cn == null) { - // For shortcuts with no component, keep them as they are - c.markRestored(); } - } catch (URISyntaxException e) { - c.markDeleted("Invalid uri: " + intentDescription); - continue; + } + // else if cn == null => can't infer much, leave it + // else if !validPkg => could be restored icon or missing sd-card + + if (!TextUtils.isEmpty(targetPkg) && !validTarget) { + // Points to a valid app (superset of cn != null) but the apk + // is not available. + + if (c.restoreFlag != 0) { + // Package is not yet available but might be + // installed later. + FileLog.d(TAG, "package not yet restored: " + targetPkg); + + if (c.hasRestoreFlag(ShortcutInfo.FLAG_RESTORE_STARTED)) { + // Restore has started once. + } else if (installingPkgs.containsKey(targetPkg)) { + // App restore has started. Update the flag + c.restoreFlag |= ShortcutInfo.FLAG_RESTORE_STARTED; + c.updater().commit(); + } else { + c.markDeleted("Unrestored app removed: " + targetPkg); + continue; + } + } else if (PackageManagerHelper.isAppOnSdcard( + manager, targetPkg)) { + // Package is present but not available. + disabledState |= ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE; + // Add the icon on the workspace anyway. + allowMissingTarget = true; + } else if (!isSdCardReady) { + // SdCard is not ready yet. Package might get available, + // once it is ready. + Log.d(TAG, "Missing pkg, will check later: " + targetPkg); + pendingPackages.addToList(c.user, targetPkg); + // Add the icon on the workspace anyway. + allowMissingTarget = true; + } else { + // Do not wait for external media load anymore. + c.markDeleted("Invalid package removed: " + targetPkg); + continue; + } + } + + if (validTarget) { + // The shortcut points to a valid target (either no target + // or something which is ready to be used) + c.markRestored(); } boolean useLowResIcon = !c.isOnWorkspaceOrHotseat() && c.getInt(rankIndex) >= FolderIcon.NUM_ITEMS_IN_PREVIEW; if (c.restoreFlag != 0) { - if (c.user.equals(Process.myUserHandle())) { - info = c.getRestoredItemInfo(intent); - } else { - // Don't restore items for other profiles. - c.markDeleted("Restore from managed profile not supported"); - continue; - } + // Already verified above that user is same as default user + info = c.getRestoredItemInfo(intent); } else if (c.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) { info = c.getAppShortcutInfo( @@ -1343,7 +1351,7 @@ public class LauncherModel extends BroadcastReceiver info = c.loadSimpleShortcut(); // Shortcuts are only available on the primary profile - if (PackageManagerHelper.isAppSuspended(manager, targetPackage)) { + if (PackageManagerHelper.isAppSuspended(manager, targetPkg)) { disabledState |= ShortcutInfo.FLAG_DISABLED_SUSPENDED; } @@ -1375,15 +1383,12 @@ public class LauncherModel extends BroadcastReceiver info.isDisabled |= ShortcutInfo.FLAG_DISABLED_SAFEMODE; } - if (c.restoreFlag != 0) { - ComponentName cn = info.getTargetComponent(); - if (cn != null) { - Integer progress = installingPkgs.get(cn.getPackageName()); - if (progress != null) { - info.setInstallProgress(progress); - } else { - info.status &= ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE; - } + if (c.restoreFlag != 0 && !TextUtils.isEmpty(targetPkg)) { + Integer progress = installingPkgs.get(targetPkg); + if (progress != null) { + info.setInstallProgress(progress); + } else { + info.status &= ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE; } } @@ -1489,11 +1494,7 @@ public class LauncherModel extends BroadcastReceiver } if (appWidgetInfo.hasRestoreFlag( LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG)) { - intentDescription = c.getString(intentIndex); - if (!TextUtils.isEmpty(intentDescription)) { - appWidgetInfo.bindOptions = - Intent.parseUri(intentDescription, 0); - } + appWidgetInfo.bindOptions = c.parseIntent(); } c.applyCommonProperties(appWidgetInfo); diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java index e884393061..e450785c75 100644 --- a/src/com/android/launcher3/LauncherSettings.java +++ b/src/com/android/launcher3/LauncherSettings.java @@ -37,7 +37,7 @@ public class LauncherSettings { public static final String MODIFIED = "modified"; } - static interface BaseLauncherColumns extends ChangeLogColumns { + static public interface BaseLauncherColumns extends ChangeLogColumns { /** * Descriptive name of the gesture that can be displayed to the user. *

Type: TEXT

diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java index 711be37b4c..36f60b94b7 100644 --- a/src/com/android/launcher3/model/LoaderCursor.java +++ b/src/com/android/launcher3/model/LoaderCursor.java @@ -50,6 +50,7 @@ import com.android.launcher3.util.GridOccupancy; import com.android.launcher3.util.LongArrayMap; import com.android.launcher3.util.PackageManagerHelper; +import java.net.URISyntaxException; import java.security.InvalidParameterException; import java.util.ArrayList; @@ -84,6 +85,7 @@ public class LoaderCursor extends CursorWrapper { private final int cellYIndex; private final int profileIdIndex; private final int restoredIndex; + private final int intentIndex; // Properties loaded per iteration public long serialNumber; @@ -114,6 +116,7 @@ public class LoaderCursor extends CursorWrapper { cellYIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY); profileIdIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.PROFILE_ID); restoredIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.RESTORED); + intentIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT); } @Override @@ -131,6 +134,17 @@ public class LoaderCursor extends CursorWrapper { return result; } + public Intent parseIntent() { + String intentDescription = getString(intentIndex); + try { + return TextUtils.isEmpty(intentDescription) ? + null : Intent.parseUri(intentDescription, 0); + } catch (URISyntaxException e) { + Log.e(TAG, "Error parsing Intent"); + return null; + } + } + public ShortcutInfo loadSimpleShortcut() { final ShortcutInfo info = new ShortcutInfo(); // Non-app shortcuts are only supported for current user. diff --git a/tests/src/com/android/launcher3/model/LoaderCursorTest.java b/tests/src/com/android/launcher3/model/LoaderCursorTest.java index b1c34d1070..173c556218 100644 --- a/tests/src/com/android/launcher3/model/LoaderCursorTest.java +++ b/tests/src/com/android/launcher3/model/LoaderCursorTest.java @@ -25,6 +25,7 @@ import org.junit.runner.RunWith; import java.util.ArrayList; import java.util.Arrays; +import static com.android.launcher3.LauncherSettings.BaseLauncherColumns.INTENT; import static com.android.launcher3.LauncherSettings.Favorites.CELLX; import static com.android.launcher3.LauncherSettings.Favorites.CELLY; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER; @@ -73,7 +74,7 @@ public class LoaderCursorTest { mCursor = new MatrixCursor(new String[] { ICON, ICON_PACKAGE, ICON_RESOURCE, TITLE, _ID, CONTAINER, ITEM_TYPE, PROFILE_ID, - SCREEN, CELLX, CELLY, RESTORED + SCREEN, CELLX, CELLY, RESTORED, INTENT }); mContext = InstrumentationRegistry.getTargetContext();