diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java index a94f25d2b2..14ff47b6a9 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java @@ -25,11 +25,13 @@ import android.annotation.TargetApi; import android.content.Context; import android.os.Build; import android.os.SystemClock; +import android.util.Log; import android.view.ViewConfiguration; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.MainThreadExecutor; import com.android.launcher3.logging.UserEventDispatcher; +import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.quickstep.ActivityControlHelper.ActivityInitListener; import com.android.quickstep.views.RecentsView; @@ -162,6 +164,9 @@ public class OverviewCommandHelper { @Override public void run() { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.ALL_APPS_UPON_RECENTS, "RecentsActivityCommand.run"); + } long elapsedTime = mCreateTime - mLastToggleTime; mLastToggleTime = mCreateTime; diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java index 13a8dc26aa..bf3cd8afe2 100644 --- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java +++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java @@ -16,11 +16,6 @@ package com.android.quickstep.logging; -import android.content.Context; -import android.content.Intent; -import android.stats.launcher.nano.LauncherExtension; -import android.stats.launcher.nano.LauncherTarget; - import static android.stats.launcher.nano.Launcher.ALLAPPS; import static android.stats.launcher.nano.Launcher.HOME; import static android.stats.launcher.nano.Launcher.LAUNCH_APP; @@ -29,6 +24,11 @@ import static android.stats.launcher.nano.Launcher.DISMISS_TASK; import static android.stats.launcher.nano.Launcher.BACKGROUND; import static android.stats.launcher.nano.Launcher.OVERVIEW; +import android.content.Context; +import android.content.Intent; +import android.stats.launcher.nano.Launcher; +import android.stats.launcher.nano.LauncherExtension; +import android.stats.launcher.nano.LauncherTarget; import android.view.View; import com.android.launcher3.ItemInfo; @@ -39,8 +39,6 @@ import com.android.launcher3.util.ComponentKey; import com.android.systemui.shared.system.StatsLogCompat; import com.google.protobuf.nano.MessageNano; -import androidx.annotation.Nullable; - /** * This method calls the StatsLog hidden method until they are made available public. * @@ -85,6 +83,17 @@ public class StatsLogCompatManager extends StatsLogManager { MessageNano.toByteArray(ext), true); } + @Override + public void logSwipeOnContainer(boolean isSwipingToLeft, int pageId) { + LauncherExtension ext = new LauncherExtension(); + ext.srcTarget = new LauncherTarget[1]; + int srcState = mStateProvider.getCurrentState(); + fillInLauncherExtensionWithPageId(ext, pageId); + int launcherAction = isSwipingToLeft ? Launcher.SWIPE_LEFT : Launcher.SWIPE_RIGHT; + StatsLogCompat.write(launcherAction, srcState, srcState, + MessageNano.toByteArray(ext), true); + } + public static boolean fillInLauncherExtension(View v, LauncherExtension extension) { StatsLogUtils.LogContainerProvider provider = StatsLogUtils.getLaunchProviderRecursive(v); if (v == null || !(v.getTag() instanceof ItemInfo) || provider == null) { @@ -99,6 +108,13 @@ public class StatsLogCompatManager extends StatsLogManager { return true; } + public static boolean fillInLauncherExtensionWithPageId(LauncherExtension ext, int pageId) { + Target target = new Target(); + target.pageIndex = pageId; + copy(target, ext.srcTarget[0]); + return true; + } + private static void copy(Target src, LauncherTarget dst) { // fill in } diff --git a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java index f27f400884..edd5011f23 100644 --- a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java +++ b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java @@ -34,9 +34,9 @@ import androidx.test.uiautomator.UiDevice; import com.android.launcher3.tapl.LauncherInstrumentation; import com.android.launcher3.tapl.TestHelpers; +import com.android.launcher3.util.rule.FailureWatcher; import com.android.systemui.shared.system.QuickStepContract; -import org.junit.Assert; import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.Statement; @@ -79,6 +79,14 @@ public class NavigationModeSwitchRule implements TestRule { description.getAnnotation(NavigationModeSwitch.class) != null) { Mode mode = description.getAnnotation(NavigationModeSwitch.class).mode(); return new Statement() { + private void assertTrue(String message, boolean condition) { + if(!condition) { + final AssertionError assertionError = new AssertionError(message); + FailureWatcher.onError(mLauncher.getDevice(), description, assertionError); + throw assertionError; + } + } + @Override public void evaluate() throws Throwable { mLauncher.enableDebugTracing(); @@ -107,7 +115,8 @@ public class NavigationModeSwitchRule implements TestRule { Log.e(TAG, "Exception", e); throw e; } finally { - Assert.assertTrue(setActiveOverlay(prevOverlayPkg, originalMode)); + assertTrue("Couldn't set overlay", + setActiveOverlay(prevOverlayPkg, originalMode)); } mLauncher.disableDebugTracing(); } @@ -176,7 +185,7 @@ public class NavigationModeSwitchRule implements TestRule { latch.await(10, TimeUnit.SECONDS); targetContext.getMainExecutor().execute(() -> sysUINavigationMode.removeModeChangeListener(listener)); - Assert.assertTrue("Navigation mode didn't change to " + expectedMode, + assertTrue("Navigation mode didn't change to " + expectedMode, currentSysUiNavigationMode() == expectedMode); } @@ -184,7 +193,7 @@ public class NavigationModeSwitchRule implements TestRule { if (mLauncher.getNavigationModel() == expectedMode) break; Thread.sleep(100); } - Assert.assertTrue("Couldn't switch to " + overlayPackage, + assertTrue("Couldn't switch to " + overlayPackage, mLauncher.getNavigationModel() == expectedMode); for (int i = 0; i != 100; ++i) { @@ -192,7 +201,7 @@ public class NavigationModeSwitchRule implements TestRule { Thread.sleep(100); } final String error = mLauncher.getNavigationModeMismatchError(); - Assert.assertTrue("Switching nav mode: " + error, error == null); + assertTrue("Switching nav mode: " + error, error == null); Thread.sleep(5000); return true; diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java index 885fdbf423..be8506d83e 100644 --- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java +++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java @@ -97,6 +97,7 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest { @Test @PortraitLandscape public void testOverview() throws Exception { + mLauncher.enableDebugTracing(); startTestApps(); Overview overview = mLauncher.pressHome().switchToOverview(); assertTrue("Launcher internal state didn't switch to Overview", @@ -176,6 +177,7 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest { executeOnLauncher( launcher -> assertEquals("Still have tasks after dismissing all", 0, getTaskCount(launcher))); + mLauncher.disableDebugTracing(); } private int getCurrentOverviewPage(Launcher launcher) { diff --git a/robolectric_tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java b/robolectric_tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java index e9324f9ce2..42a4f5cc99 100644 --- a/robolectric_tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java +++ b/robolectric_tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java @@ -29,7 +29,8 @@ public class PackageInstallStateChangedTaskTest extends BaseModelUpdateTaskTestC private PackageInstallStateChangedTask newTask(String pkg, int progress) { int state = PackageInstallerCompat.STATUS_INSTALLING; - PackageInstallInfo installInfo = new PackageInstallInfo(pkg, state, progress); + PackageInstallInfo installInfo = new PackageInstallInfo(pkg, state, progress, + android.os.Process.myUserHandle()); return new PackageInstallStateChangedTask(installInfo); } diff --git a/src/com/android/launcher3/AllAppsList.java b/src/com/android/launcher3/AllAppsList.java index 733f29540f..8b49c06389 100644 --- a/src/com/android/launcher3/AllAppsList.java +++ b/src/com/android/launcher3/AllAppsList.java @@ -89,7 +89,7 @@ public class AllAppsList { public void addPromiseApp(Context context, PackageInstallerCompat.PackageInstallInfo installInfo) { ApplicationInfo applicationInfo = LauncherAppsCompat.getInstance(context) - .getApplicationInfo(installInfo.packageName, 0, Process.myUserHandle()); + .getApplicationInfo(installInfo.packageName, 0, installInfo.user); // only if not yet installed if (applicationInfo == null) { PromiseAppInfo info = new PromiseAppInfo(installInfo); diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java index e9b932aaf5..670cd2877d 100644 --- a/src/com/android/launcher3/InstallShortcutReceiver.java +++ b/src/com/android/launcher3/InstallShortcutReceiver.java @@ -19,6 +19,7 @@ package com.android.launcher3; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProviderInfo; import android.content.BroadcastReceiver; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; @@ -29,7 +30,6 @@ import android.content.pm.ShortcutInfo; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Handler; -import android.os.Looper; import android.os.Message; import android.os.Parcelable; import android.os.Process; @@ -141,7 +141,8 @@ public class InstallShortcutReceiver extends BroadcastReceiver { String pkg = getIntentPackage(info.launchIntent); if (!TextUtils.isEmpty(pkg) - && !launcherApps.isPackageEnabledForProfile(pkg, info.user)) { + && !launcherApps.isPackageEnabledForProfile(pkg, info.user) + && !info.isActivity) { if (DBG) Log.d(TAG, "Ignoring shortcut for absent package: " + info.launchIntent); continue; @@ -250,7 +251,8 @@ public class InstallShortcutReceiver extends BroadcastReceiver { } public static WorkspaceItemInfo fromActivityInfo(LauncherActivityInfo info, Context context) { - return (WorkspaceItemInfo) (new PendingInstallShortcutInfo(info, context).getItemInfo().first); + return (WorkspaceItemInfo) + new PendingInstallShortcutInfo(info, context).getItemInfo().first; } public static void queueShortcut(ShortcutInfo info, Context context) { @@ -261,8 +263,9 @@ public class InstallShortcutReceiver extends BroadcastReceiver { queuePendingShortcutInfo(new PendingInstallShortcutInfo(info, widgetId, context), context); } - public static void queueActivityInfo(LauncherActivityInfo activity, Context context) { - queuePendingShortcutInfo(new PendingInstallShortcutInfo(activity, context), context); + public static void queueApplication(Intent data, UserHandle user, Context context) { + queuePendingShortcutInfo(new PendingInstallShortcutInfo(data, context, user), + context); } public static HashSet getPendingShortcuts(Context context) { @@ -326,7 +329,7 @@ public class InstallShortcutReceiver extends BroadcastReceiver { private static class PendingInstallShortcutInfo { - final LauncherActivityInfo activityInfo; + final boolean isActivity; final ShortcutInfo shortcutInfo; final AppWidgetProviderInfo providerInfo; @@ -340,7 +343,7 @@ public class InstallShortcutReceiver extends BroadcastReceiver { * Initializes a PendingInstallShortcutInfo received from a different app. */ public PendingInstallShortcutInfo(Intent data, UserHandle user, Context context) { - activityInfo = null; + isActivity = false; shortcutInfo = null; providerInfo = null; @@ -350,14 +353,13 @@ public class InstallShortcutReceiver extends BroadcastReceiver { launchIntent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT); label = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME); - } /** * Initializes a PendingInstallShortcutInfo to represent a launcher target. */ public PendingInstallShortcutInfo(LauncherActivityInfo info, Context context) { - activityInfo = info; + isActivity = true; shortcutInfo = null; providerInfo = null; @@ -369,11 +371,27 @@ public class InstallShortcutReceiver extends BroadcastReceiver { label = info.getLabel().toString(); } + /** + * Initializes a PendingInstallShortcutInfo to represent a launcher target. + */ + public PendingInstallShortcutInfo(Intent data, Context context, UserHandle user) { + isActivity = true; + shortcutInfo = null; + providerInfo = null; + + this.data = data; + this.user = user; + mContext = context; + + launchIntent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT); + label = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME); + } + /** * Initializes a PendingInstallShortcutInfo to represent a launcher target. */ public PendingInstallShortcutInfo(ShortcutInfo info, Context context) { - activityInfo = null; + isActivity = false; shortcutInfo = info; providerInfo = null; @@ -390,7 +408,7 @@ public class InstallShortcutReceiver extends BroadcastReceiver { */ public PendingInstallShortcutInfo( AppWidgetProviderInfo info, int widgetId, Context context) { - activityInfo = null; + isActivity = false; shortcutInfo = null; providerInfo = info; @@ -405,17 +423,7 @@ public class InstallShortcutReceiver extends BroadcastReceiver { public String encodeToString() { try { - if (activityInfo != null) { - // 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(); - } else if (shortcutInfo != null) { + if (shortcutInfo != null) { // If it a launcher target, we only need component name, and user to // recreate this. return new JSONStringer() @@ -457,7 +465,8 @@ public class InstallShortcutReceiver extends BroadcastReceiver { JSONStringer json = new JSONStringer() .object() .key(LAUNCH_INTENT_KEY).value(launchIntent.toUri(0)) - .key(NAME_KEY).value(name); + .key(NAME_KEY).value(name) + .key(APP_SHORTCUT_TYPE_KEY).value(isActivity); if (icon != null) { byte[] iconByteArray = GraphicsUtils.flattenBitmap(icon); json = json.key(ICON_KEY).value( @@ -477,29 +486,18 @@ public class InstallShortcutReceiver extends BroadcastReceiver { } public Pair getItemInfo() { - if (activityInfo != null) { - AppInfo appInfo = new AppInfo(mContext, activityInfo, user); - final LauncherAppState app = LauncherAppState.getInstance(mContext); - // Set default values until proper values is loaded. - appInfo.title = ""; - appInfo.applyFrom(app.getIconCache().getDefaultIcon(user)); - final WorkspaceItemInfo si = appInfo.makeWorkspaceItem(); - if (Looper.myLooper() == LauncherModel.getWorkerLooper()) { - app.getIconCache().getTitleAndIcon(si, activityInfo, false /* useLowResIcon */); - } else { - app.getModel().updateAndBindWorkspaceItem(() -> { - app.getIconCache().getTitleAndIcon( - si, activityInfo, false /* useLowResIcon */); - return si; - }); - } - return Pair.create((ItemInfo) si, (Object) activityInfo); + if (isActivity) { + WorkspaceItemInfo si = createWorkspaceItemInfo(data, + LauncherAppState.getInstance(mContext)); + si.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; + si.status |= WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON; + return Pair.create(si, null); } else if (shortcutInfo != null) { - WorkspaceItemInfo si = new WorkspaceItemInfo(shortcutInfo, mContext); + WorkspaceItemInfo itemInfo = new WorkspaceItemInfo(shortcutInfo, mContext); LauncherIcons li = LauncherIcons.obtain(mContext); - si.applyFrom(li.createShortcutIcon(shortcutInfo)); + itemInfo.applyFrom(li.createShortcutIcon(shortcutInfo)); li.recycle(); - return Pair.create((ItemInfo) si, (Object) shortcutInfo); + return Pair.create(itemInfo, shortcutInfo); } else if (providerInfo != null) { LauncherAppWidgetProviderInfo info = LauncherAppWidgetProviderInfo .fromProviderInfo(mContext, providerInfo); @@ -511,15 +509,16 @@ public class InstallShortcutReceiver extends BroadcastReceiver { widgetInfo.minSpanY = info.minSpanY; widgetInfo.spanX = Math.min(info.spanX, idp.numColumns); widgetInfo.spanY = Math.min(info.spanY, idp.numRows); - return Pair.create((ItemInfo) widgetInfo, (Object) providerInfo); + return Pair.create(widgetInfo, providerInfo); } else { - WorkspaceItemInfo si = createWorkspaceItemInfo(data, LauncherAppState.getInstance(mContext)); - return Pair.create((ItemInfo) si, null); + WorkspaceItemInfo itemInfo = + createWorkspaceItemInfo(data, LauncherAppState.getInstance(mContext)); + return Pair.create(itemInfo, null); } } public boolean isLauncherActivity() { - return activityInfo != null; + return isActivity; } } @@ -534,7 +533,9 @@ public class InstallShortcutReceiver extends BroadcastReceiver { if (decoder.optBoolean(APP_SHORTCUT_TYPE_KEY)) { LauncherActivityInfo info = LauncherAppsCompat.getInstance(context) .resolveActivity(decoder.launcherIntent, decoder.user); - return info == null ? null : new PendingInstallShortcutInfo(info, context); + if (info != null) { + return new PendingInstallShortcutInfo(info, context); + } } else if (decoder.optBoolean(DEEPSHORTCUT_TYPE_KEY)) { DeepShortcutManager sm = DeepShortcutManager.getInstance(context); List si = sm.queryForFullDetails( @@ -578,7 +579,11 @@ public class InstallShortcutReceiver extends BroadcastReceiver { data.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, iconResource); } - return new PendingInstallShortcutInfo(data, decoder.user, context); + if (decoder.optBoolean(APP_SHORTCUT_TYPE_KEY)) { + return new PendingInstallShortcutInfo(data, context, decoder.user); + } else { + return new PendingInstallShortcutInfo(data, decoder.user, context); + } } catch (JSONException | URISyntaxException e) { Log.d(TAG, "Exception reading shortcut to add: " + e); } diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java index d66e5813b9..e1ea3be04e 100644 --- a/src/com/android/launcher3/LauncherStateManager.java +++ b/src/com/android/launcher3/LauncherStateManager.java @@ -227,6 +227,10 @@ public class LauncherStateManager { private void goToState(LauncherState state, boolean animated, long delay, final Runnable onCompleteRunnable) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.ALL_APPS_UPON_RECENTS, "goToState: " + state + " @ " + + Log.getStackTraceString(new Throwable())); + } animated &= Utilities.areAnimationsEnabled(mLauncher); if (mLauncher.isInState(state)) { if (mConfig.mCurrentAnimation == null) { @@ -426,6 +430,9 @@ public class LauncherStateManager { if (state != mCurrentStableState) { mLastStableState = state.getHistoryForState(mCurrentStableState); mCurrentStableState = state; + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.ALL_APPS_UPON_RECENTS, "onStateTransitionEnd: " + state); + } } state.onStateTransitionEnd(mLauncher); diff --git a/src/com/android/launcher3/SessionCommitReceiver.java b/src/com/android/launcher3/SessionCommitReceiver.java index b0da6b9cd9..b4078ee0ea 100644 --- a/src/com/android/launcher3/SessionCommitReceiver.java +++ b/src/com/android/launcher3/SessionCommitReceiver.java @@ -18,28 +18,33 @@ package com.android.launcher3; import android.annotation.TargetApi; import android.content.BroadcastReceiver; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; +import android.content.pm.ApplicationInfo; import android.content.pm.LauncherActivityInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller.SessionInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.database.Cursor; +import android.graphics.Bitmap; import android.net.Uri; import android.os.AsyncTask; import android.os.Build; -import android.os.Process; import android.os.UserHandle; import android.provider.Settings; import android.text.TextUtils; import android.util.Log; import com.android.launcher3.compat.LauncherAppsCompat; +import com.android.launcher3.compat.PackageInstallerCompat; import java.util.List; +import static com.android.launcher3.compat.PackageInstallerCompat.getUserHandle; + /** * BroadcastReceiver to handle session commit intent. */ @@ -66,15 +71,29 @@ public class SessionCommitReceiver extends BroadcastReceiver { SessionInfo info = intent.getParcelableExtra(PackageInstaller.EXTRA_SESSION); UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER); + PackageInstallerCompat packageInstallerCompat = PackageInstallerCompat.getInstance(context); - if (TextUtils.isEmpty(info.getAppPackageName()) || - info.getInstallReason() != PackageManager.INSTALL_REASON_USER) { + if (TextUtils.isEmpty(info.getAppPackageName()) + || info.getInstallReason() != PackageManager.INSTALL_REASON_USER + || packageInstallerCompat.promiseIconAddedForId(info.getSessionId())) { + packageInstallerCompat.removePromiseIconId(info.getSessionId()); return; } queueAppIconAddition(context, info.getAppPackageName(), user); } + public static void queuePromiseAppIconAddition(Context context, SessionInfo sessionInfo) { + String packageName = sessionInfo.getAppPackageName(); + List activities = LauncherAppsCompat.getInstance(context) + .getActivityList(packageName, getUserHandle(sessionInfo)); + if (activities == null || activities.isEmpty()) { + // Ensure application isn't already installed. + queueAppIconAddition(context, packageName, sessionInfo.getAppLabel(), + sessionInfo.getAppIcon(), getUserHandle(sessionInfo)); + } + } + public static void queueAppIconAddition(Context context, String packageName, UserHandle user) { List activities = LauncherAppsCompat.getInstance(context) .getActivityList(packageName, user); @@ -82,7 +101,18 @@ public class SessionCommitReceiver extends BroadcastReceiver { // no activity found return; } - InstallShortcutReceiver.queueActivityInfo(activities.get(0), context); + queueAppIconAddition(context, packageName, activities.get(0).getLabel(), null, user); + } + + private static void queueAppIconAddition(Context context, String packageName, + CharSequence label, Bitmap icon, UserHandle user) { + Intent data = new Intent(); + data.putExtra(Intent.EXTRA_SHORTCUT_INTENT, new Intent().setComponent( + new ComponentName(packageName, "")).setPackage(packageName)); + data.putExtra(Intent.EXTRA_SHORTCUT_NAME, label); + data.putExtra(Intent.EXTRA_SHORTCUT_ICON, icon); + + InstallShortcutReceiver.queueApplication(data, user, context); } public static boolean isEnabled(Context context) { diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 3be91d4108..6612662ea5 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -1052,6 +1052,7 @@ public class Workspace extends PagedView if (!mOverlayShown) { mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.SWIPE, Action.Direction.LEFT, ContainerType.WORKSPACE, 0); + mLauncher.getStatsLogManager().logSwipeOnContainer(true, 0); } mOverlayShown = true; // Not announcing the overlay page for accessibility since it announces itself. @@ -1061,6 +1062,7 @@ public class Workspace extends PagedView if (!ued.isPreviousHomeGesture()) { mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.SWIPE, Action.Direction.RIGHT, ContainerType.WORKSPACE, -1); + mLauncher.getStatsLogManager().logSwipeOnContainer(false, -1); } } else if (Float.compare(mOverlayTranslation, 0f) != 0) { // When arriving to 0 overscroll from non-zero overscroll, announce page for diff --git a/src/com/android/launcher3/WorkspaceItemInfo.java b/src/com/android/launcher3/WorkspaceItemInfo.java index b72866c266..050a8bef75 100644 --- a/src/com/android/launcher3/WorkspaceItemInfo.java +++ b/src/com/android/launcher3/WorkspaceItemInfo.java @@ -50,24 +50,26 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { * The icon was added as an auto-install app, and is not ready to be used. This flag can't * be present along with {@link #FLAG_RESTORED_ICON}, and is set during default layout * parsing. + * + * OR this icon was added due to it being an active install session created by the user. */ - public static final int FLAG_AUTOINSTALL_ICON = 2; //0B10; + public static final int FLAG_AUTOINSTALL_ICON = 1 << 1; /** * The icon is being installed. If {@link #FLAG_RESTORED_ICON} or {@link #FLAG_AUTOINSTALL_ICON} * is set, then the icon is either being installed or is in a broken state. */ - public static final int FLAG_INSTALL_SESSION_ACTIVE = 4; // 0B100; + public static final int FLAG_INSTALL_SESSION_ACTIVE = 1 << 2; /** * Indicates that the widget restore has started. */ - public static final int FLAG_RESTORE_STARTED = 8; //0B1000; + public static final int FLAG_RESTORE_STARTED = 1 << 3; /** * Web UI supported. */ - public static final int FLAG_SUPPORTS_WEB_UI = 16; //0B10000; + public static final int FLAG_SUPPORTS_WEB_UI = 1 << 4; /** * The intent used to start the application. @@ -210,7 +212,7 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { public ComponentName getTargetComponent() { ComponentName cn = super.getTargetComponent(); if (cn == null && (itemType == Favorites.ITEM_TYPE_SHORTCUT - || hasStatusFlag(FLAG_SUPPORTS_WEB_UI))) { + || hasStatusFlag(FLAG_SUPPORTS_WEB_UI | FLAG_AUTOINSTALL_ICON))) { // Legacy shortcuts and promise icons with web UI may not have a componentName but just // a packageName. In that case create a dummy componentName instead of adding additional // check everywhere. diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java index 4a2109e588..293b86722d 100644 --- a/src/com/android/launcher3/allapps/AllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java @@ -628,20 +628,4 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo return super.performAccessibilityAction(action, arguments); } - - @Override - public boolean dispatchTouchEvent(MotionEvent ev) { - final boolean result = super.dispatchTouchEvent(ev); - switch (ev.getActionMasked()) { - case MotionEvent.ACTION_DOWN: - if (result) mAllAppsStore.enableDeferUpdates( - AllAppsStore.DEFER_UPDATES_USER_INTERACTION); - break; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - mAllAppsStore.disableDeferUpdates(AllAppsStore.DEFER_UPDATES_USER_INTERACTION); - break; - } - return result; - } } diff --git a/src/com/android/launcher3/allapps/AllAppsStore.java b/src/com/android/launcher3/allapps/AllAppsStore.java index 267363fa7d..ca8dbebfc2 100644 --- a/src/com/android/launcher3/allapps/AllAppsStore.java +++ b/src/com/android/launcher3/allapps/AllAppsStore.java @@ -39,10 +39,8 @@ public class AllAppsStore { // Defer updates flag used to defer all apps updates to the next draw. public static final int DEFER_UPDATES_NEXT_DRAW = 1 << 0; - // Defer updates flag used to defer all apps updates while the user interacts with all apps. - public static final int DEFER_UPDATES_USER_INTERACTION = 1 << 1; // Defer updates flag used to defer all apps updates by a test's request. - public static final int DEFER_UPDATES_TEST = 1 << 2; + public static final int DEFER_UPDATES_TEST = 1 << 1; private PackageUserKey mTempKey = new PackageUserKey(null, null); private final HashMap mComponentToAppMap = new HashMap<>(); diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java index 1d19b533a0..1885d8f03d 100644 --- a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java +++ b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java @@ -31,11 +31,14 @@ import android.os.Bundle; import android.os.Process; import android.os.UserHandle; import android.util.ArrayMap; +import android.util.Log; import com.android.launcher3.compat.ShortcutConfigActivityInfo.ShortcutConfigActivityInfoVL; +import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.util.PackageUserKey; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import androidx.annotation.NonNull; @@ -167,6 +170,10 @@ public class LauncherAppsCompatVL extends LauncherAppsCompat { @Override public void onPackagesSuspended(String[] packageNames, UserHandle user) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.APP_NOT_DISABLED, "onPackagesSuspended: " + + Arrays.toString(packageNames)); + } mCallback.onPackagesSuspended(packageNames, user); } diff --git a/src/com/android/launcher3/compat/PackageInstallerCompat.java b/src/com/android/launcher3/compat/PackageInstallerCompat.java index 4f4d64161a..11cb1f88d0 100644 --- a/src/com/android/launcher3/compat/PackageInstallerCompat.java +++ b/src/com/android/launcher3/compat/PackageInstallerCompat.java @@ -19,15 +19,23 @@ package com.android.launcher3.compat; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageInstaller; +import android.os.Process; import android.os.UserHandle; +import java.util.Collections; import java.util.HashMap; import java.util.List; import androidx.annotation.NonNull; +import com.android.launcher3.Utilities; + public abstract class PackageInstallerCompat { + // Set of session ids of promise icons that have been added to the home screen + // as FLAG_PROMISE_NEW_INSTALLS. + protected static final String PROMISE_ICON_IDS = "promise_icon_ids"; + public static final int STATUS_INSTALLED = 0; public static final int STATUS_INSTALLING = 1; public static final int STATUS_FAILED = 2; @@ -44,6 +52,10 @@ public abstract class PackageInstallerCompat { } } + public static UserHandle getUserHandle(PackageInstaller.SessionInfo info) { + return Utilities.ATLEAST_Q ? info.getUser() : Process.myUserHandle(); + } + /** * @return a map of active installs to their progress */ @@ -61,30 +73,44 @@ public abstract class PackageInstallerCompat { public final String packageName; public final int state; public final int progress; + public final UserHandle user; private PackageInstallInfo(@NonNull PackageInstaller.SessionInfo info) { this.state = STATUS_INSTALLING; this.packageName = info.getAppPackageName(); this.componentName = new ComponentName(packageName, ""); this.progress = (int) (info.getProgress() * 100f); + this.user = getUserHandle(info); } - public PackageInstallInfo(String packageName, int state, int progress) { + public PackageInstallInfo(String packageName, int state, int progress, UserHandle user) { this.state = state; this.packageName = packageName; this.componentName = new ComponentName(packageName, ""); this.progress = progress; + this.user = user; } public static PackageInstallInfo fromInstallingState(PackageInstaller.SessionInfo info) { return new PackageInstallInfo(info); } - public static PackageInstallInfo fromState(int state, String packageName) { - return new PackageInstallInfo(packageName, state, 0 /* progress */); + public static PackageInstallInfo fromState(int state, String packageName, UserHandle user) { + return new PackageInstallInfo(packageName, state, 0 /* progress */, user); } } public abstract List getAllVerifiedSessions(); + + /** + * Returns true if a promise icon was already added to the home screen for {@param sessionId}. + * Applicable only for icons with flag FLAG_PROMISE_NEW_INSTALLS. + */ + public abstract boolean promiseIconAddedForId(int sessionId); + + /** + * Applicable only for icons with flag FLAG_PROMISE_NEW_INSTALLS. + */ + public abstract void removePromiseIconId(int sessionId); } diff --git a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java index 8a5eabca99..e1f17cf461 100644 --- a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java +++ b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java @@ -21,17 +21,21 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller.SessionCallback; import android.content.pm.PackageInstaller.SessionInfo; +import android.content.pm.PackageManager; import android.os.Handler; -import android.os.Process; import android.os.UserHandle; import android.text.TextUtils; import android.util.SparseArray; +import com.android.launcher3.SessionCommitReceiver; import com.android.launcher3.Utilities; import com.android.launcher3.icons.IconCache; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherModel; import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.util.IntArray; +import com.android.launcher3.util.IntSet; +import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.util.Thunk; import java.util.ArrayList; @@ -39,11 +43,13 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; +import static com.android.launcher3.Utilities.getPrefs; + public class PackageInstallerCompatVL extends PackageInstallerCompat { private static final boolean DEBUG = false; - @Thunk final SparseArray mActiveSessions = new SparseArray<>(); + @Thunk final SparseArray mActiveSessions = new SparseArray<>(); @Thunk final PackageInstaller mInstaller; private final IconCache mCache; @@ -51,6 +57,7 @@ public class PackageInstallerCompatVL extends PackageInstallerCompat { private final Context mAppContext; private final HashMap mSessionVerifiedMap = new HashMap<>(); private final LauncherAppsCompat mLauncherApps; + private final IntSet mPromiseIconIds; PackageInstallerCompatVL(Context context) { mAppContext = context.getApplicationContext(); @@ -59,17 +66,38 @@ public class PackageInstallerCompatVL extends PackageInstallerCompat { mWorker = new Handler(LauncherModel.getWorkerLooper()); mInstaller.registerSessionCallback(mCallback, mWorker); mLauncherApps = LauncherAppsCompat.getInstance(context); + mPromiseIconIds = IntSet.wrap(IntArray.wrap(Utilities.getIntArrayFromString( + getPrefs(context).getString(PROMISE_ICON_IDS, "")))); + + cleanUpPromiseIconIds(); + } + + private void cleanUpPromiseIconIds() { + IntArray existingIds = new IntArray(); + for (SessionInfo info : updateAndGetActiveSessionCache().values()) { + existingIds.add(info.getSessionId()); + } + IntArray idsToRemove = new IntArray(); + + for (int i = mPromiseIconIds.size() - 1; i >= 0; --i) { + if (!existingIds.contains(mPromiseIconIds.getArray().get(i))) { + idsToRemove.add(mPromiseIconIds.getArray().get(i)); + } + } + for (int i = idsToRemove.size() - 1; i >= 0; --i) { + mPromiseIconIds.getArray().removeValue(idsToRemove.get(i)); + } } @Override public HashMap updateAndGetActiveSessionCache() { HashMap activePackages = new HashMap<>(); - UserHandle primaryUser = Process.myUserHandle(); for (SessionInfo info : getAllVerifiedSessions()) { - addSessionInfoToCache(info, Utilities.ATLEAST_Q ? info.getUser() : primaryUser); + addSessionInfoToCache(info, getUserHandle(info)); if (info.getAppPackageName() != null) { activePackages.put(info.getAppPackageName(), info); - mActiveSessions.put(info.getSessionId(), info.getAppPackageName()); + mActiveSessions.put(info.getSessionId(), + new PackageUserKey(info.getAppPackageName(), getUserHandle(info))); } } return activePackages; @@ -78,7 +106,7 @@ public class PackageInstallerCompatVL extends PackageInstallerCompat { public SessionInfo getActiveSessionInfo(UserHandle user, String pkg) { for (SessionInfo info : getAllVerifiedSessions()) { boolean match = pkg.equals(info.getAppPackageName()); - if (Utilities.ATLEAST_Q && !user.equals(info.getUser())) { + if (Utilities.ATLEAST_Q && !user.equals(getUserHandle(info))) { match = false; } if (match) { @@ -120,19 +148,38 @@ public class PackageInstallerCompatVL extends PackageInstallerCompat { PackageInstallInfo.fromInstallingState(sessionInfo)); } } + + if (Utilities.ATLEAST_OREO && FeatureFlags.PROMISE_APPS_NEW_INSTALLS.get() + && SessionCommitReceiver.isEnabled(mAppContext) + && sessionInfo != null + && sessionInfo.getInstallReason() == PackageManager.INSTALL_REASON_USER) { + SessionCommitReceiver.queuePromiseAppIconAddition(mAppContext, sessionInfo); + if (!mPromiseIconIds.contains(sessionInfo.getSessionId())) { + mPromiseIconIds.add(sessionInfo.getSessionId()); + updatePromiseIconPrefs(); + } + } } @Override public void onFinished(int sessionId, boolean success) { // For a finished session, we can't get the session info. So use the // packageName from our local cache. - String packageName = mActiveSessions.get(sessionId); + PackageUserKey key = mActiveSessions.get(sessionId); mActiveSessions.remove(sessionId); - if (packageName != null) { - sendUpdate(PackageInstallInfo.fromState( - success ? STATUS_INSTALLED : STATUS_FAILED, - packageName)); + if (key != null && key.mPackageName != null) { + String packageName = key.mPackageName; + sendUpdate(PackageInstallInfo.fromState(success ? STATUS_INSTALLED : STATUS_FAILED, + packageName, key.mUser)); + + if (!success && FeatureFlags.PROMISE_APPS_NEW_INSTALLS.get()) { + LauncherAppState appState = LauncherAppState.getInstanceNoCreate(); + if (appState != null) { + LauncherModel model = appState.getModel(); + model.onPackageRemoved(packageName, key.mUser); + } + } } } @@ -155,8 +202,9 @@ public class PackageInstallerCompatVL extends PackageInstallerCompat { private SessionInfo pushSessionDisplayToLauncher(int sessionId) { SessionInfo session = verify(mInstaller.getSessionInfo(sessionId)); if (session != null && session.getAppPackageName() != null) { - mActiveSessions.put(sessionId, session.getAppPackageName()); - addSessionInfoToCache(session, Process.myUserHandle()); + mActiveSessions.put(session.getSessionId(), + new PackageUserKey(session.getAppPackageName(), getUserHandle(session))); + addSessionInfoToCache(session, getUserHandle(session)); LauncherAppState app = LauncherAppState.getInstanceNoCreate(); if (app != null) { app.getModel().updateSessionDisplayInfo(session.getAppPackageName()); @@ -178,7 +226,7 @@ public class PackageInstallerCompatVL extends PackageInstallerCompat { if (!mSessionVerifiedMap.containsKey(pkg)) { LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mAppContext); boolean hasSystemFlag = launcherApps.getApplicationInfo(pkg, - ApplicationInfo.FLAG_SYSTEM, Process.myUserHandle()) != null; + ApplicationInfo.FLAG_SYSTEM, getUserHandle(sessionInfo)) != null; mSessionVerifiedMap.put(pkg, DEBUG || hasSystemFlag); } } @@ -198,4 +246,23 @@ public class PackageInstallerCompatVL extends PackageInstallerCompat { } return list; } + + @Override + public boolean promiseIconAddedForId(int sessionId) { + return mPromiseIconIds.contains(sessionId); + } + + @Override + public void removePromiseIconId(int sessionId) { + if (mPromiseIconIds.contains(sessionId)) { + mPromiseIconIds.getArray().removeValue(sessionId); + updatePromiseIconPrefs(); + } + } + + private void updatePromiseIconPrefs() { + getPrefs(mAppContext).edit() + .putString(PROMISE_ICON_IDS, mPromiseIconIds.getArray().toConcatString()) + .apply(); + } } diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java index 23edcd25f8..ea6261a6a6 100644 --- a/src/com/android/launcher3/config/BaseFlags.java +++ b/src/com/android/launcher3/config/BaseFlags.java @@ -60,6 +60,11 @@ public abstract class BaseFlags { // When enabled the promise icon is visible in all apps while installation an app. public static final boolean LAUNCHER3_PROMISE_APPS_IN_ALL_APPS = false; + // When enabled a promise icon is added to the home screen when install session is active. + public static final TogglableFlag PROMISE_APPS_NEW_INSTALLS = + new TogglableFlag("PROMISE_APPS_NEW_INSTALLS", true, + "Adds a promise icon to the home screen for new install sessions."); + // Enable moving the QSB on the 0th screen of the workspace public static final boolean QSB_ON_FIRST_SCREEN = true; diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java index d11d434df1..cad95b0d24 100644 --- a/src/com/android/launcher3/logging/StatsLogManager.java +++ b/src/com/android/launcher3/logging/StatsLogManager.java @@ -41,5 +41,6 @@ public class StatsLogManager implements ResourceBasedOverride { public void logAppLaunch(View v, Intent intent) { } public void logTaskLaunch(View v, ComponentKey key) { } public void logTaskDismiss(View v, ComponentKey key) { } + public void logSwipeOnContainer(boolean isSwipingToLeft, int pageId) { } public void verify() {} // TODO: should move into robo tests } diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java index ed0d470801..7d4f2f7225 100644 --- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java +++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java @@ -16,6 +16,8 @@ package com.android.launcher3.model; import android.content.Intent; +import android.content.pm.LauncherActivityInfo; +import android.content.pm.PackageInstaller.SessionInfo; import android.os.UserHandle; import android.util.LongSparseArray; import android.util.Pair; @@ -32,6 +34,8 @@ import com.android.launcher3.LauncherModel.Callbacks; import com.android.launcher3.LauncherSettings; import com.android.launcher3.WorkspaceItemInfo; import com.android.launcher3.Utilities; +import com.android.launcher3.compat.LauncherAppsCompat; +import com.android.launcher3.compat.PackageInstallerCompat; import com.android.launcher3.util.GridOccupancy; import com.android.launcher3.util.IntArray; @@ -85,6 +89,10 @@ public class AddWorkspaceItemsTask extends BaseModelUpdateTask { } } + PackageInstallerCompat packageInstaller = + PackageInstallerCompat.getInstance(app.getContext()); + LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(app.getContext()); + for (ItemInfo item : filteredItems) { // Find appropriate space for the item. int[] coords = findSpaceForItem(app, dataModel, workspaceScreens, @@ -101,6 +109,36 @@ public class AddWorkspaceItemsTask extends BaseModelUpdateTask { throw new RuntimeException("Unexpected info type"); } + if (item instanceof WorkspaceItemInfo && ((WorkspaceItemInfo) item).isPromise()) { + WorkspaceItemInfo workspaceInfo = (WorkspaceItemInfo) item; + String packageName = item.getTargetComponent() != null + ? item.getTargetComponent().getPackageName() : null; + if (packageName == null) { + continue; + } + SessionInfo sessionInfo = packageInstaller.getActiveSessionInfo(item.user, + packageName); + if (sessionInfo == null) { + List activities = launcherApps + .getActivityList(packageName, item.user); + if (activities != null && !activities.isEmpty()) { + // App was installed while launcher was in the background. + itemInfo = new AppInfo(app.getContext(), activities.get(0), item.user) + .makeWorkspaceItem(); + WorkspaceItemInfo wii = (WorkspaceItemInfo) itemInfo; + wii.title = ""; + wii.applyFrom(app.getIconCache().getDefaultIcon(item.user)); + app.getIconCache().getTitleAndIcon(wii, + ((WorkspaceItemInfo) itemInfo).usingLowResIcon()); + } else { + // Session was cancelled, do not add. + continue; + } + } else { + workspaceInfo.setInstallProgress((int) sessionInfo.getProgress()); + } + } + // Add the shortcut to the db getModelWriter().addItemToDatabase(itemInfo, LauncherSettings.Favorites.CONTAINER_DESKTOP, screenId, diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java index 1a03b77714..1c39d1f23c 100644 --- a/src/com/android/launcher3/model/LoaderCursor.java +++ b/src/com/android/launcher3/model/LoaderCursor.java @@ -227,7 +227,7 @@ public class LoaderCursor extends CursorWrapper { if (!TextUtils.isEmpty(title)) { info.title = Utilities.trim(title); } - } else if (hasRestoreFlag(WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON)) { + } else if (hasRestoreFlag(WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON)) { if (TextUtils.isEmpty(info.title)) { info.title = getTitle(); } diff --git a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java index 5f6d1281bd..9fcab38870 100644 --- a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java +++ b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java @@ -18,7 +18,6 @@ package com.android.launcher3.model; import android.content.ComponentName; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; -import android.os.Process; import com.android.launcher3.AllAppsList; import com.android.launcher3.AppInfo; @@ -56,7 +55,7 @@ public class PackageInstallStateChangedTask extends BaseModelUpdateTask { ApplicationInfo ai = app.getContext() .getPackageManager().getApplicationInfo(mInstallInfo.packageName, 0); if (InstantAppResolver.newInstance(app.getContext()).isInstantApp(ai)) { - app.getModel().onPackageAdded(ai.packageName, Process.myUserHandle()); + app.getModel().onPackageAdded(ai.packageName, mInstallInfo.user); } } catch (PackageManager.NameNotFoundException e) { // Ignore diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java index c37ed99522..4428c8e6df 100644 --- a/src/com/android/launcher3/model/PackageUpdatedTask.java +++ b/src/com/android/launcher3/model/PackageUpdatedTask.java @@ -43,6 +43,7 @@ import com.android.launcher3.icons.BitmapInfo; import com.android.launcher3.icons.LauncherIcons; import com.android.launcher3.logging.FileLog; import com.android.launcher3.shortcuts.DeepShortcutManager; +import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.util.FlagOp; import com.android.launcher3.util.IntSparseArrayMap; import com.android.launcher3.util.ItemInfoMatcher; @@ -55,6 +56,8 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; +import static com.android.launcher3.WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON; + /** * Handles updates due to changes in package manager (app installed/updated/removed) * or when a user availability changes. @@ -85,6 +88,10 @@ public class PackageUpdatedTask extends BaseModelUpdateTask { @Override public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList appsList) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.APP_NOT_DISABLED, "PackageUpdatedTask: " + mOp + ", " + + Arrays.toString(mPackages)); + } final Context context = app.getContext(); final IconCache iconCache = app.getIconCache(); @@ -99,7 +106,7 @@ public class PackageUpdatedTask extends BaseModelUpdateTask { if (DEBUG) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]); iconCache.updateIconsForPkg(packages[i], mUser); if (FeatureFlags.LAUNCHER3_PROMISE_APPS_IN_ALL_APPS) { - appsList.removePackage(packages[i], Process.myUserHandle()); + appsList.removePackage(packages[i], mUser); } appsList.addPackage(context, packages[i], mUser); @@ -227,8 +234,7 @@ public class PackageUpdatedTask extends BaseModelUpdateTask { isTargetValid = LauncherAppsCompat.getInstance(context) .isActivityEnabledForProfile(cn, mUser); } - if (si.hasStatusFlag(WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON) - && !isTargetValid) { + if (si.hasStatusFlag(FLAG_AUTOINSTALL_ICON)) { if (updateWorkspaceItemIntent(context, si, packageName)) { infoUpdated = true; } else if (si.hasPromiseIconUi()) { diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java index f9f5dc42ab..520598adfc 100644 --- a/src/com/android/launcher3/testing/TestProtocol.java +++ b/src/com/android/launcher3/testing/TestProtocol.java @@ -81,4 +81,6 @@ public final class TestProtocol { public static final String NO_BACKGROUND_TO_OVERVIEW_TAG = "b/138251824"; public static final String NO_DRAG_TO_WORKSPACE = "b/138729456"; + public static final String APP_NOT_DISABLED = "b/139891609"; + public static final String ALL_APPS_UPON_RECENTS = "b/139941530"; } diff --git a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java index e7a2bcab6b..cdda0f0dcc 100644 --- a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java +++ b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java @@ -21,10 +21,10 @@ public class FailureWatcher extends TestWatcher { mDevice = device; } - private void dumpViewHierarchy() { + private static void dumpViewHierarchy(UiDevice device) { final ByteArrayOutputStream stream = new ByteArrayOutputStream(); try { - mDevice.dumpWindowHierarchy(stream); + device.dumpWindowHierarchy(stream); stream.flush(); stream.close(); for (String line : stream.toString().split("\\r?\\n")) { @@ -37,7 +37,11 @@ public class FailureWatcher extends TestWatcher { @Override protected void failed(Throwable e, Description description) { - if (mDevice == null) return; + onError(mDevice, description, e); + } + + public static void onError(UiDevice device, Description description, Throwable e) { + if (device == null) return; final String pathname = getInstrumentation().getTargetContext(). getFilesDir().getPath() + "/TestScreenshot-" + description.getMethodName() + ".png"; @@ -45,15 +49,15 @@ public class FailureWatcher extends TestWatcher { ", screenshot will be saved to " + pathname + ", track trace is below, UI object dump is further below:\n" + Log.getStackTraceString(e)); - dumpViewHierarchy(); + dumpViewHierarchy(device); try { - final String dumpsysResult = mDevice.executeShellCommand( + final String dumpsysResult = device.executeShellCommand( "dumpsys activity service TouchInteractionService"); Log.d(TAG, "TouchInteractionService: " + dumpsysResult); } catch (IOException ex) { } - mDevice.takeScreenshot(new File(pathname)); + device.takeScreenshot(new File(pathname)); } }