From 80303ac4b9b2f881d146af619aaad28b390a4ca0 Mon Sep 17 00:00:00 2001 From: Vinit Nayak Date: Wed, 6 May 2020 13:18:13 -0700 Subject: [PATCH 01/35] Notify SysUi on device rotation for back gesture Whenever device rotates, we notify sysui to hide/show the back gesture if the foreground app also rotates. We also notify sysui when device rotates to match the orientation of the current foreground app (this is for apps with fixed rotations). Fixes: 154580671 Test: Created test apps of different rotations and ensured that back functionality was present when attempting to go back. Change-Id: I33a71698411d9bc2416b6660f8dbd53233628917 --- .../RecentsAnimationDeviceState.java | 119 ++++++++++++++++-- .../quickstep/util/RecentsOrientedState.java | 6 +- 2 files changed, 115 insertions(+), 10 deletions(-) diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java index adf2321d83..0b2fb8ed1a 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java @@ -16,6 +16,7 @@ package com.android.quickstep; import static android.content.Intent.ACTION_USER_UNLOCKED; +import static android.view.Surface.ROTATION_0; import static com.android.launcher3.util.DefaultDisplay.CHANGE_ALL; import static com.android.launcher3.util.DefaultDisplay.CHANGE_FRAME_DELAY; @@ -49,15 +50,18 @@ import android.os.UserManager; import android.provider.Settings; import android.text.TextUtils; import android.view.MotionEvent; +import android.view.OrientationEventListener; import androidx.annotation.BinderThread; import com.android.launcher3.R; import com.android.launcher3.Utilities; +import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.util.DefaultDisplay; import com.android.launcher3.util.SecureSettingsObserver; import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener; import com.android.quickstep.util.NavBarPosition; +import com.android.quickstep.util.RecentsOrientedState; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags; @@ -113,9 +117,53 @@ public class RecentsAnimationDeviceState implements } enableMultipleRegions(false); } + + @Override + public void onActivityRotation(int displayId) { + super.onActivityRotation(displayId); + // This always gets called before onDisplayInfoChanged() so we know how to process + // the rotation in that method. This is done to avoid having a race condition between + // the sensor readings and onDisplayInfoChanged() call + if (displayId != mDisplayId) { + return; + } + + mPrioritizeDeviceRotation = true; + if (mInOverview) { + // reset, launcher must be rotating + mExitOverviewRunnable.run(); + } + } + }; + + private Runnable mExitOverviewRunnable = new Runnable() { + @Override + public void run() { + mInOverview = false; + enableMultipleRegions(false); + } }; private OrientationTouchTransformer mOrientationTouchTransformer; + /** + * Used to listen for when the device rotates into the orientation of the current + * foreground app. For example, if a user quickswitches from a portrait to a fixed landscape + * app and then rotates rotates the device to match that orientation, this triggers calls to + * sysui to adjust the navbar. + */ + private OrientationEventListener mOrientationListener; + private int mPreviousRotation = ROTATION_0; + /** + * This is the configuration of the foreground app or the app that will be in the foreground + * once a quickstep gesture finishes. + */ + private int mCurrentAppRotation = -1; + /** + * This flag is set to true when the device physically changes orientations. When true, + * we will always report the current rotation of the foreground app whenever the display + * changes, as it would indicate the user's intention to rotate the foreground app. + */ + private boolean mPrioritizeDeviceRotation = false; private Region mExclusionRegion; private SystemGestureExclusionListenerCompat mExclusionListener; @@ -194,6 +242,26 @@ public class RecentsAnimationDeviceState implements userSetupObserver.register(); runOnDestroy(userSetupObserver::unregister); } + + mOrientationListener = new OrientationEventListener(context) { + @Override + public void onOrientationChanged(int degrees) { + int newRotation = RecentsOrientedState.getRotationForUserDegreesRotated(degrees, + mPreviousRotation); + if (newRotation == mPreviousRotation) { + return; + } + + mPreviousRotation = newRotation; + mPrioritizeDeviceRotation = true; + + if (newRotation == mCurrentAppRotation) { + // When user rotates device to the orientation of the foreground app after + // quickstepping + toggleSecondaryNavBarsForRotation(false); + } + } + }; } private void setupOrientationSwipeHandler() { @@ -273,6 +341,18 @@ public class RecentsAnimationDeviceState implements mNavBarPosition = new NavBarPosition(mMode, info); updateGestureTouchRegions(); mOrientationTouchTransformer.createOrAddTouchRegion(info); + mCurrentAppRotation = mDisplayRotation; + + /* Update nav bars on the following: + * a) if we're not expecting quickswitch, this is coming from an activity rotation + * b) we launch an app in the orientation that user is already in + * c) We're not in overview, since overview will always be portrait (w/o home rotation) + */ + if ((mPrioritizeDeviceRotation + || mCurrentAppRotation == mPreviousRotation) // switch to an app of orientation user is in + && !mInOverview) { + toggleSecondaryNavBarsForRotation(false); + } } /** @@ -558,9 +638,13 @@ public class RecentsAnimationDeviceState implements mOrientationTouchTransformer.transform(event); } - void enableMultipleRegions(boolean enable) { - mOrientationTouchTransformer.enableMultipleRegions(enable, mDefaultDisplay.getInfo()); - notifySysuiForRotation(mOrientationTouchTransformer.getQuickStepStartingRotation()); + private void enableMultipleRegions(boolean enable) { + toggleSecondaryNavBarsForRotation(enable); + if (enable && !TestProtocol.sDisableSensorRotation) { + mOrientationListener.enable(); + } else { + mOrientationListener.disable(); + } } private void notifySysuiForRotation(int rotation) { @@ -586,10 +670,7 @@ public class RecentsAnimationDeviceState implements // If we're in landscape w/o ever quickswitching, show the navbar in landscape enableMultipleRegions(true); } - activityInterface.onExitOverview(this, () -> { - mInOverview = false; - enableMultipleRegions(false); - }); + activityInterface.onExitOverview(this, mExitOverviewRunnable); } else if (endTarget == GestureState.GestureEndTarget.HOME) { enableMultipleRegions(false); } else if (endTarget == GestureState.GestureEndTarget.NEW_TASK) { @@ -599,6 +680,11 @@ public class RecentsAnimationDeviceState implements } else { notifySysuiForRotation(mOrientationTouchTransformer.getCurrentActiveRotation()); } + + // A new gesture is starting, reset the current device rotation + // This is done under the assumption that the user won't rotate the phone and then + // quickswitch in the old orientation. + mPrioritizeDeviceRotation = false; } else if (endTarget == GestureState.GestureEndTarget.LAST_TASK) { if (!mTaskListFrozen) { // touched nav bar but didn't go anywhere and not quickswitching, do nothing @@ -608,7 +694,24 @@ public class RecentsAnimationDeviceState implements } } - int getCurrentActiveRotation() { + private void notifySysuiOfCurrentRotation(int rotation) { + UI_HELPER_EXECUTOR.execute(() -> SystemUiProxy.INSTANCE.get(mContext) + .onQuickSwitchToNewTask(rotation)); + } + + /** + * Disables/Enables multiple nav bars on {@link OrientationTouchTransformer} and then + * notifies system UI of the primary rotation the user is interacting with + * + * @param enable if {@code true}, this will report to sysUI the navbar of the region the gesture + * started in (during ACTION_DOWN), otherwise will report {@param displayRotation} + */ + private void toggleSecondaryNavBarsForRotation(boolean enable) { + mOrientationTouchTransformer.enableMultipleRegions(enable, mDefaultDisplay.getInfo()); + notifySysuiOfCurrentRotation(mOrientationTouchTransformer.getQuickStepStartingRotation()); + } + + public int getCurrentActiveRotation() { if (!mMode.hasGestures) { // touch rotation should always match that of display for 3 button return mDisplayRotation; diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java index 922f5ac79e..0e9d6dd305 100644 --- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java +++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java @@ -458,7 +458,8 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre } break; case ROTATION_270: - if (degrees < (90 - threshold)) { + if (degrees < (90 - threshold) || + (degrees > (270 + threshold) && degrees < 360)) { return ROTATION_0; } if (degrees > (90 + threshold) && degrees < 180) { @@ -481,7 +482,8 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre if (degrees < (270 - threshold) && degrees > 90) { return ROTATION_180; } - if (degrees > (270 + threshold) && degrees < 360) { + if (degrees > (270 + threshold) && degrees < 360 + || (degrees >= 0 && degrees < threshold)) { return ROTATION_0; } // flip from landscape to seascape From ff85415865886d406eea002ec3391bd053d0ed1b Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Mon, 8 Jun 2020 18:43:35 -0500 Subject: [PATCH 02/35] Set qsb fade interpolator same as workspace for home <-> overview Test: go to overview from home and vice versa in 0 and 3 button modes, ensure QSB fades at the same rate as the rest of workspace Bug: 154637581 Change-Id: I2f15aaf2ba59e6b1d4754060e7b3005bed5db9c7 --- .../uioverrides/states/QuickstepAtomicAnimationFactory.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java index 79dc3e25c3..ba8656db76 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java @@ -156,6 +156,7 @@ public class QuickstepAtomicAnimationFactory extends if (toState == NORMAL && fromState == OVERVIEW) { config.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL); config.setInterpolator(ANIM_WORKSPACE_FADE, ACCEL); + config.setInterpolator(ANIM_ALL_APPS_FADE, ACCEL); config.setInterpolator(ANIM_OVERVIEW_SCALE, clampToProgress(ACCEL, 0, 0.9f)); config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, ACCEL); config.setInterpolator(ANIM_OVERVIEW_FADE, DEACCEL_1_7); @@ -210,6 +211,7 @@ public class QuickstepAtomicAnimationFactory extends } } config.setInterpolator(ANIM_WORKSPACE_FADE, OVERSHOOT_1_2); + config.setInterpolator(ANIM_ALL_APPS_FADE, OVERSHOOT_1_2); config.setInterpolator(ANIM_OVERVIEW_SCALE, OVERSHOOT_1_2); config.setInterpolator(ANIM_DEPTH, OVERSHOOT_1_2); Interpolator translationInterpolator = ENABLE_OVERVIEW_ACTIONS.get() From 5e957551be37179b41d5b7ab2e17211dc6de757c Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Tue, 9 Jun 2020 14:57:07 -0500 Subject: [PATCH 03/35] Fix quick switching to any task that already appeared Previously we did this for the last task that appeared, but didn't take into account cases where multiple tasks had appeared during the same gesture state. We handle that now. Test: - Quick switch to delayed task A, start new gesture, return to the first app after onTaskAppeared(A) - Quick switch to delayed task A, start new gesture, wait for onTaskAppeared(A), then switch to delayed task B, start new gesture, wait for onTaskAppeared(B), and switch back to A - Quick switch to delayed task A, start new gesture, wait for onTaskAppeared(A), then switch to delayed task B, start new gesture, wait for onTaskAppeared(B), and switch back to A and quickly back to original app (before settling on A) Ensure task starts/resumes and is interactable in all cases. Bug: 158588954 Change-Id: I647a6d015baa1d9b6d613e6c0e584589f35da54a --- .../com/android/quickstep/BaseSwipeUpHandler.java | 9 +++++---- .../android/quickstep/BaseSwipeUpHandlerV2.java | 4 ++-- .../quickstep/TouchInteractionService.java | 2 ++ .../src/com/android/quickstep/GestureState.java | 15 +++++++++++++++ 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java index b5fb31a9de..56af2e00c6 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java @@ -144,13 +144,14 @@ public abstract class BaseSwipeUpHandler, Q extend TaskView nextTask = mRecentsView.getTaskView(taskId); if (nextTask != null) { mGestureState.updateLastStartedTaskId(taskId); + boolean hasTaskPreviouslyAppeared = mGestureState.getPreviouslyAppearedTaskIds() + .contains(taskId); nextTask.launchTask(false /* animate */, true /* freezeTaskList */, success -> { resultCallback.accept(success); if (success) { - if (mRecentsView.indexOfChild(nextTask) - == getLastAppearedTaskIndex()) { - onRestartLastAppearedTask(); + if (hasTaskPreviouslyAppeared) { + onRestartPreviouslyAppearedTask(); } } else { mActivityInterface.onLaunchTaskFailed(); @@ -171,7 +172,7 @@ public abstract class BaseSwipeUpHandler, Q extend * start A again to ensure it stays on top. */ @CallSuper - protected void onRestartLastAppearedTask() { + protected void onRestartPreviouslyAppearedTask() { // Finish the controller here, since we won't get onTaskAppeared() for a task that already // appeared. if (mRecentsAnimationController != null) { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java index f2438b62b2..7b3a787e29 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java @@ -1097,8 +1097,8 @@ public abstract class BaseSwipeUpHandlerV2, Q exte } @Override - protected void onRestartLastAppearedTask() { - super.onRestartLastAppearedTask(); + protected void onRestartPreviouslyAppearedTask() { + super.onRestartPreviouslyAppearedTask(); reset(); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java index 226c8181b6..be69a36eb8 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java @@ -540,6 +540,8 @@ public class TouchInteractionService extends Service implements PluginListener mAM.getRunningTask(false /* filterOnlyVisibleRecents */))); diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java index 188072a042..00b5eb9880 100644 --- a/quickstep/src/com/android/quickstep/GestureState.java +++ b/quickstep/src/com/android/quickstep/GestureState.java @@ -30,6 +30,8 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; /** * Manages the state for an active system gesture, listens for events from the system and Launcher, @@ -128,6 +130,7 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL private ActivityManager.RunningTaskInfo mRunningTask; private GestureEndTarget mEndTarget; private RemoteAnimationTargetCompat mLastAppearedTaskTarget; + private Set mPreviouslyAppearedTaskIds = new HashSet<>(); private int mLastStartedTaskId = -1; public GestureState(OverviewComponentObserver componentObserver, int gestureId) { @@ -147,6 +150,7 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL mRunningTask = other.mRunningTask; mEndTarget = other.mEndTarget; mLastAppearedTaskTarget = other.mLastAppearedTaskTarget; + mPreviouslyAppearedTaskIds = other.mPreviouslyAppearedTaskIds; mLastStartedTaskId = other.mLastStartedTaskId; } @@ -234,6 +238,9 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL */ public void updateLastAppearedTaskTarget(RemoteAnimationTargetCompat lastAppearedTaskTarget) { mLastAppearedTaskTarget = lastAppearedTaskTarget; + if (lastAppearedTaskTarget != null) { + mPreviouslyAppearedTaskIds.add(lastAppearedTaskTarget.taskId); + } } /** @@ -243,6 +250,14 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL return mLastAppearedTaskTarget != null ? mLastAppearedTaskTarget.taskId : -1; } + public void updatePreviouslyAppearedTaskIds(Set previouslyAppearedTaskIds) { + mPreviouslyAppearedTaskIds = previouslyAppearedTaskIds; + } + + public Set getPreviouslyAppearedTaskIds() { + return mPreviouslyAppearedTaskIds; + } + /** * Updates the last task that we started via startActivityFromRecents() during this gesture. */ From 55e2b1635f27c44bc2dabc8561e357706d8b3832 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 9 Jun 2020 15:44:48 -0700 Subject: [PATCH 04/35] Adding a new attribute to speficy folder label directly in layout Bug: 158141109 Change-Id: I84dccf43981abc910c0d9e75bf316c6b27b3606b --- .../model/DefaultLayoutProviderTest.java | 16 ++++++++++++++++ .../launcher3/util/LauncherLayoutBuilder.java | 12 +++++++++++- .../android/launcher3/AutoInstallsLayout.java | 4 +++- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/robolectric_tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java b/robolectric_tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java index 7ca416d520..8f3a83ed07 100644 --- a/robolectric_tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java +++ b/robolectric_tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java @@ -89,6 +89,22 @@ public class DefaultLayoutProviderTest { assertEquals(3, ((FolderInfo) info).contents.size()); } + @Test + public void testCustomProfileLoaded_with_folder_custom_title() throws Exception { + writeLayoutAndLoad(new LauncherLayoutBuilder().atHotseat(0).putFolder("CustomFolder") + .addApp(TEST_PACKAGE, TEST_PACKAGE) + .addApp(TEST_PACKAGE, TEST_PACKAGE) + .addApp(TEST_PACKAGE, TEST_PACKAGE) + .build()); + + // Verify folder + assertEquals(1, mModelHelper.getBgDataModel().workspaceItems.size()); + ItemInfo info = mModelHelper.getBgDataModel().workspaceItems.get(0); + assertEquals(LauncherSettings.Favorites.ITEM_TYPE_FOLDER, info.itemType); + assertEquals(3, ((FolderInfo) info).contents.size()); + assertEquals("CustomFolder", info.title.toString()); + } + @Test public void testCustomProfileLoaded_with_widget() throws Exception { String pendingAppPkg = "com.test.pending"; diff --git a/robolectric_tests/src/com/android/launcher3/util/LauncherLayoutBuilder.java b/robolectric_tests/src/com/android/launcher3/util/LauncherLayoutBuilder.java index d3659ebdcd..4e21dce021 100644 --- a/robolectric_tests/src/com/android/launcher3/util/LauncherLayoutBuilder.java +++ b/robolectric_tests/src/com/android/launcher3/util/LauncherLayoutBuilder.java @@ -47,6 +47,7 @@ public class LauncherLayoutBuilder { private static final String ATTR_PACKAGE_NAME = "packageName"; private static final String ATTR_CLASS_NAME = "className"; private static final String ATTR_TITLE = "title"; + private static final String ATTR_TITLE_TEXT = "titleText"; private static final String ATTR_SCREEN = "screen"; // x and y can be specified as negative integers, in which case -1 represents the @@ -145,8 +146,17 @@ public class LauncherLayoutBuilder { } public FolderBuilder putFolder(int titleResId) { - FolderBuilder folderBuilder = new FolderBuilder(); items.put(ATTR_TITLE, Integer.toString(titleResId)); + return putFolder(); + } + + public FolderBuilder putFolder(String title) { + items.put(ATTR_TITLE_TEXT, title); + return putFolder(); + } + + private FolderBuilder putFolder() { + FolderBuilder folderBuilder = new FolderBuilder(); items.put(ATTR_CHILDREN, folderBuilder.mChildren); mNodes.add(Pair.create(TAG_FOLDER, items)); return folderBuilder; diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java index 5971a028ca..432073ebaf 100644 --- a/src/com/android/launcher3/AutoInstallsLayout.java +++ b/src/com/android/launcher3/AutoInstallsLayout.java @@ -132,6 +132,7 @@ public class AutoInstallsLayout { private static final String ATTR_PACKAGE_NAME = "packageName"; private static final String ATTR_CLASS_NAME = "className"; private static final String ATTR_TITLE = "title"; + private static final String ATTR_TITLE_TEXT = "titleText"; private static final String ATTR_SCREEN = "screen"; // x and y can be specified as negative integers, in which case -1 represents the @@ -585,7 +586,8 @@ public class AutoInstallsLayout { if (titleResId != 0) { title = mSourceRes.getString(titleResId); } else { - title = ""; + String titleText = getAttributeValue(parser, ATTR_TITLE_TEXT); + title = TextUtils.isEmpty(titleText) ? "" : titleText; } mValues.put(Favorites.TITLE, title); From f74f0c27bc25361c96a54d035de10006e2843b44 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 9 Jun 2020 18:07:58 -0700 Subject: [PATCH 05/35] Creating correct device profile when appContext and launcher context do not match Bug: 156891776 Change-Id: If2df3a6719de4207fa15d8a416704eb8e7c136b9 --- .../com/android/quickstep/BaseSwipeUpHandler.java | 10 ++++------ .../src/com/android/quickstep/RecentsActivity.java | 3 +-- .../android/quickstep/SwipeUpAnimationLogic.java | 6 +++--- .../quickstep/util/RecentsOrientedState.java | 14 +++++++++++++- 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java index b5fb31a9de..1b0afaebdf 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java @@ -32,7 +32,6 @@ import androidx.annotation.CallSuper; import androidx.annotation.UiThread; import com.android.launcher3.DeviceProfile; -import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.util.VibratorWrapper; @@ -96,8 +95,8 @@ public abstract class BaseSwipeUpHandler, Q extend * depend on proper class initialization. */ protected void initAfterSubclassConstructor() { - initTransitionEndpoints(InvariantDeviceProfile.INSTANCE.get(mContext) - .getDeviceProfile(mContext)); + initTransitionEndpoints( + mTaskViewSimulator.getOrientationState().getLauncherDeviceProfile()); } protected void performHapticFeedback() { @@ -205,7 +204,7 @@ public abstract class BaseSwipeUpHandler, Q extend mRecentsAnimationController = recentsAnimationController; mRecentsAnimationTargets = targets; mTransformParams.setTargetSet(mRecentsAnimationTargets); - DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(mContext).getDeviceProfile(mContext); + DeviceProfile dp = mTaskViewSimulator.getOrientationState().getLauncherDeviceProfile(); RemoteAnimationTargetCompat runningTaskTarget = targets.findTask( mGestureState.getRunningTaskId()); @@ -300,8 +299,7 @@ public abstract class BaseSwipeUpHandler, Q extend if (TestProtocol.sDebugTracing) { Log.d(TestProtocol.PAUSE_NOT_DETECTED, "BaseSwipeUpHandler.2"); } - initTransitionEndpoints(InvariantDeviceProfile.INSTANCE.get(mContext) - .getDeviceProfile(mContext)); + initTransitionEndpoints(createdActivity.getDeviceProfile()); } return true; } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java index 852a51a9ce..170102047b 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java @@ -139,13 +139,12 @@ public final class RecentsActivity extends StatefulActivity { */ protected DeviceProfile createDeviceProfile() { DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(this).getDeviceProfile(this); - DeviceProfile dp1 = InvariantDeviceProfile.INSTANCE.get(this).getDeviceProfile(this); // In case we are reusing IDP, create a copy so that we don't conflict with Launcher // activity. return (mRecentsRootView != null) && isInMultiWindowMode() ? dp.getMultiWindowProfile(this, getMultiWindowDisplaySize()) - : dp1.copy(this); + : dp.copy(this); } @Override diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeUpAnimationLogic.java index b17730ba6d..dc8f1c54c8 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeUpAnimationLogic.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeUpAnimationLogic.java @@ -83,15 +83,15 @@ public abstract class SwipeUpAnimationLogic { mGestureState = gestureState; mTaskViewSimulator = new TaskViewSimulator(context, gestureState.getActivityInterface()); mTransformParams = transformParams; + + mTaskViewSimulator.setLayoutRotation( + mDeviceState.getCurrentActiveRotation(), mDeviceState.getDisplayRotation()); } protected void initTransitionEndpoints(DeviceProfile dp) { mDp = dp; mTaskViewSimulator.setDp(dp); - mTaskViewSimulator.setLayoutRotation( - mDeviceState.getCurrentActiveRotation(), - mDeviceState.getDisplayRotation()); mTransitionDragLength = mGestureState.getActivityInterface().getSwipeUpDestinationAndLength( dp, mContext, TEMP_RECT, mTaskViewSimulator.getOrientationState().getOrientationHandler()); diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java index 7715cca60f..76ca3de5bf 100644 --- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java +++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java @@ -26,8 +26,8 @@ import static android.view.Surface.ROTATION_90; import static com.android.launcher3.logging.LoggerUtils.extractObjectNameAndAddress; import static com.android.launcher3.states.RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; - import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS; + import static java.lang.annotation.RetentionPolicy.SOURCE; import android.content.ContentResolver; @@ -49,6 +49,7 @@ import androidx.annotation.IntDef; import androidx.annotation.NonNull; import com.android.launcher3.DeviceProfile; +import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.Utilities; import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.touch.PagedOrientationHandler; @@ -524,4 +525,15 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre + " mFlags=" + mFlags + "]"; } + + /** + * Returns the device profile based on expected launcher rotation + */ + public DeviceProfile getLauncherDeviceProfile() { + InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(mContext); + // TODO also check the natural orientation is landscape or portrait + return (mLauncherRotation == ROTATION_90 || mLauncherRotation == ROTATION_270) + ? idp.landscapeProfile + : idp.portraitProfile; + } } From b64b59d025c7b3ce71016544630b20e684e08fa8 Mon Sep 17 00:00:00 2001 From: Sreyas Date: Tue, 9 Jun 2020 21:00:22 -0700 Subject: [PATCH 06/35] Fix Task Icon menu behavior. Tapping task icon will now show the scrim for rest of thumbnail and not snap to page that is already snapped to. Pressing task icon from clear all will scroll to the page. Link: https://drive.google.com/file/d/1I90rd6ELPZNIje2_VZ3CamWWeFN8ywhL/view?usp=sharing Bug: 158004853 Change-Id: I9ac8229a603190ea09a74e1cfb70a6bb6e1e65b7 --- .../android/quickstep/views/RecentsView.java | 13 ++++++++++++- .../com/android/quickstep/views/TaskView.java | 17 ++++++++++------- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java index 98784efdc1..9b1e27d3e6 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java @@ -607,6 +607,17 @@ public abstract class RecentsView extends PagedView impl } } + /** + * Whether the Clear All button is hidden or fully visible. Used to determine if center + * displayed page is a task or the Clear All button. + * + * @return True = Clear All button not fully visible, center page is a task. False = Clear All + * button fully visible, center page is Clear All button. + */ + public boolean isClearAllHidden() { + return mClearAllButton.getAlpha() != 1f; + } + @Override protected void onPageBeginTransition() { super.onPageBeginTransition(); @@ -616,7 +627,7 @@ public abstract class RecentsView extends PagedView impl @Override protected void onPageEndTransition() { super.onPageEndTransition(); - if (getScrollX() == getScrollForPage(getPageNearestToCenterOfScreen())) { + if (isClearAllHidden()) { LayoutUtils.setViewEnabled(mActionsView, true); } if (getNextPage() > 0) { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java index cadf6c4174..e25c85b92b 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java @@ -425,13 +425,16 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { } private boolean showTaskMenu(int action) { - getRecentsView().snapToPage(getRecentsView().indexOfChild(this)); - mMenuView = TaskMenuView.showForTask(this); - mActivity.getStatsLogManager().log(LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS, buildProto()); - UserEventDispatcher.newInstance(getContext()).logActionOnItem(action, Direction.NONE, - LauncherLogProto.ItemType.TASK_ICON); - if (mMenuView != null) { - mMenuView.addOnAttachStateChangeListener(mTaskMenuStateListener); + if (!getRecentsView().isClearAllHidden()) { + getRecentsView().snapToPage(getRecentsView().indexOfChild(this)); + } else { + mMenuView = TaskMenuView.showForTask(this); + mActivity.getStatsLogManager().log(LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS, buildProto()); + UserEventDispatcher.newInstance(getContext()).logActionOnItem(action, Direction.NONE, + LauncherLogProto.ItemType.TASK_ICON); + if (mMenuView != null) { + mMenuView.addOnAttachStateChangeListener(mTaskMenuStateListener); + } } return mMenuView != null; } From fa88a25ea4aa59323e74fe6414285a72ef192ba2 Mon Sep 17 00:00:00 2001 From: Tracy Zhou Date: Wed, 10 Jun 2020 10:21:39 -0700 Subject: [PATCH 07/35] Consider folder diff differently Fixes: 157813770 Test: manual Change-Id: I0e95f7d9709cacfe1c3b8384dfb15208a4c36914 --- .../model/GridSizeMigrationTaskV2.java | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java b/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java index 5ba2c8e3f5..25a2c695f1 100644 --- a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java +++ b/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java @@ -59,7 +59,6 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; -import java.util.stream.Collectors; /** * This class takes care of shrinking the workspace (by maximum of one row and one column), as a @@ -248,12 +247,25 @@ public class GridSizeMigrationTaskV2 { /** Return what's in the src but not in the dest */ private static List calcDiff(List src, List dest) { - Set destSet = dest.parallelStream().map(DbEntry::getIntentStr).collect( - Collectors.toSet()); + Set destIntentSet = new HashSet<>(); + Set> destFolderIntentSet = new HashSet<>(); + for (DbEntry entry : dest) { + if (entry.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) { + destFolderIntentSet.add(entry.mFolderItems.keySet()); + } else { + destIntentSet.add(entry.mIntent); + } + } List diff = new ArrayList<>(); for (DbEntry entry : src) { - if (!destSet.contains(entry.mIntent)) { - diff.add(entry); + if (entry.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) { + if (!destFolderIntentSet.contains(entry.mFolderItems.keySet())) { + diff.add(entry); + } + } else { + if (!destIntentSet.contains(entry.mIntent)) { + diff.add(entry); + } } } return diff; From bc83edbf4dda767684c69c932a87262d9fa57965 Mon Sep 17 00:00:00 2001 From: Andy Wickham Date: Wed, 27 May 2020 12:58:40 -0700 Subject: [PATCH 08/35] Allows Accessibility to focus on specified view in AbstractFloatingView. Here, the first item in an ArrowPopup or Folder are focused on. Note: There's another pre-existing bug where it announces "Home screen x of y" when the floating view appears; this change doesn't address that. Fixes: 147470419 Change-Id: I1dc70edc21ea7c19a5742208512738d6c4a94067 --- src/com/android/launcher3/AbstractFloatingView.java | 8 +++++++- src/com/android/launcher3/folder/Folder.java | 5 +++++ src/com/android/launcher3/popup/ArrowPopup.java | 5 +++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java index 572615ff8a..cd27a2ddca 100644 --- a/src/com/android/launcher3/AbstractFloatingView.java +++ b/src/com/android/launcher3/AbstractFloatingView.java @@ -174,7 +174,8 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch targetInfo.first, TYPE_WINDOW_STATE_CHANGED, targetInfo.second); if (mIsOpen) { - performAccessibilityAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); + getAccessibilityInitialFocusView().performAccessibilityAction( + AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); } ActivityContext.lookupContext(getContext()).getDragLayer() .sendAccessibilityEvent(TYPE_WINDOW_CONTENT_CHANGED); @@ -184,6 +185,11 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch return null; } + /** Returns the View that Accessibility services should focus on first. */ + protected View getAccessibilityInitialFocusView() { + return this; + } + /** * Returns a view matching FloatingViewType */ diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java index fdf0ea46f2..c7487cb602 100644 --- a/src/com/android/launcher3/folder/Folder.java +++ b/src/com/android/launcher3/folder/Folder.java @@ -745,6 +745,11 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo : getContext().getString(R.string.folder_closed)); } + @Override + protected View getAccessibilityInitialFocusView() { + return mContent.getFirstItem(); + } + private void closeComplete(boolean wasAnimated) { // TODO: Clear all active animations. DragLayer parent = (DragLayer) getParent(); diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java index 5b0c388332..d5b32fccd1 100644 --- a/src/com/android/launcher3/popup/ArrowPopup.java +++ b/src/com/android/launcher3/popup/ArrowPopup.java @@ -389,6 +389,11 @@ public abstract class ArrowPopup extends Abstrac return Pair.create(this, ""); } + @Override + protected View getAccessibilityInitialFocusView() { + return getChildCount() > 0 ? getChildAt(0) : this; + } + private void animateOpen() { setVisibility(View.VISIBLE); From 779955390ca635db90185af573897c5235678f6b Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Wed, 10 Jun 2020 15:36:52 -0500 Subject: [PATCH 09/35] Add null check before updating animation progress Haven't been able to reproduce it locally, but seems theoretically possible if we get an onDrag() event right after something else cancels the animation (which clears the animation controller). Bug: 157900227 Change-Id: Ia134aa948e62d39f71e41dd4e6b98f3227ae0522 --- .../launcher3/touch/AbstractStateChangeTouchController.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java index 2c21609fa6..171c5ee4e4 100644 --- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java +++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java @@ -310,6 +310,9 @@ public abstract class AbstractStateChangeTouchController } protected void updateProgress(float fraction) { + if (mCurrentAnimation == null) { + return; + } mCurrentAnimation.setPlayFraction(fraction); if (mAtomicComponentsController != null) { // Make sure we don't divide by 0, and have at least a small runway. From ba0a6b61a3b229407bc4f4a62ed0f8c14adfa82a Mon Sep 17 00:00:00 2001 From: thiruram Date: Tue, 9 Jun 2020 14:24:49 -0700 Subject: [PATCH 10/35] Log folder open event into WW. Bug: 158597506 Sample Log: https://paste.googleplex.com/5351626992779264 Change-Id: Ifb2f061924035abc84472a9a03d1b4212588428b --- .../logging/StatsLogCompatManager.java | 36 ++++++++++++++++--- .../launcher3/logging/StatsLogManager.java | 12 ++++++- .../launcher3/touch/ItemClickHandler.java | 3 ++ 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java index be8eb48f25..390330f166 100644 --- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java +++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java @@ -94,6 +94,11 @@ public class StatsLogCompatManager extends StatsLogManager { log(event, DEFAULT_INSTANCE_ID, info); } + @Override + public void log(EventEnum event, ItemInfo itemInfo) { + logInternal(event, DEFAULT_INSTANCE_ID, itemInfo); + } + /** * Logs an event and accompanying {@link InstanceId} and {@link LauncherAtom.ItemInfo}. */ @@ -135,6 +140,27 @@ public class StatsLogCompatManager extends StatsLogManager { logInternal(event, DEFAULT_INSTANCE_ID, info, srcState, dstState); } + private void logInternal(EventEnum event, InstanceId instanceId, @Nullable ItemInfo info) { + LauncherAppState.getInstance(sContext).getModel().enqueueModelUpdateTask( + new BaseModelUpdateTask() { + @Override + public void execute(LauncherAppState app, BgDataModel dataModel, + AllAppsList apps) { + LauncherAtom.ItemInfo atomInfo = LauncherAtom.ItemInfo.getDefaultInstance(); + if (info != null) { + if (info.container >= 0) { + atomInfo = info.buildProto(dataModel.folders.get(info.container)); + } else { + atomInfo = info.buildProto(); + } + } + logInternal(event, instanceId, atomInfo, + LAUNCHER_UICHANGED__DST_STATE__HOME, + LAUNCHER_UICHANGED__DST_STATE__BACKGROUND); + } + }); + } + /** * Logs an event and accompanying {@link InstanceId} and {@link LauncherAtom.ItemInfo}. */ @@ -143,14 +169,14 @@ public class StatsLogCompatManager extends StatsLogManager { info = info == null ? LauncherAtom.ItemInfo.getDefaultInstance() : info; if (IS_VERBOSE) { - String name = (event instanceof LauncherEvent) ? ((LauncherEvent) event).name() : + String name = (event instanceof Enum) ? ((Enum) event).name() : event.getId() + ""; Log.d(TAG, instanceId == DEFAULT_INSTANCE_ID ? String.format("\n%s (State:%s->%s) \n%s", name, getStateString(srcState), - getStateString(dstState), info) - : String.format("\n%s (State:%s->%s) (InstanceId:%s)\n%s", name, instanceId, - getStateString(srcState), getStateString(dstState), info)); + getStateString(dstState), info) + : String.format("\n%s (State:%s->%s) (InstanceId:%s)\n%s", name, + getStateString(srcState), getStateString(dstState), instanceId, info)); } if (!Utilities.ATLEAST_R) { @@ -333,7 +359,7 @@ public class StatsLogCompatManager extends StatsLogManager { } private static String getStateString(int state) { - switch(state) { + switch (state) { case LAUNCHER_UICHANGED__DST_STATE__BACKGROUND: return "BACKGROUND"; case LAUNCHER_UICHANGED__DST_STATE__HOME: diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java index f216f8129b..6af0eefe11 100644 --- a/src/com/android/launcher3/logging/StatsLogManager.java +++ b/src/com/android/launcher3/logging/StatsLogManager.java @@ -127,7 +127,10 @@ public class StatsLogManager implements ResourceBasedOverride { LAUNCHER_SYSTEM_SHORTCUT_PIN_TAP(522), @UiEvent(doc = "User is shown All Apps education view.") - LAUNCHER_ALL_APPS_EDU_SHOWN(523); + LAUNCHER_ALL_APPS_EDU_SHOWN(523), + + @UiEvent(doc = "User opened a folder.") + LAUNCHER_FOLDER_OPEN(551); // ADD MORE private final int mId; @@ -194,6 +197,13 @@ public class StatsLogManager implements ResourceBasedOverride { public void log(EventEnum event, @Nullable ItemInfo itemInfo) { } + /** + * Logs an event and accompanying {@link com.android.launcher3.model.data.ItemInfo}. + */ + public void log(EventEnum event, + com.android.launcher3.model.data.ItemInfo itemInfo) { + } + /** * Logs an event and accompanying {@link InstanceId} and {@link ItemInfo}. */ diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java index 6abca767ae..de16941864 100644 --- a/src/com/android/launcher3/touch/ItemClickHandler.java +++ b/src/com/android/launcher3/touch/ItemClickHandler.java @@ -17,6 +17,7 @@ package com.android.launcher3.touch; import static com.android.launcher3.Launcher.REQUEST_BIND_PENDING_APPWIDGET; import static com.android.launcher3.Launcher.REQUEST_RECONFIGURE_APPWIDGET; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN; import static com.android.launcher3.model.AppLaunchTracker.CONTAINER_ALL_APPS; import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_BY_PUBLISHER; import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER; @@ -45,6 +46,7 @@ import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.FolderIcon; +import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; @@ -111,6 +113,7 @@ public class ItemClickHandler { if (!folder.isOpen() && !folder.isDestroyed()) { // Open the requested folder folder.animateOpen(); + StatsLogManager.newInstance(v.getContext()).log(LAUNCHER_FOLDER_OPEN, folder.mInfo); } } From 849622f6cb3ce905bffeb58ceeeda4be0ee155c0 Mon Sep 17 00:00:00 2001 From: Becky Qiu Date: Thu, 28 May 2020 15:52:02 -0700 Subject: [PATCH 11/35] [Overview Actions] Add actions to the task menu for in-place landscape. Test: local Bug: 153736749 Change-Id: I9ba5a089e434e75de7d9cc29ebd303f7a1388324 --- .../android/quickstep/TaskOverlayFactory.java | 82 ++++++++++++++++--- .../quickstep/TaskShortcutFactory.java | 17 ++++ .../android/quickstep/views/RecentsView.java | 5 ++ .../quickstep/views/TaskThumbnailView.java | 10 +++ 4 files changed, 104 insertions(+), 10 deletions(-) diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java index 97cd11b4f5..a6a08cb656 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java @@ -16,6 +16,8 @@ package com.android.quickstep; +import static android.view.Surface.ROTATION_0; + import static com.android.launcher3.util.MainThreadInitializedObject.forOverride; import android.annotation.SuppressLint; @@ -24,6 +26,7 @@ import android.graphics.Insets; import android.graphics.Matrix; import android.graphics.Rect; import android.os.Build; +import android.view.View; import android.widget.Toast; import androidx.annotation.RequiresApi; @@ -31,9 +34,12 @@ import androidx.annotation.RequiresApi; import com.android.launcher3.BaseActivity; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.R; +import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.util.MainThreadInitializedObject; import com.android.launcher3.util.ResourceBasedOverride; +import com.android.quickstep.util.RecentsOrientedState; import com.android.quickstep.views.OverviewActionsView; import com.android.quickstep.views.TaskThumbnailView; import com.android.quickstep.views.TaskView; @@ -58,6 +64,19 @@ public class TaskOverlayFactory implements ResourceBasedOverride { shortcuts.add(shortcut); } } + RecentsOrientedState orientedState = taskView.getRecentsView().getPagedViewOrientedState(); + boolean canLauncherRotate = orientedState.canLauncherRotate(); + boolean isInLandscape = orientedState.getTouchRotation() != ROTATION_0; + + // Add overview actions to the menu when in in-place rotate landscape mode. + if (!canLauncherRotate && isInLandscape) { + for (TaskShortcutFactory actionMenuOption : ACTION_MENU_OPTIONS) { + SystemShortcut shortcut = actionMenuOption.getShortcut(activity, taskView); + if (shortcut != null) { + shortcuts.add(shortcut); + } + } + } return shortcuts; } @@ -85,6 +104,11 @@ public class TaskOverlayFactory implements ResourceBasedOverride { TaskShortcutFactory.WELLBEING }; + private static final TaskShortcutFactory[] ACTION_MENU_OPTIONS = new TaskShortcutFactory[]{ + TaskShortcutFactory.SCREENSHOT, + TaskShortcutFactory.MODAL + }; + /** * Overlay on each task handling Overview Action Buttons. */ @@ -94,10 +118,14 @@ public class TaskOverlayFactory implements ResourceBasedOverride { protected final TaskThumbnailView mThumbnailView; private T mActionsView; + private ImageActionsApi mImageApi; + private boolean mIsAllowedByPolicy; protected TaskOverlay(TaskThumbnailView taskThumbnailView) { mApplicationContext = taskThumbnailView.getContext().getApplicationContext(); mThumbnailView = taskThumbnailView; + mImageApi = new ImageActionsApi( + mApplicationContext, mThumbnailView::getThumbnail); } protected T getActionsView() { @@ -112,15 +140,12 @@ public class TaskOverlayFactory implements ResourceBasedOverride { * Called when the current task is interactive for the user */ public void initOverlay(Task task, ThumbnailData thumbnail, Matrix matrix) { - ImageActionsApi imageApi = new ImageActionsApi( - mApplicationContext, mThumbnailView::getThumbnail); final boolean isAllowedByPolicy = thumbnail.isRealSnapshot; - getActionsView().setCallbacks(new OverlayUICallbacks() { @Override public void onShare() { if (isAllowedByPolicy) { - imageApi.startShareActivity(); + mImageApi.startShareActivity(); } else { showBlockedByPolicyMessage(); } @@ -129,16 +154,23 @@ public class TaskOverlayFactory implements ResourceBasedOverride { @SuppressLint("NewApi") @Override public void onScreenshot() { - if (isAllowedByPolicy) { - imageApi.saveScreenshot(mThumbnailView.getThumbnail(), - getTaskSnapshotBounds(), getTaskSnapshotInsets(), task.key); - } else { - showBlockedByPolicyMessage(); - } + saveScreenshot(task); } }); } + /** + * Called to save screenshot of the task thumbnail. + */ + @SuppressLint("NewApi") + private void saveScreenshot(Task task) { + if (mThumbnailView.isRealSnapshot()) { + mImageApi.saveScreenshot(mThumbnailView.getThumbnail(), + getTaskSnapshotBounds(), getTaskSnapshotInsets(), task.key); + } else { + showBlockedByPolicyMessage(); + } + } /** * Called when the overlay is no longer used. @@ -146,6 +178,20 @@ public class TaskOverlayFactory implements ResourceBasedOverride { public void reset() { } + /** + * Gets the modal state system shortcut. + */ + public SystemShortcut getModalStateSystemShortcut(WorkspaceItemInfo itemInfo) { + return null; + } + + /** + * Gets the system shortcut for the screenshot that will be added to the task menu. + */ + public SystemShortcut getScreenshotShortcut(BaseDraggingActivity activity, + ItemInfo iteminfo) { + return new ScreenshotSystemShortcut(activity, iteminfo); + } /** * Gets the task snapshot as it is displayed on the screen. * @@ -175,6 +221,22 @@ public class TaskOverlayFactory implements ResourceBasedOverride { R.string.blocked_by_policy, Toast.LENGTH_LONG).show(); } + + private class ScreenshotSystemShortcut extends SystemShortcut { + + private final BaseDraggingActivity mActivity; + + ScreenshotSystemShortcut(BaseDraggingActivity activity, ItemInfo itemInfo) { + super(R.drawable.ic_screenshot, R.string.action_screenshot, activity, itemInfo); + mActivity = activity; + } + + @Override + public void onClick(View view) { + saveScreenshot(mThumbnailView.getTaskView().getTask()); + dismissTaskMenuView(mActivity); + } + } } /** diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskShortcutFactory.java index 3623e671f1..ea1795c032 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskShortcutFactory.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskShortcutFactory.java @@ -18,6 +18,8 @@ package com.android.quickstep; import static android.view.Display.DEFAULT_DISPLAY; +import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS; +import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_SELECTIONS; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_FREE_FORM_TAP; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_SPLIT_SCREEN_TAP; import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.TAP; @@ -332,4 +334,19 @@ public interface TaskShortcutFactory { TaskShortcutFactory WELLBEING = (activity, view) -> WellbeingModel.SHORTCUT_FACTORY.getShortcut(activity, dummyInfo(view)); + + TaskShortcutFactory SCREENSHOT = (activity, tv) -> { + if (ENABLE_OVERVIEW_ACTIONS.get()) { + return tv.getThumbnail().getTaskOverlay() + .getScreenshotShortcut(activity, dummyInfo(tv)); + } + return null; + }; + + TaskShortcutFactory MODAL = (activity, tv) -> { + if (ENABLE_OVERVIEW_ACTIONS.get() && ENABLE_OVERVIEW_SELECTIONS.get()) { + return tv.getThumbnail().getTaskOverlay().getModalStateSystemShortcut(dummyInfo(tv)); + } + return null; + }; } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java index 98784efdc1..1e4a87c4b0 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java @@ -2182,6 +2182,11 @@ public abstract class RecentsView extends PagedView impl if (getCurrentPageTaskView() != null) { getCurrentPageTaskView().setModalness(modalness); } + // Only show actions view when it's modal for in-place landscape mode. + boolean inPlaceLandscape = !mOrientationState.canLauncherRotate() + && mOrientationState.getTouchRotation() != ROTATION_0; + mActionsView.updateHiddenFlags(HIDDEN_NON_ZERO_ROTATION, modalness < 1 && inPlaceLandscape); + LayoutUtils.setViewEnabled(mActionsView, true); } @Nullable diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java index a371dd21ff..26fb563b82 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java @@ -447,6 +447,16 @@ public class TaskThumbnailView extends View implements PluginListener Date: Thu, 28 May 2020 16:55:26 -0700 Subject: [PATCH 12/35] Show discovery tip for hybrid hotseat Doc: go/hybrid-hotseat-tips Issue 157683315: for fully populated hotseat, count returns to home screen and show discovery tip if Tip action was not tapped. Issue 158301717: Don't use cached items if client has predicted items. Test: Manual Change-Id: I4747a1148caa62a6262fb6592d5185bdf216ede6 --- .../hybridhotseat/HotseatEduController.java | 25 ++++---- .../hybridhotseat/HotseatEduDialog.java | 2 + .../HotseatPredictionController.java | 60 ++++++++++++++----- .../uioverrides/QuickstepLauncher.java | 11 +--- quickstep/res/values/strings.xml | 8 ++- .../launcher3/BaseQuickstepLauncher.java | 9 +++ .../util/QuickstepOnboardingPrefs.java | 23 +++++++ res/layout/arrow_toast.xml | 2 + .../launcher3/util/OnboardingPrefs.java | 5 +- 9 files changed, 102 insertions(+), 43 deletions(-) diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java index f1ce72e708..49f3eb8fde 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java @@ -47,12 +47,12 @@ public class HotseatEduController { public static final String KEY_HOTSEAT_EDU_SEEN = "hotseat_edu_seen"; public static final String HOTSEAT_EDU_ACTION = "com.android.launcher3.action.SHOW_HYBRID_HOTSEAT_EDU"; - private static final String SETTINGS_ACTION = + public static final String SETTINGS_ACTION = "android.settings.ACTION_CONTENT_SUGGESTIONS_SETTINGS"; private final Launcher mLauncher; private final Hotseat mHotseat; - private final HotseatRestoreHelper mRestoreHelper; + private HotseatRestoreHelper mRestoreHelper; private List mPredictedApps; private HotseatEduDialog mActiveDialog; @@ -71,14 +71,17 @@ public class HotseatEduController { * Checks what type of migration should be used and migrates hotseat */ void migrate() { - mRestoreHelper.createBackup(); + if (mRestoreHelper != null) { + mRestoreHelper.createBackup(); + } if (FeatureFlags.HOTSEAT_MIGRATE_TO_FOLDER.get()) { migrateToFolder(); } else { migrateHotseatWhole(); } - Snackbar.show(mLauncher, R.string.hotsaet_tip_prediction_enabled, R.string.hotseat_turn_off, - null, () -> mLauncher.startActivity(new Intent(SETTINGS_ACTION))); + Snackbar.show(mLauncher, R.string.hotsaet_tip_prediction_enabled, + R.string.hotseat_prediction_settings, null, + () -> mLauncher.startActivity(new Intent(SETTINGS_ACTION))); } /** @@ -223,15 +226,15 @@ public class HotseatEduController { void finishOnboarding() { mOnOnboardingComplete.run(); - destroy(); mLauncher.getSharedPrefs().edit().putBoolean(KEY_HOTSEAT_EDU_SEEN, true).apply(); } void showDimissTip() { if (mHotseat.getShortcutsAndWidgets().getChildCount() < mLauncher.getDeviceProfile().inv.numHotseatIcons) { - Snackbar.show(mLauncher, R.string.hotseat_tip_gaps_filled, R.string.hotseat_turn_off, - null, () -> mLauncher.startActivity(new Intent(SETTINGS_ACTION))); + Snackbar.show(mLauncher, R.string.hotseat_tip_gaps_filled, + R.string.hotseat_prediction_settings, null, + () -> mLauncher.startActivity(new Intent(SETTINGS_ACTION))); } else { new ArrowTipView(mLauncher).show( mLauncher.getString(R.string.hotseat_tip_no_empty_slots), mHotseat.getTop()); @@ -242,12 +245,6 @@ public class HotseatEduController { mPredictedApps = predictedApps; } - void destroy() { - if (mActiveDialog != null) { - mActiveDialog.setHotseatEduController(null); - } - } - void showEdu() { int childCount = mHotseat.getShortcutsAndWidgets().getChildCount(); CellLayout cellLayout = mLauncher.getWorkspace().getScreenWithId(Workspace.FIRST_SCREEN_ID); diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java index 99cb3b351b..bbc128f5ce 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java @@ -29,6 +29,7 @@ import android.view.View; import android.widget.Button; import android.widget.TextView; +import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.CellLayout; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Insettable; @@ -245,6 +246,7 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable || mHotseatEduController == null) { return; } + AbstractFloatingView.closeAllOpenViews(mLauncher); attachToContainer(); logOnBoardingSeen(); animateOpen(); diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java index bd4d7139e9..27423a5968 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java @@ -17,6 +17,7 @@ package com.android.launcher3.hybridhotseat; import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_GRID; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; +import static com.android.launcher3.hybridhotseat.HotseatEduController.SETTINGS_ACTION; import android.animation.Animator; import android.animation.AnimatorSet; @@ -27,6 +28,7 @@ import android.app.prediction.AppPredictor; import android.app.prediction.AppTarget; import android.app.prediction.AppTargetEvent; import android.content.ComponentName; +import android.content.Intent; import android.util.Log; import android.view.View; import android.view.ViewGroup; @@ -64,6 +66,8 @@ import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.IntArray; +import com.android.launcher3.views.ArrowTipView; +import com.android.launcher3.views.Snackbar; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -107,8 +111,6 @@ public class HotseatPredictionController implements DragController.DragListener, private boolean mIsCacheEmpty; private boolean mIsDestroyed = false; - private HotseatEduController mHotseatEduController; - private List mOutlineDrawings = new ArrayList<>(); @@ -146,11 +148,48 @@ public class HotseatPredictionController implements DragController.DragListener, } /** - * Transitions to NORMAL workspace mode and shows edu + * Shows appropriate hotseat education based on prediction enabled and migration states. */ public void showEdu() { - if (mHotseatEduController == null) return; - mHotseatEduController.showEdu(); + if (mComponentKeyMappers.isEmpty()) { + // launcher has empty predictions set + Snackbar.show(mLauncher, R.string.hotsaet_tip_prediction_disabled, + R.string.hotseat_prediction_settings, null, + () -> mLauncher.startActivity( + new Intent(SETTINGS_ACTION))); + } else if (isEduSeen()) { + // user has already went through education + new ArrowTipView(mLauncher).show( + mLauncher.getString(R.string.hotsaet_tip_prediction_enabled), + mHotseat.getTop()); + } else { + HotseatEduController eduController = new HotseatEduController(mLauncher, mRestoreHelper, + this::createPredictor); + eduController.setPredictedApps(mapToWorkspaceItemInfo(mComponentKeyMappers)); + eduController.showEdu(); + } + } + + /** + * Shows educational tip for hotseat if user does not go through Tips app. + */ + public void showDiscoveryTip() { + if (getPredictedIcons().size() == mHotSeatItemsCount) { + new ArrowTipView(mLauncher).show( + mLauncher.getString(R.string.hotseat_tip_no_empty_slots), mHotseat.getTop()); + } else { + Snackbar.show(mLauncher, R.string.hotseat_tip_gaps_filled, + R.string.hotseat_prediction_settings, null, + () -> mLauncher.startActivity(new Intent(SETTINGS_ACTION))); + } + } + + /** + * Returns if hotseat client has predictions + * @return + */ + public boolean hasPredictions() { + return !mComponentKeyMappers.isEmpty(); } @Override @@ -250,10 +289,6 @@ public class HotseatPredictionController implements DragController.DragListener, if (mAppPredictor != null) { mAppPredictor.destroy(); } - if (mHotseatEduController != null) { - mHotseatEduController.destroy(); - mHotseatEduController = null; - } } /** @@ -299,10 +334,6 @@ public class HotseatPredictionController implements DragController.DragListener, mAppPredictor.requestPredictionUpdate(); }); setPauseUIUpdate(false); - if (!isEduSeen()) { - mHotseatEduController = new HotseatEduController(mLauncher, mRestoreHelper, - this::createPredictor); - } } /** @@ -350,9 +381,6 @@ public class HotseatPredictionController implements DragController.DragListener, if (Utilities.IS_DEBUG_DEVICE) FileLog.d(TAG, predictionLog.toString()); updateDependencies(); fillGapsWithPrediction(); - if (!isEduSeen() && mHotseatEduController != null) { - mHotseatEduController.setPredictedApps(mapToWorkspaceItemInfo(mComponentKeyMappers)); - } cachePredictionComponentKeysIfNecessary(componentKeys); } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index 494a98dcf5..f7d0cd508c 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -88,7 +88,6 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { */ public static final AsyncCommand SET_SHELF_HEIGHT = (context, arg1, arg2) -> SystemUiProxy.INSTANCE.get(context).setShelfHeight(arg1 != 0, arg2); - private HotseatPredictionController mHotseatPredictionController; @Override protected void onCreate(Bundle savedInstanceState) { @@ -168,13 +167,6 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { } } - /** - * Returns Prediction controller for hybrid hotseat - */ - public HotseatPredictionController getHotseatPredictionController() { - return mHotseatPredictionController; - } - /** * Recents logic that triggers when launcher state changes or launcher activity stops/resumes. */ @@ -195,7 +187,8 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { @Override public void bindPredictedItems(List appInfos, IntArray ranks) { super.bindPredictedItems(appInfos, ranks); - if (mHotseatPredictionController != null) { + if (mHotseatPredictionController != null + && !mHotseatPredictionController.hasPredictions()) { mHotseatPredictionController.showCachedItems(appInfos, ranks); } } diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml index a27c127317..1b828268ce 100644 --- a/quickstep/res/values/strings.xml +++ b/quickstep/res/values/strings.xml @@ -76,8 +76,8 @@ No thanks - - Settings + + Settings Most-used apps appear here, and change based on routines @@ -86,7 +86,9 @@ App suggestions added to empty space - App suggestions Enabled + App suggestions enabled + + App suggestions are disabled Predicted app: %1$s diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java index 48743070d8..d2e0339325 100644 --- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java @@ -31,6 +31,7 @@ import android.os.Bundle; import android.os.CancellationSignal; import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.hybridhotseat.HotseatPredictionController; import com.android.launcher3.model.WellbeingModel; import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.proxy.ProxyActivityStarter; @@ -75,6 +76,7 @@ public abstract class BaseQuickstepLauncher extends Launcher private final ShelfPeekAnim mShelfPeekAnim = new ShelfPeekAnim(this); private OverviewActionsView mActionsView; + protected HotseatPredictionController mHotseatPredictionController; @Override protected void onCreate(Bundle savedInstanceState) { @@ -305,6 +307,13 @@ public abstract class BaseQuickstepLauncher extends Launcher return mShelfPeekAnim; } + /** + * Returns Prediction controller for hybrid hotseat + */ + public HotseatPredictionController getHotseatPredictionController() { + return mHotseatPredictionController; + } + public void setHintUserWillBeActive() { addActivityFlags(ACTIVITY_STATE_USER_WILL_BE_ACTIVE); } diff --git a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java index 7e8222c228..1abe903d3d 100644 --- a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java +++ b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java @@ -31,6 +31,7 @@ import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.LauncherState; import com.android.launcher3.Workspace; import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.hybridhotseat.HotseatPredictionController; import com.android.launcher3.statemanager.StateManager; import com.android.launcher3.statemanager.StateManager.StateListener; import com.android.launcher3.util.OnboardingPrefs; @@ -100,6 +101,28 @@ public class QuickstepOnboardingPrefs extends OnboardingPrefs() { + boolean mFromAllApps = false; + + @Override + public void onStateTransitionStart(LauncherState toState) { + mFromAllApps = mLauncher.getStateManager().getCurrentStableState() == ALL_APPS; + } + + @Override + public void onStateTransitionComplete(LauncherState finalState) { + HotseatPredictionController client = mLauncher.getHotseatPredictionController(); + if (mFromAllApps && finalState == NORMAL && client.hasPredictions()) { + if (incrementEventCount(HOTSEAT_DISCOVERY_TIP_COUNT)) { + client.showDiscoveryTip(); + stateManager.removeStateListener(this); + } + } + } + }); + } + if (SysUINavigationMode.getMode(launcher) == NO_BUTTON && FeatureFlags.ENABLE_ALL_APPS_EDU.get()) { stateManager.addStateListener(new StateListener() { diff --git a/res/layout/arrow_toast.xml b/res/layout/arrow_toast.xml index 087e45a4dd..2c97e8954b 100644 --- a/res/layout/arrow_toast.xml +++ b/res/layout/arrow_toast.xml @@ -34,6 +34,8 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" + android:paddingTop="5dp" + android:paddingBottom="5dp" android:gravity="center" android:layout_gravity="center_vertical" android:textColor="@android:color/white" diff --git a/src/com/android/launcher3/util/OnboardingPrefs.java b/src/com/android/launcher3/util/OnboardingPrefs.java index 162028991d..90a1c82661 100644 --- a/src/com/android/launcher3/util/OnboardingPrefs.java +++ b/src/com/android/launcher3/util/OnboardingPrefs.java @@ -37,13 +37,14 @@ public class OnboardingPrefs { public static final String HOME_BOUNCE_COUNT = "launcher.home_bounce_count"; public static final String SHELF_BOUNCE_COUNT = "launcher.shelf_bounce_count"; public static final String ALL_APPS_COUNT = "launcher.all_apps_count"; + public static final String HOTSEAT_DISCOVERY_TIP_COUNT = "launcher.hotseat_discovery_tip_count"; /** * Events that either have happened or have not (booleans). */ @StringDef(value = { HOME_BOUNCE_SEEN, - SHELF_BOUNCE_SEEN, + SHELF_BOUNCE_SEEN }) @Retention(RetentionPolicy.SOURCE) public @interface EventBoolKey {} @@ -55,6 +56,7 @@ public class OnboardingPrefs { HOME_BOUNCE_COUNT, SHELF_BOUNCE_COUNT, ALL_APPS_COUNT, + HOTSEAT_DISCOVERY_TIP_COUNT }) @Retention(RetentionPolicy.SOURCE) public @interface EventCountKey {} @@ -65,6 +67,7 @@ public class OnboardingPrefs { maxCounts.put(HOME_BOUNCE_COUNT, 3); maxCounts.put(SHELF_BOUNCE_COUNT, 3); maxCounts.put(ALL_APPS_COUNT, 5); + maxCounts.put(HOTSEAT_DISCOVERY_TIP_COUNT, 5); MAX_COUNTS = Collections.unmodifiableMap(maxCounts); } From 84f30b213a1f134034f16a172abe7610ca5ac428 Mon Sep 17 00:00:00 2001 From: Vinit Nayak Date: Wed, 10 Jun 2020 18:47:05 -0700 Subject: [PATCH 13/35] Remove unused HomeRotatedPageHandler Transfer functionality of choosing task menu layout to PortraitPageHandler, which is what it should have been to begin with. Fixes: 158484000 Change-Id: Iadda53e7e1f796c063a111823f7f6278f3fdbf58 --- .../QuickstepTestInformationHandler.java | 2 +- .../quickstep/util/RecentsOrientedState.java | 2 +- .../touch/HomeRotatedPageHandler.java | 55 ------------------- .../touch/LandscapePagedViewHandler.java | 13 ----- .../touch/PagedOrientationHandler.java | 2 - .../touch/PortraitPagedViewHandler.java | 15 +---- .../touch/SeascapePagedViewHandler.java | 14 ----- 7 files changed, 3 insertions(+), 100 deletions(-) delete mode 100644 src/com/android/launcher3/touch/HomeRotatedPageHandler.java diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java index a28dabc6a3..ebc83c6bad 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java @@ -37,7 +37,7 @@ public class QuickstepTestInformationHandler extends TestInformationHandler { case TestProtocol.REQUEST_BACKGROUND_TO_OVERVIEW_SWIPE_HEIGHT: { final float swipeHeight = LayoutUtils.getShelfTrackingDistance(mContext, mDeviceProfile, - PagedOrientationHandler.HOME_ROTATED); + PagedOrientationHandler.PORTRAIT); response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, (int) swipeHeight); return response; } diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java index 7715cca60f..0d6fbeed57 100644 --- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java +++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java @@ -197,7 +197,7 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre mPreviousRotation = touchRotation; if (mLauncherRotation == mTouchRotation || canLauncherRotate()) { - mOrientationHandler = PagedOrientationHandler.HOME_ROTATED; + mOrientationHandler = PagedOrientationHandler.PORTRAIT; if (DEBUG) { Log.d(TAG, "current RecentsOrientedState: " + this); } diff --git a/src/com/android/launcher3/touch/HomeRotatedPageHandler.java b/src/com/android/launcher3/touch/HomeRotatedPageHandler.java deleted file mode 100644 index db5c659e04..0000000000 --- a/src/com/android/launcher3/touch/HomeRotatedPageHandler.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.launcher3.touch; - -import android.graphics.RectF; -import android.view.Surface; -import android.widget.LinearLayout; - -public class HomeRotatedPageHandler extends PortraitPagedViewHandler { - @Override - public void offsetTaskRect(RectF rect, float value, int displayRotation, int launcherRotation) { - if (launcherRotation == Surface.ROTATION_0) { - super.offsetTaskRect(rect, value, displayRotation, launcherRotation); - } else if (launcherRotation == Surface.ROTATION_90) { - if (displayRotation == Surface.ROTATION_0) { - rect.offset(0, value); - } else if (displayRotation == Surface.ROTATION_90) { - rect.offset(value, 0); - } else if (displayRotation == Surface.ROTATION_180) { - rect.offset(-value, 0); - } else { - rect.offset(-value, 0); - } - } else if (launcherRotation == Surface.ROTATION_270) { - if (displayRotation == Surface.ROTATION_0) { - rect.offset(0, -value); - } else if (displayRotation == Surface.ROTATION_90) { - rect.offset(value, 0); - } else if (displayRotation == Surface.ROTATION_180) { - rect.offset(0, -value); - } else { - rect.offset(value, 0); - } - } // TODO (b/149609488) handle 180 case as well - } - - @Override - public int getTaskMenuLayoutOrientation(LinearLayout taskMenuLayout) { - return taskMenuLayout.getOrientation(); - } -} diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java index d02c731de3..48c773413f 100644 --- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java +++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java @@ -180,19 +180,6 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler { return Surface.ROTATION_90; } - @Override - public void offsetTaskRect(RectF rect, float value, int displayRotation, int launcherRotation) { - if (displayRotation == Surface.ROTATION_0) { - rect.offset(0, value); - } else if (displayRotation == Surface.ROTATION_90) { - rect.offset(value, 0); - } else if (displayRotation == Surface.ROTATION_180) { - rect.offset(0, -value); - } else { - rect.offset(-value, 0); - } - } - @Override public int getChildStart(View view) { return view.getTop(); diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java index 2e0268dc79..65b1a7a77e 100644 --- a/src/com/android/launcher3/touch/PagedOrientationHandler.java +++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java @@ -43,7 +43,6 @@ public interface PagedOrientationHandler { PagedOrientationHandler PORTRAIT = new PortraitPagedViewHandler(); PagedOrientationHandler LANDSCAPE = new LandscapePagedViewHandler(); PagedOrientationHandler SEASCAPE = new SeascapePagedViewHandler(); - PagedOrientationHandler HOME_ROTATED = new HomeRotatedPageHandler(); interface Int2DAction { void call(T target, int x, int y); @@ -82,7 +81,6 @@ public interface PagedOrientationHandler { boolean getRecentsRtlSetting(Resources resources); float getDegreesRotated(); int getRotation(); - void offsetTaskRect(RectF rect, float value, int delta, int launcherRotation); int getPrimaryValue(int x, int y); int getSecondaryValue(int x, int y); void delegateScrollTo(PagedView pagedView, int secondaryScroll, int primaryScroll); diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java index 2fc7a9f40e..79e5c87785 100644 --- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java +++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java @@ -178,19 +178,6 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler { return Surface.ROTATION_0; } - @Override - public void offsetTaskRect(RectF rect, float value, int displayRotation, int launcherRotation) { - if (displayRotation == Surface.ROTATION_0) { - rect.offset(value, 0); - } else if (displayRotation == Surface.ROTATION_90) { - rect.offset(0, -value); - } else if (displayRotation == Surface.ROTATION_180) { - rect.offset(-value, 0); - } else { - rect.offset(0, value); - } - } - @Override public int getChildStart(View view) { return view.getLeft(); @@ -250,7 +237,7 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler { @Override public int getTaskMenuLayoutOrientation(LinearLayout taskMenuLayout) { - return LinearLayout.VERTICAL; + return taskMenuLayout.getOrientation(); } @Override diff --git a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java index 4c1700ee9a..d5ae2dcb16 100644 --- a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java +++ b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java @@ -18,7 +18,6 @@ package com.android.launcher3.touch; import android.content.res.Resources; import android.graphics.PointF; -import android.graphics.RectF; import android.view.Surface; import android.view.View; @@ -41,19 +40,6 @@ public class SeascapePagedViewHandler extends LandscapePagedViewHandler { return Utilities.isRtl(resources); } - @Override - public void offsetTaskRect(RectF rect, float value, int displayRotation, int launcherRotation) { - if (displayRotation == Surface.ROTATION_0) { - rect.offset(0, value); - } else if (displayRotation == Surface.ROTATION_90) { - rect.offset(value, 0); - } else if (displayRotation == Surface.ROTATION_180) { - rect.offset(0, -value); - } else { - rect.offset(-value, 0); - } - } - @Override public float getDegreesRotated() { return 270; From de52876a2bc66f31dd26e2c786ffbc56ec85a341 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 10 Jun 2020 12:19:25 -0700 Subject: [PATCH 14/35] Fixing sysui visibility changing multiple times on startup > During startup shelftop is updated after all-apps, causing all-apps to set the sysuiVisibility according to it's own UI Bug: 156422012 Change-Id: Idee06249ad45946ed0a9dc84702510ad90a305f4 --- .../quickstep/views/ShelfScrimView.java | 14 +++++++ .../allapps/AllAppsTransitionController.java | 14 ------- .../launcher3/util/SystemUiController.java | 41 ++++++++++++------- .../android/launcher3/views/ScrimView.java | 17 +++++++- 4 files changed, 57 insertions(+), 29 deletions(-) diff --git a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java index f5498c9961..bec3050dad 100644 --- a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java +++ b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java @@ -23,6 +23,7 @@ import static com.android.launcher3.anim.Interpolators.ACCEL; import static com.android.launcher3.anim.Interpolators.ACCEL_2; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound; +import static com.android.launcher3.util.SystemUiController.UI_STATE_SCRIM_VIEW; import android.content.Context; import android.graphics.Canvas; @@ -187,6 +188,7 @@ public class ShelfScrimView extends ScrimView mShelfTopAtThreshold = mShiftRange * SCRIM_CATCHUP_THRESHOLD + mTopOffset; } updateColors(); + updateSysUiColors(); updateDragHandleAlpha(); invalidate(); } @@ -240,6 +242,18 @@ public class ShelfScrimView extends ScrimView } } + @Override + protected void updateSysUiColors() { + // Use a light system UI (dark icons) if all apps is behind at least half of the + // status bar. + boolean forceChange = mShelfTop <= mLauncher.getDeviceProfile().getInsets().top / 2f; + if (forceChange) { + mLauncher.getSystemUiController().updateUiState(UI_STATE_SCRIM_VIEW, !mIsScrimDark); + } else { + mLauncher.getSystemUiController().updateUiState(UI_STATE_SCRIM_VIEW, 0); + } + } + @Override protected boolean shouldDragHandleBeVisible() { boolean needsAllAppsEdu = mIsTwoZoneSwipeModel diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java index 99ed0ad52b..e786ad18fa 100644 --- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java +++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java @@ -14,7 +14,6 @@ import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FA import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_HEADER_FADE; import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE; import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS; -import static com.android.launcher3.util.SystemUiController.UI_STATE_ALL_APPS; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -37,7 +36,6 @@ import com.android.launcher3.anim.PropertySetter; import com.android.launcher3.statemanager.StateManager.StateHandler; import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper; -import com.android.launcher3.util.Themes; import com.android.launcher3.views.ScrimView; import com.android.systemui.plugins.AllAppsSearchPlugin; import com.android.systemui.plugins.PluginListener; @@ -75,7 +73,6 @@ public class AllAppsTransitionController implements StateHandler, private ScrimView mScrimView; private final Launcher mLauncher; - private final boolean mIsDarkTheme; private boolean mIsVerticalLayout; // Animation in this class is controlled by a single variable {@link mProgress}. @@ -98,7 +95,6 @@ public class AllAppsTransitionController implements StateHandler, mShiftRange = mLauncher.getDeviceProfile().heightPx; mProgress = 1f; - mIsDarkTheme = Themes.getAttrBoolean(mLauncher, R.attr.isMainColorDark); mIsVerticalLayout = mLauncher.getDeviceProfile().isVerticalBarLayout(); mLauncher.addOnDeviceProfileChangeListener(this); } @@ -137,16 +133,6 @@ public class AllAppsTransitionController implements StateHandler, if (mPlugin != null) { mPlugin.setProgress(progress); } - - // Use a light system UI (dark icons) if all apps is behind at least half of the - // status bar. - boolean forceChange = Math.min(shiftCurrent, mScrimView.getVisualTop()) - <= mLauncher.getDeviceProfile().getInsets().top / 2f; - if (forceChange) { - mLauncher.getSystemUiController().updateUiState(UI_STATE_ALL_APPS, !mIsDarkTheme); - } else { - mLauncher.getSystemUiController().updateUiState(UI_STATE_ALL_APPS, 0); - } } public float getProgress() { diff --git a/src/com/android/launcher3/util/SystemUiController.java b/src/com/android/launcher3/util/SystemUiController.java index 53cc157682..275c0246e2 100644 --- a/src/com/android/launcher3/util/SystemUiController.java +++ b/src/com/android/launcher3/util/SystemUiController.java @@ -30,7 +30,7 @@ public class SystemUiController { // Various UI states in increasing order of priority public static final int UI_STATE_BASE_WINDOW = 0; - public static final int UI_STATE_ALL_APPS = 1; + public static final int UI_STATE_SCRIM_VIEW = 1; public static final int UI_STATE_WIDGET_BOTTOM_SHEET = 2; public static final int UI_STATE_OVERVIEW = 3; @@ -61,25 +61,38 @@ public class SystemUiController { // Apply the state flags in priority order int newFlags = oldFlags; for (int stateFlag : mStates) { - if (Utilities.ATLEAST_OREO) { - if ((stateFlag & FLAG_LIGHT_NAV) != 0) { - newFlags |= View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; - } else if ((stateFlag & FLAG_DARK_NAV) != 0) { - newFlags &= ~(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR); - } - } - - if ((stateFlag & FLAG_LIGHT_STATUS) != 0) { - newFlags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; - } else if ((stateFlag & FLAG_DARK_STATUS) != 0) { - newFlags &= ~(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); - } + newFlags = getSysUiVisibilityFlags(stateFlag, newFlags); } if (newFlags != oldFlags) { mWindow.getDecorView().setSystemUiVisibility(newFlags); } } + /** + * Returns the sysui visibility for the base layer + */ + public int getBaseSysuiVisibility() { + return getSysUiVisibilityFlags( + mStates[UI_STATE_BASE_WINDOW], mWindow.getDecorView().getSystemUiVisibility()); + } + + private int getSysUiVisibilityFlags(int stateFlag, int currentVisibility) { + if (Utilities.ATLEAST_OREO) { + if ((stateFlag & FLAG_LIGHT_NAV) != 0) { + currentVisibility |= View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; + } else if ((stateFlag & FLAG_DARK_NAV) != 0) { + currentVisibility &= ~(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR); + } + } + + if ((stateFlag & FLAG_LIGHT_STATUS) != 0) { + currentVisibility |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; + } else if ((stateFlag & FLAG_DARK_STATUS) != 0) { + currentVisibility &= ~(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); + } + return currentVisibility; + } + @Override public String toString() { return "mStates=" + Arrays.toString(mStates); diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java index a2c7d14d52..22faf97cc4 100644 --- a/src/com/android/launcher3/views/ScrimView.java +++ b/src/com/android/launcher3/views/ScrimView.java @@ -27,6 +27,7 @@ import static com.android.launcher3.anim.Interpolators.DEACCEL; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.anim.Interpolators.clampToProgress; import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound; +import static com.android.launcher3.util.SystemUiController.UI_STATE_SCRIM_VIEW; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -53,6 +54,7 @@ import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeL import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.graphics.ColorUtils; import androidx.core.view.ViewCompat; import androidx.core.view.accessibility.AccessibilityNodeInfoCompat; import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat; @@ -77,7 +79,6 @@ import com.android.launcher3.widget.WidgetsFullSheet; import java.util.List; - /** * Simple scrim which draws a flat color */ @@ -115,6 +116,7 @@ public class ScrimView extends View implements Insettable, O private final WallpaperColorInfo mWallpaperColorInfo; private final AccessibilityManager mAM; protected final int mEndScrim; + protected final boolean mIsScrimDark; private final StateListener mAccessibilityLauncherStateListener = new StateListener() { @@ -156,6 +158,7 @@ public class ScrimView extends View implements Insettable, O mLauncher = Launcher.cast(Launcher.getLauncher(context)); mWallpaperColorInfo = WallpaperColorInfo.INSTANCE.get(context); mEndScrim = Themes.getAttrColor(context, R.attr.allAppsScrimColor); + mIsScrimDark = ColorUtils.calculateLuminance(mEndScrim) < 0.5f; mMaxScrimAlpha = 0.7f; @@ -233,6 +236,7 @@ public class ScrimView extends View implements Insettable, O mProgress = progress; stopDragHandleEducationAnim(); updateColors(); + updateSysUiColors(); updateDragHandleAlpha(); invalidate(); } @@ -245,6 +249,17 @@ public class ScrimView extends View implements Insettable, O mEndFlatColor, Math.round((1 - mProgress) * mEndFlatColorAlpha)); } + protected void updateSysUiColors() { + // Use a light system UI (dark icons) if all apps is behind at least half of the + // status bar. + boolean forceChange = mProgress <= 0.1f; + if (forceChange) { + mLauncher.getSystemUiController().updateUiState(UI_STATE_SCRIM_VIEW, !mIsScrimDark); + } else { + mLauncher.getSystemUiController().updateUiState(UI_STATE_SCRIM_VIEW, 0); + } + } + protected void updateDragHandleAlpha() { if (mDragHandle != null) { mDragHandle.setAlpha(mDragHandleAlpha); From 6fd62fde9184cfaee85abd9ab6bc7a2c57f879ab Mon Sep 17 00:00:00 2001 From: Samuel Fufa Date: Tue, 9 Jun 2020 18:10:31 -0700 Subject: [PATCH 15/35] Migrate Hotseat logging to WW Bug: 158218197 Change-Id: I77743b78593f169ffc30f91ab9963052417dac23 --- .../hybridhotseat/HotseatEduController.java | 4 ++ .../hybridhotseat/HotseatEduDialog.java | 50 +++---------------- .../HotseatPredictionController.java | 8 ++- .../uioverrides/QuickstepLauncher.java | 3 +- .../launcher3/logging/StatsLogManager.java | 15 +++++- 5 files changed, 31 insertions(+), 49 deletions(-) diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java index 49f3eb8fde..5d807d33f8 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java @@ -15,6 +15,9 @@ */ package com.android.launcher3.hybridhotseat; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent + .LAUNCHER_HOTSEAT_EDU_ONLY_TIP; + import android.content.Intent; import android.view.View; @@ -262,6 +265,7 @@ public class HotseatEduController { requiresMigration ? R.string.hotseat_tip_no_empty_slots : R.string.hotseat_auto_enrolled), mHotseat.getTop()); + mLauncher.getStatsLogManager().log(LAUNCHER_HOTSEAT_EDU_ONLY_TIP); finishOnboarding(); } } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java index bbc128f5ce..96be5dfe11 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java @@ -15,9 +15,10 @@ */ package com.android.launcher3.hybridhotseat; -import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent; -import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType - .HYBRID_HOTSEAT_CANCELED; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent + .LAUNCHER_HOTSEAT_EDU_ACCEPT; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOTSEAT_EDU_DENY; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOTSEAT_EDU_SEEN; import android.animation.PropertyValuesHolder; import android.content.Context; @@ -35,10 +36,8 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.Insettable; import com.android.launcher3.Launcher; import com.android.launcher3.R; -import com.android.launcher3.Workspace; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.config.FeatureFlags; -import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.uioverrides.PredictedAppIcon; import com.android.launcher3.userevent.nano.LauncherLogProto; @@ -113,15 +112,13 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable mHotseatEduController.moveHotseatItems(); mHotseatEduController.finishOnboarding(); - //TODO: pass actual page index here. - // Temporarily we're passing 1 for folder migration and 2 for page migration - logUserAction(true, FeatureFlags.HOTSEAT_MIGRATE_TO_FOLDER.get() ? 1 : 2); + mLauncher.getStatsLogManager().log(LAUNCHER_HOTSEAT_EDU_ACCEPT); } private void onDismiss(View v) { mHotseatEduController.showDimissTip(); mHotseatEduController.finishOnboarding(); - logUserAction(false, -1); + mLauncher.getStatsLogManager().log(LAUNCHER_HOTSEAT_EDU_DENY); handleClose(true); } @@ -165,39 +162,6 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable } } - private void logUserAction(boolean migrated, int pageIndex) { - LauncherLogProto.Action action = new LauncherLogProto.Action(); - LauncherLogProto.Target target = new LauncherLogProto.Target(); - - int hotseatItemsCount = mLauncher.getHotseat().getShortcutsAndWidgets().getChildCount(); - // -1 to exclude smart space - int workspaceItemCount = mLauncher.getWorkspace().getScreenWithId( - Workspace.FIRST_SCREEN_ID).getShortcutsAndWidgets().getChildCount() - 1; - - action.type = LauncherLogProto.Action.Type.TOUCH; - action.touch = LauncherLogProto.Action.Touch.TAP; - target.containerType = LauncherLogProto.ContainerType.TIP; - target.tipType = LauncherLogProto.TipType.HYBRID_HOTSEAT; - target.controlType = migrated ? LauncherLogProto.ControlType.HYBRID_HOTSEAT_ACCEPTED - : HYBRID_HOTSEAT_CANCELED; - target.rank = MIGRATION_EXPERIMENT_IDENTIFIER; - // encoding migration type on pageIndex - target.pageIndex = pageIndex; - target.cardinality = (workspaceItemCount * 1000) + hotseatItemsCount; - LauncherLogProto.LauncherEvent event = newLauncherEvent(action, target); - UserEventDispatcher.newInstance(getContext()).dispatchUserEvent(event, null); - } - - private void logOnBoardingSeen() { - LauncherLogProto.Action action = new LauncherLogProto.Action(); - LauncherLogProto.Target target = new LauncherLogProto.Target(); - action.type = LauncherLogProto.Action.Type.TIP; - target.containerType = LauncherLogProto.ContainerType.TIP; - target.tipType = LauncherLogProto.TipType.HYBRID_HOTSEAT; - LauncherLogProto.LauncherEvent event = newLauncherEvent(action, target); - UserEventDispatcher.newInstance(getContext()).dispatchUserEvent(event, null); - } - private void animateOpen() { if (mIsOpen || mOpenCloseAnimator.isRunning()) { return; @@ -248,7 +212,7 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable } AbstractFloatingView.closeAllOpenViews(mLauncher); attachToContainer(); - logOnBoardingSeen(); + mLauncher.getStatsLogManager().log(LAUNCHER_HOTSEAT_EDU_SEEN); animateOpen(); populatePreview(predictions); } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java index 27423a5968..63cc3a0cb8 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java @@ -339,11 +339,15 @@ public class HotseatPredictionController implements DragController.DragListener, /** * Create WorkspaceItemInfo objects and binds PredictedAppIcon views for cached predicted items. */ - public void showCachedItems(List apps, IntArray ranks) { + public void showCachedItems(List apps, IntArray ranks) { + if (hasPredictions() && mAppPredictor != null) { + mAppPredictor.requestPredictionUpdate(); + fillGapsWithPrediction(); + return; + } mIsCacheEmpty = apps.isEmpty(); int count = Math.min(ranks.size(), apps.size()); List items = new ArrayList<>(count); - mComponentKeyMappers.clear(); for (int i = 0; i < count; i++) { WorkspaceItemInfo item = new WorkspaceItemInfo(apps.get(i)); ComponentKey componentKey = new ComponentKey(item.getTargetComponent(), item.user); diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index f7d0cd508c..3b45ec955d 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -187,8 +187,7 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { @Override public void bindPredictedItems(List appInfos, IntArray ranks) { super.bindPredictedItems(appInfos, ranks); - if (mHotseatPredictionController != null - && !mHotseatPredictionController.hasPredictions()) { + if (mHotseatPredictionController != null) { mHotseatPredictionController.showCachedItems(appInfos, ranks); } } diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java index 6af0eefe11..ce70a3225f 100644 --- a/src/com/android/launcher3/logging/StatsLogManager.java +++ b/src/com/android/launcher3/logging/StatsLogManager.java @@ -130,9 +130,20 @@ public class StatsLogManager implements ResourceBasedOverride { LAUNCHER_ALL_APPS_EDU_SHOWN(523), @UiEvent(doc = "User opened a folder.") - LAUNCHER_FOLDER_OPEN(551); - // ADD MORE + LAUNCHER_FOLDER_OPEN(551), + @UiEvent(doc = "Hotseat education half sheet seen") + LAUNCHER_HOTSEAT_EDU_SEEN(479), + + @UiEvent(doc = "Hotseat migration accepted") + LAUNCHER_HOTSEAT_EDU_ACCEPT(480), + + @UiEvent(doc = "Hotseat migration denied") + LAUNCHER_HOTSEAT_EDU_DENY(481), + + @UiEvent(doc = "Hotseat education tip shown") + LAUNCHER_HOTSEAT_EDU_ONLY_TIP(482); + // ADD MORE private final int mId; LauncherEvent(int id) { From da727bbb9879b2ab02a6592841356911a5558aed Mon Sep 17 00:00:00 2001 From: Sreyas Date: Tue, 9 Jun 2020 20:28:52 -0700 Subject: [PATCH 16/35] Adding tooltip for Select button. Change-Id: I3a09d20b6dd26e81b8a010e2d2da52c52408e845 --- res/layout/arrow_toast.xml | 3 +- .../android/launcher3/views/ArrowTipView.java | 28 +++++++++++++++++-- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/res/layout/arrow_toast.xml b/res/layout/arrow_toast.xml index 2c97e8954b..0ec9981220 100644 --- a/res/layout/arrow_toast.xml +++ b/res/layout/arrow_toast.xml @@ -60,6 +60,5 @@ android:elevation="2dp" android:layout_width="10dp" android:layout_height="8dp" - android:layout_marginTop="-2dp" - android:layout_gravity="center_horizontal"/> + android:layout_marginTop="-2dp"/> diff --git a/src/com/android/launcher3/views/ArrowTipView.java b/src/com/android/launcher3/views/ArrowTipView.java index a7575d12ba..b4a6b141ce 100644 --- a/src/com/android/launcher3/views/ArrowTipView.java +++ b/src/com/android/launcher3/views/ArrowTipView.java @@ -125,11 +125,35 @@ public class ArrowTipView extends AbstractFloatingView { * Show Tip with specified string and Y location */ public ArrowTipView show(String text, int top) { + return show(text, Gravity.CENTER_HORIZONTAL, 0, top); + } + + /** + * Show the ArrowTipView (tooltip) center, start, or end aligned. + * + * @param text The text to be shown in the tooltip. + * @param gravity The gravity aligns the tooltip center, start, or end. + * @param arrowMarginStart The margin from start to place arrow (ignored if center) + * @param top The Y coordinate of the bottom of tooltip. + * @return The tooltip. + */ + public ArrowTipView show(String text, int gravity, int arrowMarginStart, int top) { ((TextView) findViewById(R.id.text)).setText(text); - mActivity.getDragLayer().addView(this); + ViewGroup parent = mActivity.getDragLayer(); + parent.addView(this); DragLayer.LayoutParams params = (DragLayer.LayoutParams) getLayoutParams(); - params.gravity = Gravity.CENTER_HORIZONTAL; + params.gravity = gravity; + LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) findViewById( + R.id.arrow).getLayoutParams(); + lp.gravity = gravity; + if (gravity == Gravity.END) { + lp.setMarginEnd(parent.getMeasuredWidth() - arrowMarginStart); + } else if (gravity == Gravity.START) { + lp.setMarginStart(arrowMarginStart); + } + requestLayout(); + params.leftMargin = mActivity.getDeviceProfile().workspacePadding.left; params.rightMargin = mActivity.getDeviceProfile().workspacePadding.right; post(() -> setY(top - getHeight())); From 852145c9b51ee1866a648fca39ff0439abdea961 Mon Sep 17 00:00:00 2001 From: Samuel Fufa Date: Thu, 11 Jun 2020 13:51:37 -0700 Subject: [PATCH 17/35] Reduce launcher logs in bugreports Bug: 158216867 Test: Manual Change-Id: I068550f2c0b233d5c7a6c4685efb36b62ced5dde --- .../PredictionUiStateManager.java | 14 ++ .../hybridhotseat/HotseatFileLog.java | 129 ++++++++++++++++++ .../HotseatPredictionController.java | 5 +- .../logging/UserEventDispatcher.java | 9 -- 4 files changed, 146 insertions(+), 11 deletions(-) create mode 100644 quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatFileLog.java diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java index b6a8206ef0..f881610b77 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java @@ -23,6 +23,7 @@ import android.app.prediction.AppPredictor; import android.app.prediction.AppTarget; import android.content.ComponentName; import android.content.Context; +import android.os.Process; import androidx.annotation.NonNull; @@ -35,6 +36,7 @@ import com.android.launcher3.LauncherState; import com.android.launcher3.Utilities; import com.android.launcher3.allapps.AllAppsContainerView; import com.android.launcher3.allapps.AllAppsStore.OnUpdateListener; +import com.android.launcher3.hybridhotseat.HotseatFileLog; import com.android.launcher3.hybridhotseat.HotseatPredictionController; import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver; import com.android.launcher3.model.data.ItemInfo; @@ -310,6 +312,18 @@ public class PredictionUiStateManager implements StateListener, */ public static void fillInPredictedRank( @NonNull ItemInfo itemInfo, @NonNull LauncherLogProto.Target target) { + + HotseatFileLog hotseatFileLog = HotseatFileLog.INSTANCE.getNoCreate(); + + if (hotseatFileLog != null && itemInfo != null && Utilities.IS_DEBUG_DEVICE) { + final String pkg = itemInfo.getTargetComponent() != null + ? itemInfo.getTargetComponent().getPackageName() : "unknown"; + hotseatFileLog.log("UserEvent", + "appLaunch: packageName:" + pkg + ",isWorkApp:" + (itemInfo.user != null + && !Process.myUserHandle().equals(itemInfo.user)) + + ",launchLocation:" + itemInfo.container); + } + final PredictionUiStateManager manager = PredictionUiStateManager.INSTANCE.getNoCreate(); if (manager == null || itemInfo.getTargetComponent() == null || itemInfo.user == null || (itemInfo.itemType != LauncherSettings.Favorites.ITEM_TYPE_APPLICATION diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatFileLog.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatFileLog.java new file mode 100644 index 0000000000..c15a5963f6 --- /dev/null +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatFileLog.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher3.hybridhotseat; + +import android.content.Context; +import android.os.Handler; +import android.util.Log; + +import com.android.launcher3.logging.FileLog; +import com.android.launcher3.util.Executors; +import com.android.launcher3.util.MainThreadInitializedObject; + +import java.io.File; +import java.io.FileWriter; +import java.io.PrintWriter; +import java.text.DateFormat; +import java.util.Calendar; +import java.util.Date; + +/** + * Helper class to allow hot seat file logging + */ +public class HotseatFileLog { + + public static final int LOG_DAYS = 10; + private static final String FILE_NAME_PREFIX = "hotseat-log-"; + private static final DateFormat DATE_FORMAT = + DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT); + public static final MainThreadInitializedObject INSTANCE = + new MainThreadInitializedObject<>(HotseatFileLog::new); + + + private final Handler mHandler = new Handler( + Executors.createAndStartNewLooper("hotseat-logger")); + private final File mLogsDir; + private PrintWriter mCurrentWriter; + private String mFileName; + + private HotseatFileLog(Context context) { + mLogsDir = context.getFilesDir(); + } + + /** + * Prints log values to disk + */ + public void log(String tag, String msg) { + String out = String.format("%s %s %s", DATE_FORMAT.format(new Date()), tag, msg); + + mHandler.post(() -> { + synchronized (this) { + PrintWriter writer = getWriter(); + if (writer != null) { + writer.println(out); + } + } + }); + } + + private PrintWriter getWriter() { + String fName = FILE_NAME_PREFIX + (LOG_DAYS % 10); + if (fName.equals(mFileName)) return mCurrentWriter; + + Calendar cal = Calendar.getInstance(); + + boolean append = false; + File logFile = new File(mLogsDir, fName); + if (logFile.exists()) { + Calendar modifiedTime = Calendar.getInstance(); + modifiedTime.setTimeInMillis(logFile.lastModified()); + + // If the file was modified more that 36 hours ago, purge the file. + // We use instead of 24 to account for day-365 followed by day-1 + modifiedTime.add(Calendar.HOUR, 36); + append = cal.before(modifiedTime); + } + + + if (mCurrentWriter != null) { + mCurrentWriter.close(); + } + try { + mCurrentWriter = new PrintWriter(new FileWriter(logFile, append)); + mFileName = fName; + } catch (Exception ex) { + Log.e("HotseatLogs", "Error writing logs to file", ex); + closeWriter(); + } + return mCurrentWriter; + } + + + private synchronized void closeWriter() { + mFileName = null; + if (mCurrentWriter != null) { + mCurrentWriter.close(); + } + mCurrentWriter = null; + } + + + /** + * Returns a list of all log files + */ + public synchronized File[] getLogFiles() { + File[] files = new File[LOG_DAYS + FileLog.LOG_DAYS]; + //include file log files here + System.arraycopy(FileLog.getLogFiles(), 0, files, 0, FileLog.LOG_DAYS); + + closeWriter(); + for (int i = 0; i < LOG_DAYS; i++) { + files[FileLog.LOG_DAYS + i] = new File(mLogsDir, FILE_NAME_PREFIX + i); + } + return files; + } +} diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java index 27423a5968..43cc865bfb 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java @@ -52,7 +52,6 @@ import com.android.launcher3.appprediction.DynamicItemCache; import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.icons.IconCache; -import com.android.launcher3.logging.FileLog; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; @@ -378,7 +377,9 @@ public class HotseatPredictionController implements DragController.DragListener, mComponentKeyMappers.add(new ComponentKeyMapper(key, mDynamicItemCache)); } predictionLog.append("]"); - if (Utilities.IS_DEBUG_DEVICE) FileLog.d(TAG, predictionLog.toString()); + if (Utilities.IS_DEBUG_DEVICE) { + HotseatFileLog.INSTANCE.get(mLauncher).log(TAG, predictionLog.toString()); + } updateDependencies(); fillGapsWithPrediction(); cachePredictionComponentKeysIfNecessary(componentKeys); diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java index 7818ff55fd..e094cab82f 100644 --- a/src/com/android/launcher3/logging/UserEventDispatcher.java +++ b/src/com/android/launcher3/logging/UserEventDispatcher.java @@ -48,7 +48,6 @@ import androidx.annotation.Nullable; import com.android.launcher3.DropTarget; import com.android.launcher3.R; import com.android.launcher3.Utilities; -import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.userevent.LauncherLogProto; @@ -143,14 +142,6 @@ public class UserEventDispatcher implements ResourceBasedOverride { fillIntentInfo(itemTarget, intent, userHandle); } LauncherEvent event = newLauncherEvent(action, targets); - ItemInfo info = v == null ? null : (ItemInfo) v.getTag(); - if (info != null && Utilities.IS_DEBUG_DEVICE && FeatureFlags.ENABLE_HYBRID_HOTSEAT.get()) { - final String pkg = info.getTargetComponent() != null - ? info.getTargetComponent().getPackageName() : "unknown"; - FileLog.d(TAG, "appLaunch: packageName:" + pkg - + ",isWorkApp:" + (info.user != null && !Process.myUserHandle().equals( - userHandle)) + ",launchLocation:" + info.container); - } dispatchUserEvent(event, intent); mAppOrTaskLaunch = true; } From adbe9b60752cd463a1c31d15a6d122621c1cb6ab Mon Sep 17 00:00:00 2001 From: Samuel Fufa Date: Thu, 11 Jun 2020 15:15:02 -0700 Subject: [PATCH 18/35] ADD NPE check before shortcut key creation. Bug: 156871815 Change-Id: I88132a51f80062eaa76da5838d20c5fe93224635 --- src/com/android/launcher3/Utilities.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index 8e33406ed5..bf637886b7 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -606,6 +606,7 @@ public final class Utilities { outObj[0] = activityInfo; return activityInfo.getFullResIcon(appState.getIconCache()); } + if (info.getIntent() == null || info.getIntent().getPackage() == null) return null; List si = ShortcutKey.fromItemInfo(info) .buildRequest(launcher) .query(ShortcutRequest.ALL); From 13c2bc7303361af51b026a217788cccfb87b4180 Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Wed, 10 Jun 2020 00:35:35 -0700 Subject: [PATCH 19/35] LAUNCHER_APP_LAUNCH_TAP should log correctly for icons inside folder Bug: 137777105 Change-Id: I5c1552481fc1b788ba41c57bfe97f126f55e5b16 --- protos/launcher_atom.proto | 4 + .../quickstep/TaskShortcutFactory.java | 44 ++----- .../android/quickstep/views/RecentsView.java | 4 +- .../com/android/quickstep/views/TaskView.java | 25 ++-- .../logging/StatsLogCompatManager.java | 123 +++++++++--------- .../launcher3/BaseDraggingActivity.java | 2 +- .../android/launcher3/LauncherSettings.java | 7 + src/com/android/launcher3/Workspace.java | 15 +-- src/com/android/launcher3/folder/Folder.java | 4 +- .../android/launcher3/folder/FolderIcon.java | 2 +- .../launcher3/logging/StatsLogManager.java | 31 +++-- .../launcher3/model/data/ItemInfo.java | 14 ++ .../notification/NotificationInfo.java | 2 +- .../launcher3/popup/RemoteActionShortcut.java | 2 +- .../launcher3/popup/SystemShortcut.java | 7 +- 15 files changed, 144 insertions(+), 142 deletions(-) diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto index 7e8e51e100..d1185bd5bc 100644 --- a/protos/launcher_atom.proto +++ b/protos/launcher_atom.proto @@ -54,6 +54,7 @@ message ContainerInfo { ShortcutsContainer shortcuts_container = 8; SettingsContainer settings_container = 9; PredictedHotseatContainer predicted_hotseat_container = 10; + TaskSwitcherContainer task_switcher_container = 11; } } @@ -82,6 +83,9 @@ message ShortcutsContainer { message SettingsContainer { } +message TaskSwitcherContainer { +} + enum Attribute { UNKNOWN = 0; DEFAULT_LAYOUT = 1; // icon automatically placed in workspace, folder, hotseat diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskShortcutFactory.java index ea1795c032..4eae437f8d 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskShortcutFactory.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskShortcutFactory.java @@ -26,23 +26,18 @@ import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch import android.app.Activity; import android.app.ActivityOptions; -import android.content.ComponentName; -import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.Rect; import android.os.Handler; import android.os.Looper; -import android.os.UserHandle; import android.view.View; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; -import com.android.launcher3.logger.LauncherAtom; import com.android.launcher3.logging.StatsLogManager.LauncherEvent; import com.android.launcher3.model.WellbeingModel; -import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.popup.SystemShortcut.AppInfo; import com.android.launcher3.userevent.nano.LauncherLogProto; @@ -71,28 +66,7 @@ public interface TaskShortcutFactory { SystemShortcut getShortcut(BaseDraggingActivity activity, TaskView view); - static WorkspaceItemInfo dummyInfo(TaskView view) { - Task task = view.getTask(); - - WorkspaceItemInfo dummyInfo = new WorkspaceItemInfo(){ - /** - * Helps to log events as {@link LauncherAtom.Task} - * instead of {@link LauncherAtom.ItemInfo}. - */ - @Override - public LauncherAtom.ItemInfo buildProto() { - return view.buildProto(); - } - }; - dummyInfo.intent = new Intent(); - ComponentName component = task.getTopComponent(); - dummyInfo.getIntent().setComponent(component); - dummyInfo.user = UserHandle.of(task.key.userId); - dummyInfo.title = TaskUtils.getTitle(view.getContext(), task); - return dummyInfo; - } - - TaskShortcutFactory APP_INFO = (activity, view) -> new AppInfo(activity, dummyInfo(view)); + TaskShortcutFactory APP_INFO = (activity, view) -> new AppInfo(activity, view.getItemInfo()); abstract class MultiWindowFactory implements TaskShortcutFactory { @@ -136,7 +110,7 @@ public interface TaskShortcutFactory { public MultiWindowSystemShortcut(int iconRes, int textRes, BaseDraggingActivity activity, TaskView taskView, MultiWindowFactory factory, LauncherEvent launcherEvent) { - super(iconRes, textRes, activity, dummyInfo(taskView)); + super(iconRes, textRes, activity, taskView.getItemInfo()); mLauncherEvent = launcherEvent; mHandler = new Handler(Looper.getMainLooper()); mTaskView = taskView; @@ -222,7 +196,7 @@ public interface TaskShortcutFactory { WindowManagerWrapper.getInstance().overridePendingAppTransitionMultiThumbFuture( future, animStartedListener, mHandler, true /* scaleUp */, taskKey.displayId); - mTarget.getStatsLogManager().log(mLauncherEvent, mTaskView.buildProto()); + mTarget.getStatsLogManager().log(mLauncherEvent, mTaskView.getItemInfo()); } } } @@ -306,7 +280,7 @@ public interface TaskShortcutFactory { private final TaskView mTaskView; public PinSystemShortcut(BaseDraggingActivity target, TaskView tv) { - super(R.drawable.ic_pin, R.string.recent_task_option_pin, target, dummyInfo(tv)); + super(R.drawable.ic_pin, R.string.recent_task_option_pin, target, tv.getItemInfo()); mTaskView = tv; } @@ -323,29 +297,29 @@ public interface TaskShortcutFactory { mTaskView.launchTask(true, resultCallback, Executors.MAIN_EXECUTOR.getHandler()); dismissTaskMenuView(mTarget); mTarget.getStatsLogManager().log(LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_PIN_TAP, - mTaskView.buildProto()); + mTaskView.getItemInfo()); } } TaskShortcutFactory INSTALL = (activity, view) -> InstantAppResolver.newInstance(activity).isInstantApp(activity, view.getTask().getTopComponent().getPackageName()) - ? new SystemShortcut.Install(activity, dummyInfo(view)) : null; + ? new SystemShortcut.Install(activity, view.getItemInfo()) : null; TaskShortcutFactory WELLBEING = (activity, view) -> - WellbeingModel.SHORTCUT_FACTORY.getShortcut(activity, dummyInfo(view)); + WellbeingModel.SHORTCUT_FACTORY.getShortcut(activity, view.getItemInfo()); TaskShortcutFactory SCREENSHOT = (activity, tv) -> { if (ENABLE_OVERVIEW_ACTIONS.get()) { return tv.getThumbnail().getTaskOverlay() - .getScreenshotShortcut(activity, dummyInfo(tv)); + .getScreenshotShortcut(activity, tv.getItemInfo()); } return null; }; TaskShortcutFactory MODAL = (activity, tv) -> { if (ENABLE_OVERVIEW_ACTIONS.get() && ENABLE_OVERVIEW_SELECTIONS.get()) { - return tv.getThumbnail().getTaskOverlay().getModalStateSystemShortcut(dummyInfo(tv)); + return tv.getThumbnail().getTaskOverlay().getModalStateSystemShortcut(tv.getItemInfo()); } return null; }; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java index 05f4e91075..534ef7b689 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java @@ -1347,7 +1347,7 @@ public abstract class RecentsView extends PagedView impl mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss( endState.logAction, Direction.UP, index, compKey); mActivity.getStatsLogManager().log( - LAUNCHER_TASK_DISMISS_SWIPE_UP, taskView.buildProto()); + LAUNCHER_TASK_DISMISS_SWIPE_UP, taskView.getItemInfo()); } } @@ -1930,7 +1930,7 @@ public abstract class RecentsView extends PagedView impl endState.logAction, Direction.DOWN, indexOfChild(tv), TaskUtils.getLaunchComponentKeyForTask(task.key)); mActivity.getStatsLogManager().log( - LAUNCHER_TASK_LAUNCH_SWIPE_DOWN, tv.buildProto()); + LAUNCHER_TASK_LAUNCH_SWIPE_DOWN, tv.getItemInfo()); } } else { onTaskLaunched(false); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java index e25c85b92b..3b1210e2ae 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java @@ -40,6 +40,7 @@ import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.app.ActivityOptions; import android.content.Context; +import android.content.Intent; import android.graphics.Outline; import android.graphics.Rect; import android.graphics.RectF; @@ -48,7 +49,6 @@ import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.InsetDrawable; import android.os.Bundle; import android.os.Handler; -import android.os.Process; import android.util.AttributeSet; import android.util.FloatProperty; import android.util.Log; @@ -61,13 +61,14 @@ import android.widget.Toast; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.DeviceProfile; +import com.android.launcher3.LauncherSettings; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.anim.PendingAnimation; -import com.android.launcher3.logger.LauncherAtom; import com.android.launcher3.logging.UserEventDispatcher; +import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.testing.TestLogging; import com.android.launcher3.testing.TestProtocol; @@ -213,7 +214,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss( Touch.TAP, Direction.NONE, getRecentsView().indexOfChild(this), TaskUtils.getLaunchComponentKeyForTask(getTask().key)); - mActivity.getStatsLogManager().log(LAUNCHER_TASK_LAUNCH_TAP, buildProto()); + mActivity.getStatsLogManager().log(LAUNCHER_TASK_LAUNCH_TAP, getItemInfo()); }); mCurrentFullscreenParams = new FullscreenDrawParams(context); @@ -226,14 +227,16 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { /** * Builds proto for logging */ - public LauncherAtom.ItemInfo buildProto() { + public WorkspaceItemInfo getItemInfo() { ComponentKey componentKey = TaskUtils.getLaunchComponentKeyForTask(getTask().key); - LauncherAtom.ItemInfo.Builder itemBuilder = LauncherAtom.ItemInfo.newBuilder(); - itemBuilder.setIsWork(componentKey.user != Process.myUserHandle()); - itemBuilder.setTask(LauncherAtom.Task.newBuilder() - .setComponentName(componentKey.componentName.flattenToShortString()) - .setIndex(getRecentsView().indexOfChild(this))); - return itemBuilder.build(); + WorkspaceItemInfo dummyInfo = new WorkspaceItemInfo(); + dummyInfo.itemType = LauncherSettings.Favorites.ITEM_TYPE_TASK; + dummyInfo.container = LauncherSettings.Favorites.CONTAINER_TASKSWITCHER; + dummyInfo.user = componentKey.user; + dummyInfo.intent = new Intent().setComponent(componentKey.componentName); + dummyInfo.title = TaskUtils.getTitle(getContext(), getTask()); + dummyInfo.screenId = getRecentsView().indexOfChild(this); + return dummyInfo; } @Override @@ -429,7 +432,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { getRecentsView().snapToPage(getRecentsView().indexOfChild(this)); } else { mMenuView = TaskMenuView.showForTask(this); - mActivity.getStatsLogManager().log(LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS, buildProto()); + mActivity.getStatsLogManager().log(LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS, getItemInfo()); UserEventDispatcher.newInstance(getContext()).logActionOnItem(action, Direction.NONE, LauncherLogProto.ItemType.TASK_ICON); if (mMenuView != null) { diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java index 390330f166..a88ba3c913 100644 --- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java +++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java @@ -64,6 +64,9 @@ public class StatsLogCompatManager extends StatsLogManager { private static Context sContext; private static final InstanceId DEFAULT_INSTANCE_ID = InstanceId.fakeInstanceId(0); + // LauncherAtom.ItemInfo.getDefaultInstance() should be used but until launcher proto migrates + // from nano to lite, bake constant to prevent robo test failure. + private static final int DEFAULT_PAGE_INDEX = -2; private static final int FOLDER_HIERARCHY_OFFSET = 100; public StatsLogCompatManager(Context context) { @@ -75,7 +78,7 @@ public class StatsLogCompatManager extends StatsLogManager { */ @Override public void log(EventEnum event) { - log(event, DEFAULT_INSTANCE_ID, LauncherAtom.ItemInfo.getDefaultInstance()); + log(event, DEFAULT_INSTANCE_ID, null); } /** @@ -83,31 +86,27 @@ public class StatsLogCompatManager extends StatsLogManager { */ @Override public void log(EventEnum event, InstanceId instanceId) { - log(event, instanceId, LauncherAtom.ItemInfo.getDefaultInstance()); + log(event, instanceId, null); } /** * Logs an event and accompanying {@link ItemInfo}. */ @Override - public void log(EventEnum event, @Nullable LauncherAtom.ItemInfo info) { + public void log(EventEnum event, @Nullable ItemInfo info) { log(event, DEFAULT_INSTANCE_ID, info); } - @Override - public void log(EventEnum event, ItemInfo itemInfo) { - logInternal(event, DEFAULT_INSTANCE_ID, itemInfo); - } - /** * Logs an event and accompanying {@link InstanceId} and {@link LauncherAtom.ItemInfo}. */ @Override public void log(EventEnum event, InstanceId instanceId, - @Nullable LauncherAtom.ItemInfo info) { + @Nullable ItemInfo info) { logInternal(event, instanceId, info, LAUNCHER_UICHANGED__DST_STATE__HOME, - LAUNCHER_UICHANGED__DST_STATE__BACKGROUND); + LAUNCHER_UICHANGED__DST_STATE__BACKGROUND, + DEFAULT_PAGE_INDEX); } /** @@ -129,58 +128,60 @@ public class StatsLogCompatManager extends StatsLogManager { */ @Override public void log(EventEnum event, int srcState, int dstState, int pageIndex) { - LauncherAtom.ItemInfo info = LauncherAtom.ItemInfo.getDefaultInstance(); - if (srcState == LAUNCHER_UICHANGED__DST_STATE__HOME - || dstState == LAUNCHER_UICHANGED__SRC_STATE__HOME) { - info = LauncherAtom.ItemInfo.newBuilder().setContainerInfo( - LauncherAtom.ContainerInfo.newBuilder().setWorkspace( - LauncherAtom.WorkspaceContainer.newBuilder().setPageIndex(pageIndex) - )).build(); - } - logInternal(event, DEFAULT_INSTANCE_ID, info, srcState, dstState); + logInternal(event, DEFAULT_INSTANCE_ID, null, srcState, dstState, pageIndex); } - private void logInternal(EventEnum event, InstanceId instanceId, @Nullable ItemInfo info) { + /** + * Logs an event and accompanying {@link InstanceId} and {@link ItemInfo}. + */ + private void logInternal(EventEnum event, InstanceId instanceId, + @Nullable ItemInfo info, int srcState, int dstState, int pageIndex) { + LauncherAppState.getInstance(sContext).getModel().enqueueModelUpdateTask( new BaseModelUpdateTask() { @Override public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) { - LauncherAtom.ItemInfo atomInfo = LauncherAtom.ItemInfo.getDefaultInstance(); - if (info != null) { - if (info.container >= 0) { - atomInfo = info.buildProto(dataModel.folders.get(info.container)); - } else { - atomInfo = info.buildProto(); - } - } - logInternal(event, instanceId, atomInfo, - LAUNCHER_UICHANGED__DST_STATE__HOME, - LAUNCHER_UICHANGED__DST_STATE__BACKGROUND); + writeEvent(event, instanceId, info, srcState, dstState, pageIndex, + dataModel.folders); } }); } - /** - * Logs an event and accompanying {@link InstanceId} and {@link LauncherAtom.ItemInfo}. - */ - private void logInternal(EventEnum event, InstanceId instanceId, - @Nullable LauncherAtom.ItemInfo info, int srcState, int dstState) { - info = info == null ? LauncherAtom.ItemInfo.getDefaultInstance() : info; + private static void writeEvent(EventEnum event, InstanceId instanceId, + @Nullable ItemInfo info, int srcState, int dstState, int pageIndex, + IntSparseArrayMap folders) { + + if (!Utilities.ATLEAST_R) { + return; + } + LauncherAtom.ItemInfo atomInfo = LauncherAtom.ItemInfo.getDefaultInstance(); + if (info != null) { + if (info.container >= 0) { + atomInfo = info.buildProto(folders.get(info.container)); + } else { + atomInfo = info.buildProto(); + } + } else { + if (srcState == LAUNCHER_UICHANGED__DST_STATE__HOME + || dstState == LAUNCHER_UICHANGED__SRC_STATE__HOME) { + atomInfo = LauncherAtom.ItemInfo.newBuilder().setContainerInfo( + LauncherAtom.ContainerInfo.newBuilder().setWorkspace( + LauncherAtom.WorkspaceContainer.newBuilder().setPageIndex(pageIndex) + )).build(); + } + } if (IS_VERBOSE) { String name = (event instanceof Enum) ? ((Enum) event).name() : event.getId() + ""; Log.d(TAG, instanceId == DEFAULT_INSTANCE_ID - ? String.format("\n%s (State:%s->%s) \n%s", name, getStateString(srcState), - getStateString(dstState), info) - : String.format("\n%s (State:%s->%s) (InstanceId:%s)\n%s", name, - getStateString(srcState), getStateString(dstState), instanceId, info)); - } - - if (!Utilities.ATLEAST_R) { - return; + ? String.format("\n%s (State:%s->%s) \n%s\n%s", name, getStateString(srcState), + getStateString(dstState), info, atomInfo) + : String.format("\n%s (State:%s->%s) (InstanceId:%s)\n%s\n%s", name, + getStateString(srcState), getStateString(dstState), instanceId, info, + atomInfo)); } SysUiStatsLog.write( @@ -191,24 +192,24 @@ public class StatsLogCompatManager extends StatsLogManager { null /* launcher extensions, deprecated */, false /* quickstep_enabled, deprecated */, event.getId() /* event_id */, - info.getItemCase().getNumber() /* target_id */, + atomInfo.getItemCase().getNumber() /* target_id */, instanceId.getId() /* instance_id TODO */, 0 /* uid TODO */, - getPackageName(info) /* package_name */, - getComponentName(info) /* component_name */, - getGridX(info, false) /* grid_x */, - getGridY(info, false) /* grid_y */, - getPageId(info, false) /* page_id */, - getGridX(info, true) /* grid_x_parent */, - getGridY(info, true) /* grid_y_parent */, - getPageId(info, true) /* page_id_parent */, - getHierarchy(info) /* hierarchy */, - info.getIsWork() /* is_work_profile */, - info.getRank() /* rank */, - info.getFolderIcon().getFromLabelState().getNumber() /* fromState */, - info.getFolderIcon().getToLabelState().getNumber() /* toState */, - info.getFolderIcon().getLabelInfo() /* edittext */, - getCardinality(info) /* cardinality */); + getPackageName(atomInfo) /* package_name */, + getComponentName(atomInfo) /* component_name */, + getGridX(atomInfo, false) /* grid_x */, + getGridY(atomInfo, false) /* grid_y */, + getPageId(atomInfo, false) /* page_id */, + getGridX(atomInfo, true) /* grid_x_parent */, + getGridY(atomInfo, true) /* grid_y_parent */, + getPageId(atomInfo, true) /* page_id_parent */, + getHierarchy(atomInfo) /* hierarchy */, + atomInfo.getIsWork() /* is_work_profile */, + atomInfo.getRank() /* rank */, + atomInfo.getFolderIcon().getFromLabelState().getNumber() /* fromState */, + atomInfo.getFolderIcon().getToLabelState().getNumber() /* toState */, + atomInfo.getFolderIcon().getLabelInfo() /* edittext */, + getCardinality(atomInfo) /* cardinality */); } /** diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java index 268b910dd9..88dbfd6e37 100644 --- a/src/com/android/launcher3/BaseDraggingActivity.java +++ b/src/com/android/launcher3/BaseDraggingActivity.java @@ -188,7 +188,7 @@ public abstract class BaseDraggingActivity extends BaseActivity } getUserEventDispatcher().logAppLaunch(v, intent, user); if (item != null) { - getStatsLogManager().log(LAUNCHER_APP_LAUNCH_TAP, item.buildProto()); + getStatsLogManager().log(LAUNCHER_APP_LAUNCH_TAP, item); } return true; } catch (NullPointerException|ActivityNotFoundException|SecurityException e) { diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java index 208d565d2e..5512654390 100644 --- a/src/com/android/launcher3/LauncherSettings.java +++ b/src/com/android/launcher3/LauncherSettings.java @@ -163,6 +163,7 @@ public class LauncherSettings { public static final int CONTAINER_SEARCH_RESULTS = -106; public static final int CONTAINER_SHORTCUTS = -107; public static final int CONTAINER_SETTINGS = -108; + public static final int CONTAINER_TASKSWITCHER = -109; public static final String containerToString(int container) { switch (container) { @@ -249,6 +250,12 @@ public class LauncherSettings { */ public static final int ITEM_TYPE_DEEP_SHORTCUT = 6; + /** + * Type of the item is recents task. + * TODO(hyunyoungs): move constants not related to Favorites DB to a better location. + */ + public static final int ITEM_TYPE_TASK = 7; + /** * The appWidgetId of the widget * diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index f6c392b536..4198e9f6e9 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -418,10 +418,7 @@ public class Workspace extends PagedView mStatsLogManager.log( LauncherEvent.LAUNCHER_ITEM_DRAG_STARTED, dragObject.logInstanceId, - dragObject.dragSource instanceof Folder - ? dragObject.originalDragInfo - .buildProto(((Folder) dragObject.dragSource).mInfo) - : dragObject.originalDragInfo.buildProto() + dragObject.originalDragInfo ); } @@ -1652,7 +1649,7 @@ public class Workspace extends PagedView mStatsLogManager.log( LauncherEvent.LAUNCHER_ITEM_DROP_FOLDER_CREATED, d.logInstanceId, - destInfo.buildProto(null)); + destInfo); FolderIcon fi = mLauncher.addFolder(target, container, screenId, targetCell[0], targetCell[1]); destInfo.cellX = -1; @@ -1693,7 +1690,7 @@ public class Workspace extends PagedView mStatsLogManager.log( LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED, d.logInstanceId, - fi.mInfo.buildProto(null)); + fi.mInfo); fi.onDrop(d, false /* itemReturnedOnFailedDrop */); // if the drag started here, we need to remove it from the workspace @@ -1899,7 +1896,7 @@ public class Workspace extends PagedView mStatsLogManager.log( LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED, d.logInstanceId, - d.dragInfo.buildProto(null)); + d.dragInfo); } if (d.stateAnnouncer != null && !droppedOnOriginalCell) { @@ -2440,7 +2437,7 @@ public class Workspace extends PagedView mStatsLogManager.log( LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED, d.logInstanceId, - d.dragInfo.buildProto(null)); + d.dragInfo); } }; boolean isWidget = pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET @@ -2532,7 +2529,7 @@ public class Workspace extends PagedView mStatsLogManager.log( LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED, d.logInstanceId, - d.dragInfo.buildProto(null)); + d.dragInfo); } } diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java index c7487cb602..530010e948 100644 --- a/src/com/android/launcher3/folder/Folder.java +++ b/src/com/android/launcher3/folder/Folder.java @@ -1338,7 +1338,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo d.stateAnnouncer.completeAction(R.string.item_moved); } mStatsLogManager - .log(LAUNCHER_ITEM_DROP_COMPLETED, d.logInstanceId, d.dragInfo.buildProto(mInfo)); + .log(LAUNCHER_ITEM_DROP_COMPLETED, d.logInstanceId, d.dragInfo); } // This is used so the item doesn't immediately appear in the folder when added. In one case @@ -1443,7 +1443,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo if (hasFocus) { startEditingFolderName(); } else { - mStatsLogManager.log(LAUNCHER_FOLDER_LABEL_UPDATED, mInfo.buildProto()); + mStatsLogManager.log(LAUNCHER_FOLDER_LABEL_UPDATED, mInfo); logFolderLabelState(); mFolderName.dispatchBackKey(); } diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java index 153d6bceb1..098ce50750 100644 --- a/src/com/android/launcher3/folder/FolderIcon.java +++ b/src/com/android/launcher3/folder/FolderIcon.java @@ -450,7 +450,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel } mInfo.setTitle(nameInfos[0].getLabel()); StatsLogManager.newInstance(getContext()) - .log(LAUNCHER_FOLDER_LABEL_UPDATED, instanceId, mInfo.buildProto()); + .log(LAUNCHER_FOLDER_LABEL_UPDATED, instanceId, mInfo); onTitleChanged(mInfo.title); mFolder.mFolderName.setText(mInfo.title); mFolder.mLauncher.getModelWriter().updateItemInDatabase(mInfo); diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java index ce70a3225f..e95c062c09 100644 --- a/src/com/android/launcher3/logging/StatsLogManager.java +++ b/src/com/android/launcher3/logging/StatsLogManager.java @@ -21,8 +21,8 @@ import androidx.annotation.Nullable; import com.android.launcher3.LauncherState; import com.android.launcher3.R; -import com.android.launcher3.logger.LauncherAtom.ItemInfo; import com.android.launcher3.logging.StatsLogUtils.LogStateProvider; +import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.util.ResourceBasedOverride; /** @@ -191,32 +191,37 @@ public class StatsLogManager implements ResourceBasedOverride { } /** - * Logs a {@link EventEnum}. + * Logs an event. + * + * @param event an enum implementing EventEnum interface. */ public void log(EventEnum event) { } /** - * Logs an event and accompanying {@link InstanceId}. + * Logs an event. + * + * @param event an enum implementing EventEnum interface. + * @param instanceId an identifier obtained from an InstanceIdSequence. */ public void log(EventEnum event, InstanceId instanceId) { } /** - * Logs an event and accompanying {@link ItemInfo}. + * Logs an event. + * + * @param event an enum implementing EventEnum interface. + * @param itemInfo item typically containing app or task launch related information. */ public void log(EventEnum event, @Nullable ItemInfo itemInfo) { } /** - * Logs an event and accompanying {@link com.android.launcher3.model.data.ItemInfo}. - */ - public void log(EventEnum event, - com.android.launcher3.model.data.ItemInfo itemInfo) { - } - - /** - * Logs an event and accompanying {@link InstanceId} and {@link ItemInfo}. + * Logs an event. + * + * @param event an enum implementing EventEnum interface. + * @param instanceId an identifier obtained from an InstanceIdSequence. + * @param itemInfo item typically containing app or task launch related information. */ public void log(EventEnum event, InstanceId instanceId, @Nullable ItemInfo itemInfo) { } @@ -225,7 +230,7 @@ public class StatsLogManager implements ResourceBasedOverride { * Log an event with ranked-choice information along with package. Does nothing if event.getId() * <= 0. * - * @param rankingEvent an enum implementing UiEventEnum interface. + * @param rankingEvent an enum implementing EventEnum interface. * @param instanceId An identifier obtained from an InstanceIdSequence. * @param packageName the package name of the relevant app, if known (null otherwise). * @param position the position picked. diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java index d52b7ebdd6..66c3cbbe27 100644 --- a/src/com/android/launcher3/model/data/ItemInfo.java +++ b/src/com/android/launcher3/model/data/ItemInfo.java @@ -24,11 +24,13 @@ import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PREDICT import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SEARCH_RESULTS; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SETTINGS; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SHORTCUTS; +import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_TASKSWITCHER; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_TRAY; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; +import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_TASK; import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.CONTAINER_NOT_SET; import android.content.ComponentName; @@ -49,6 +51,7 @@ import com.android.launcher3.logger.LauncherAtom.PredictionContainer; import com.android.launcher3.logger.LauncherAtom.SearchResultContainer; import com.android.launcher3.logger.LauncherAtom.SettingsContainer; import com.android.launcher3.logger.LauncherAtom.ShortcutsContainer; +import com.android.launcher3.logger.LauncherAtom.TaskSwitcherContainer; import com.android.launcher3.util.ContentWriter; import java.util.Optional; @@ -298,6 +301,12 @@ public class ItemInfo { .setSpanX(spanX) .setSpanY(spanY)); break; + case ITEM_TYPE_TASK: + itemBuilder + .setTask(LauncherAtom.Task.newBuilder() + .setComponentName(getTargetComponent().flattenToShortString()) + .setIndex(screenId)); + break; default: break; } @@ -378,6 +387,11 @@ public class ItemInfo { return ContainerInfo.newBuilder() .setSettingsContainer(SettingsContainer.getDefaultInstance()) .build(); + case CONTAINER_TASKSWITCHER: + return ContainerInfo.newBuilder() + .setTaskSwitcherContainer(TaskSwitcherContainer.getDefaultInstance()) + .build(); + } return ContainerInfo.getDefaultInstance(); } diff --git a/src/com/android/launcher3/notification/NotificationInfo.java b/src/com/android/launcher3/notification/NotificationInfo.java index fa1bdfbb46..f1b63f28f9 100644 --- a/src/com/android/launcher3/notification/NotificationInfo.java +++ b/src/com/android/launcher3/notification/NotificationInfo.java @@ -108,7 +108,7 @@ public class NotificationInfo implements View.OnClickListener { intent.send(null, 0, null, null, null, null, activityOptions); launcher.getUserEventDispatcher().logNotificationLaunch(view, intent); launcher.getStatsLogManager() - .log(LAUNCHER_NOTIFICATION_LAUNCH_TAP, mItemInfo.buildProto()); + .log(LAUNCHER_NOTIFICATION_LAUNCH_TAP, mItemInfo); } catch (PendingIntent.CanceledException e) { e.printStackTrace(); } diff --git a/src/com/android/launcher3/popup/RemoteActionShortcut.java b/src/com/android/launcher3/popup/RemoteActionShortcut.java index 58251e8967..8e60c27e66 100644 --- a/src/com/android/launcher3/popup/RemoteActionShortcut.java +++ b/src/com/android/launcher3/popup/RemoteActionShortcut.java @@ -78,7 +78,7 @@ public class RemoteActionShortcut extends SystemShortcut { public void onClick(View view) { AbstractFloatingView.closeAllOpenViews(mTarget); mTarget.getStatsLogManager() - .log(LAUNCHER_SYSTEM_SHORTCUT_PAUSE_TAP, mItemInfo.buildProto()); + .log(LAUNCHER_SYSTEM_SHORTCUT_PAUSE_TAP, mItemInfo); final String actionIdentity = mAction.getTitle() + ", " + mItemInfo.getTargetComponent().getPackageName(); diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java index ea8caf55de..59d24dee77 100644 --- a/src/com/android/launcher3/popup/SystemShortcut.java +++ b/src/com/android/launcher3/popup/SystemShortcut.java @@ -119,9 +119,7 @@ public abstract class SystemShortcut extends Ite widgetsBottomSheet.populateAndShow(mItemInfo); mTarget.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP, ControlType.WIDGETS_BUTTON, view); - // TODO(thiruram): Fix missing container info when item is inside folder. - mTarget.getStatsLogManager().log(LAUNCHER_SYSTEM_SHORTCUT_WIDGETS_TAP, - mItemInfo.buildProto()); + mTarget.getStatsLogManager().log(LAUNCHER_SYSTEM_SHORTCUT_WIDGETS_TAP, mItemInfo); } } @@ -142,9 +140,8 @@ public abstract class SystemShortcut extends Ite mItemInfo, sourceBounds, ActivityOptions.makeBasic().toBundle()); mTarget.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP, ControlType.APPINFO_TARGET, view); - // TODO(thiruram): Fix missing container info when item is inside folder. mTarget.getStatsLogManager() - .log(LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP, mItemInfo.buildProto()); + .log(LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP, mItemInfo); } } From 7c57559930b78ec8b2c8eb7619b59e4aba2312a2 Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Thu, 11 Jun 2020 19:29:41 -0700 Subject: [PATCH 20/35] Gates blur code behind BlurUtils#supportsBlursOnWindows. This "fixes" the bug where wallpaper zoom does not reset to 0 when screen turns off since we no longer require a valid surface to set the depth when blur is disabled. Note that the bug still exists when blur is enabled, which will need to be fixed in a follow up CL. Bug: 157946272 Change-Id: I43179435885c95eb2ecf406fa5c291badf5a1ed3 --- .../statehandlers/DepthController.java | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java index ebe9e26c02..2b08dcd6ed 100644 --- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java +++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java @@ -32,6 +32,7 @@ import com.android.launcher3.Utilities; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.statemanager.StateManager.StateHandler; import com.android.launcher3.states.StateAnimationConfig; +import com.android.systemui.shared.system.BlurUtils; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.SurfaceControlCompat; import com.android.systemui.shared.system.TransactionCompat; @@ -110,6 +111,10 @@ public class DepthController implements StateHandler { } private void ensureDependencies() { + if (mWallpaperManager == null) { + mMaxBlurRadius = mLauncher.getResources().getInteger(R.integer.max_depth_blur_radius); + mWallpaperManager = new WallpaperManagerCompat(mLauncher); + } if (mLauncher.getRootView() != null && mOnAttachListener == null) { mOnAttachListener = new View.OnAttachStateChangeListener() { @Override @@ -127,11 +132,6 @@ public class DepthController implements StateHandler { }; mLauncher.getRootView().addOnAttachStateChangeListener(mOnAttachListener); } - if (mWallpaperManager != null) { - return; - } - mMaxBlurRadius = mLauncher.getResources().getInteger(R.integer.max_depth_blur_radius); - mWallpaperManager = new WallpaperManagerCompat(mLauncher); } /** @@ -205,7 +205,8 @@ public class DepthController implements StateHandler { return; } - if (mSurface == null || !mSurface.isValid()) { + boolean supportsBlur = BlurUtils.supportsBlursOnWindows(); + if (supportsBlur && (mSurface == null || !mSurface.isValid())) { return; } mDepth = depthF; @@ -214,17 +215,20 @@ public class DepthController implements StateHandler { if (windowToken != null) { mWallpaperManager.setWallpaperZoomOut(windowToken, mDepth); } - final int blur; - if (mLauncher.isInState(LauncherState.ALL_APPS) && mDepth == 1) { - // All apps has a solid background. We don't need to draw blurs after it's fully - // visible. This will take us out of GPU composition, saving battery and increasing - // performance. - blur = 0; - } else { - blur = (int) (mDepth * mMaxBlurRadius); + + if (supportsBlur) { + final int blur; + if (mLauncher.isInState(LauncherState.ALL_APPS) && mDepth == 1) { + // All apps has a solid background. We don't need to draw blurs after it's fully + // visible. This will take us out of GPU composition, saving battery and increasing + // performance. + blur = 0; + } else { + blur = (int) (mDepth * mMaxBlurRadius); + } + new TransactionCompat() + .setBackgroundBlurRadius(mSurface, blur) + .apply(); } - new TransactionCompat() - .setBackgroundBlurRadius(mSurface, blur) - .apply(); } } From 1150ab3825b2037849ebff0c3eed4a0486005042 Mon Sep 17 00:00:00 2001 From: Samuel Fufa Date: Thu, 11 Jun 2020 22:32:39 -0700 Subject: [PATCH 21/35] Announce folder content size with folder title Bug: 144094885 Test: Manual Change-Id: I340f9292b62163e1d72778024f1765c7618084c2 --- res/values/strings.xml | 6 ++++-- .../android/launcher3/folder/FolderIcon.java | 20 ++++++++++++++++--- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 2efa66f2c1..935bb40fb3 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -172,8 +172,10 @@ Folder closed Folder renamed to %1$s - - Folder: %1$s + + Folder: %1$s, %2$d items + + Folder: %1$s, %2$d or more items diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java index 153d6bceb1..21b2e5be28 100644 --- a/src/com/android/launcher3/folder/FolderIcon.java +++ b/src/com/android/launcher3/folder/FolderIcon.java @@ -201,8 +201,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel icon.mActivity = activity; icon.mDotRenderer = grid.mDotRendererWorkSpace; - icon.setContentDescription( - group.getContext().getString(R.string.folder_name_format, folderInfo.title)); + icon.setContentDescription(icon.getAccessiblityTitle(folderInfo.title)); // Keep the notification dot up to date with the sum of all the content's dots. FolderDotInfo folderDotInfo = new FolderDotInfo(); @@ -665,6 +664,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel mDotInfo.addDotInfo(mActivity.getDotInfoForItem(item)); boolean isDotted = mDotInfo.hasDot(); updateDotScale(wasDotted, isDotted); + setContentDescription(getAccessiblityTitle(mInfo.title)); invalidate(); requestLayout(); } @@ -675,13 +675,14 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel mDotInfo.subtractDotInfo(mActivity.getDotInfoForItem(item)); boolean isDotted = mDotInfo.hasDot(); updateDotScale(wasDotted, isDotted); + setContentDescription(getAccessiblityTitle(mInfo.title)); invalidate(); requestLayout(); } public void onTitleChanged(CharSequence title) { mFolderName.setText(title); - setContentDescription(getContext().getString(R.string.folder_name_format, title)); + setContentDescription(getAccessiblityTitle(title)); } @Override @@ -775,4 +776,17 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel public void getWorkspaceVisualDragBounds(Rect bounds) { getPreviewBounds(bounds); } + + /** + * Returns a formatted accessibility title for folder + */ + public String getAccessiblityTitle(CharSequence title) { + int size = mInfo.contents.size(); + if (size < MAX_NUM_ITEMS_IN_PREVIEW) { + return getContext().getString(R.string.folder_name_format_exact, title, size); + } else { + return getContext().getString(R.string.folder_name_format_overflow, title, + MAX_NUM_ITEMS_IN_PREVIEW); + } + } } From 5112cdd30b62009545d6bfd43b2ccd11abd9cdf7 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Fri, 12 Jun 2020 14:23:46 -0500 Subject: [PATCH 22/35] Skip fling anim if it is a no-op, to save a frame of aniamtion Bug: 158701272 Change-Id: Id2bc502d1caaeefeca339d5e5ad355ad8ba6d7ec --- src/com/android/launcher3/anim/FlingSpringAnim.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/com/android/launcher3/anim/FlingSpringAnim.java b/src/com/android/launcher3/anim/FlingSpringAnim.java index 06d0f1c463..6ea38ec8ab 100644 --- a/src/com/android/launcher3/anim/FlingSpringAnim.java +++ b/src/com/android/launcher3/anim/FlingSpringAnim.java @@ -35,6 +35,7 @@ public class FlingSpringAnim { private final FlingAnimation mFlingAnim; private SpringAnimation mSpringAnim; + private final boolean mSkipFlingAnim; private float mTargetPosition; @@ -57,6 +58,10 @@ public class FlingSpringAnim { .setMaxValue(maxValue); mTargetPosition = targetPosition; + // We are already past the fling target, so skip it to avoid losing a frame of the spring. + mSkipFlingAnim = startPosition <= minValue && startVelocity < 0 + || startPosition >= maxValue && startVelocity > 0; + mFlingAnim.addEndListener(((animation, canceled, value, velocity) -> { mSpringAnim = new SpringAnimation(object, property) .setStartValue(value) @@ -84,6 +89,9 @@ public class FlingSpringAnim { public void start() { mFlingAnim.start(); + if (mSkipFlingAnim) { + mFlingAnim.cancel(); + } } public void end() { From 05179b66501d31ec3417f3a9ece9f9ade4e9fedd Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Fri, 12 Jun 2020 14:54:02 -0700 Subject: [PATCH 23/35] Fixing recents animation not getting completed sometimes when using 3P launcher Bug: 158855992 Change-Id: I2c0cb74edfea5406e79aa99d6604183e63c1f0f1 --- .../com/android/quickstep/BaseSwipeUpHandlerV2.java | 4 ++-- .../com/android/quickstep/FallbackSwipeHandler.java | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java index d55dc0f1b1..e825c5f5b8 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java @@ -131,7 +131,7 @@ public abstract class BaseSwipeUpHandlerV2, Q exte private static final int STATE_CAPTURE_SCREENSHOT = getFlagForIndex(10, "STATE_CAPTURE_SCREENSHOT"); - private static final int STATE_SCREENSHOT_CAPTURED = + protected static final int STATE_SCREENSHOT_CAPTURED = getFlagForIndex(11, "STATE_SCREENSHOT_CAPTURED"); private static final int STATE_SCREENSHOT_VIEW_SHOWN = getFlagForIndex(12, "STATE_SCREENSHOT_VIEW_SHOWN"); @@ -1192,7 +1192,7 @@ public abstract class BaseSwipeUpHandlerV2, Q exte mActivity.clearForceInvisibleFlag(INVISIBLE_BY_STATE_HANDLER); } - private void switchToScreenshot() { + protected void switchToScreenshot() { final int runningTaskId = mGestureState.getRunningTaskId(); if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { if (mRecentsAnimationController != null) { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java index 96913c651c..fc7a119f21 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java @@ -110,6 +110,16 @@ public class FallbackSwipeHandler extends false /* toRecents */, callback, true /* sendUserLeaveHint */); } + @Override + protected void switchToScreenshot() { + if (mRunningOverHome) { + // When the current task is home, then we don't need to capture anything + mStateCallback.setStateOnUiThread(STATE_SCREENSHOT_CAPTURED); + } else { + super.switchToScreenshot(); + } + } + @Override protected void notifyGestureAnimationStartToRecents() { if (mRunningOverHome) { From 01bb8125b0de1868b931e8c95000a446b14c5259 Mon Sep 17 00:00:00 2001 From: vadimt Date: Thu, 11 Jun 2020 18:37:26 -0700 Subject: [PATCH 24/35] Enable FallbackRecentsTest With some temporary workarounds. Bug: 143488140 Change-Id: Id1ed2d06fd3265a6aa7f98d2900733f580359944 --- .../android/quickstep/FallbackRecentsTest.java | 18 ++++++++---------- .../StartLauncherViaGestureTests.java | 2 ++ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java index a726052e27..a343e7c31c 100644 --- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java +++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java @@ -37,7 +37,6 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import android.app.Instrumentation; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; @@ -58,10 +57,8 @@ import com.android.launcher3.testcomponent.TestCommandReceiver; import com.android.launcher3.util.Wait; import com.android.launcher3.util.rule.FailureRewriterRule; import com.android.launcher3.util.rule.FailureWatcher; -import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch; import com.android.quickstep.views.RecentsView; -import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.RuleChain; @@ -95,7 +92,8 @@ public class FallbackRecentsTest { mDevice = UiDevice.getInstance(instrumentation); mDevice.setOrientationNatural(); mLauncher = new LauncherInstrumentation(); - mLauncher.enableCheckEventsForSuccessfulGestures(); + // b/143488140 + //mLauncher.enableCheckEventsForSuccessfulGestures(); if (TestHelpers.isInLauncherProcess()) { Utilities.enableRunningInTestHarnessForTests(); @@ -132,9 +130,9 @@ public class FallbackRecentsTest { } } - @NavigationModeSwitch + // b/143488140 + //@NavigationModeSwitch @Test - @Ignore // b/143488140 public void goToOverviewFromHome() { mDevice.pressHome(); assertTrue("Fallback Launcher not visible", mDevice.wait(Until.hasObject(By.pkg( @@ -143,9 +141,9 @@ public class FallbackRecentsTest { mLauncher.getBackground().switchToOverview(); } - @NavigationModeSwitch + // b/143488140 + //@NavigationModeSwitch @Test - @Ignore // b/143488140 public void goToOverviewFromApp() { startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR)); @@ -178,9 +176,9 @@ public class FallbackRecentsTest { return mLauncher.getBackground().switchToOverview(); } - @NavigationModeSwitch + // b/143488140 + //@NavigationModeSwitch @Test - @Ignore // b/143488140 public void testOverview() { startAppFast(getAppPackageName()); startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR)); diff --git a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java index f20a0baf10..5f49805347 100644 --- a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java +++ b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java @@ -45,6 +45,8 @@ public class StartLauncherViaGestureTests extends AbstractQuickStepTest { @Before public void setUp() throws Exception { super.setUp(); + // b/143488140 + mLauncher.pressHome(); // Start an activity where the gestures start. startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR)); } From fb40075752bbb51cd9dbc21af2f7cf982e4692a2 Mon Sep 17 00:00:00 2001 From: Becky Qiu Date: Thu, 11 Jun 2020 16:17:21 -0700 Subject: [PATCH 25/35] [Overview Actions] onBackPressed for the modal state will go to overview. Test: local Bug: 157778187 Change-Id: Ie5252d39e54ca11de389dd698bfb7751fdf8f60e --- .../uioverrides/states/OverviewModalTaskState.java | 12 ++++++++++++ .../com/android/quickstep/TaskOverlayFactory.java | 6 ++++++ .../src/com/android/quickstep/views/RecentsView.java | 10 ++++++++++ 3 files changed, 28 insertions(+) diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java index d5b06871b9..fc0dcd5119 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java @@ -20,6 +20,7 @@ import android.graphics.Rect; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherState; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.quickstep.views.RecentsView; @@ -56,6 +57,17 @@ public class OverviewModalTaskState extends OverviewState { return 1.0f; } + @Override + public void onBackPressed(Launcher launcher) { + launcher.getStateManager().goToState(LauncherState.OVERVIEW); + RecentsView recentsView = launcher.getOverviewPanel(); + if (recentsView != null) { + recentsView.resetModalVisuals(); + } else { + super.onBackPressed(launcher); + } + } + public static float[] getOverviewScaleAndOffsetForModalState(BaseDraggingActivity activity) { Rect out = new Rect(); activity.getOverviewPanel().getTaskSize(out); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java index a6a08cb656..177f9a0b68 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java @@ -178,6 +178,12 @@ public class TaskOverlayFactory implements ResourceBasedOverride { public void reset() { } + /** + * Called when the system wants to reset the modal visuals. + */ + public void resetModalVisuals() { + } + /** * Gets the modal state system shortcut. */ diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java index 534ef7b689..22d306e06a 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java @@ -1759,6 +1759,16 @@ public abstract class RecentsView extends PagedView impl return Math.max(getWidth(), 1); } + /** + * Resets the visuals when exit modal state. + */ + public void resetModalVisuals() { + TaskView taskView = getCurrentPageTaskView(); + if (taskView != null) { + taskView.getThumbnail().getTaskOverlay().resetModalVisuals(); + } + } + private void updateDeadZoneRects() { // Get the deadzone rect surrounding the clear all button to not dismiss overview to home mClearAllButtonDeadZoneRect.setEmpty(); From e1fdf3e059bab512dcf104124667f62ae33e20cb Mon Sep 17 00:00:00 2001 From: Becky Qiu Date: Fri, 12 Jun 2020 14:53:02 -0700 Subject: [PATCH 26/35] [Overview Actions] Add a decelerateInterpolator for motion of select mode. Test: local Bug: 157777836 Change-Id: I8cbc14c41e9046aa5993fe4add010acdd612539a --- .../src/com/android/quickstep/views/RecentsView.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java index 534ef7b689..8c0b4b7e1b 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java @@ -30,6 +30,7 @@ import static com.android.launcher3.Utilities.mapToRange; import static com.android.launcher3.Utilities.squaredHypot; import static com.android.launcher3.Utilities.squaredTouchSlop; import static com.android.launcher3.anim.Interpolators.ACCEL; +import static com.android.launcher3.anim.Interpolators.ACCEL_0_75; import static com.android.launcher3.anim.Interpolators.ACCEL_2; import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; import static com.android.launcher3.anim.Interpolators.LINEAR; @@ -1731,7 +1732,7 @@ public abstract class RecentsView extends PagedView impl private void updatePageOffsets() { float offset = mAdjacentPageOffset * getWidth(); - float modalOffset = mTaskModalness * getWidth(); + float modalOffset = ACCEL_0_75.getInterpolation(mTaskModalness) * getWidth(); if (mIsRtl) { offset = -offset; modalOffset = -modalOffset; From 8da127f17598c5583d9d882dfbce05d1975096be Mon Sep 17 00:00:00 2001 From: thiruram Date: Fri, 12 Jun 2020 15:40:24 -0700 Subject: [PATCH 27/35] Updates StatsLogManager to log LauncherAtom.ItemInfo directly. This method is requied for logging tap on QSB with just container info. Bug: 154717227 Change-Id: I0c61c86724b4faafe4073a578b92a654ca23727a --- .../logging/StatsLogCompatManager.java | 22 +++++++++++++++++++ .../launcher3/logging/StatsLogManager.java | 11 ++++++++++ 2 files changed, 33 insertions(+) diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java index a88ba3c913..ebb44e2466 100644 --- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java +++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java @@ -97,6 +97,22 @@ public class StatsLogCompatManager extends StatsLogManager { log(event, DEFAULT_INSTANCE_ID, info); } + /** + * Logs an event. + * + * @param event an enum implementing EventEnum interface. + * @param atomItemInfo item typically containing app or task launch related information. + */ + @Override + public void log(EventEnum event, @Nullable LauncherAtom.ItemInfo atomItemInfo, int srcState, + int dstState) { + write(event, DEFAULT_INSTANCE_ID, + atomItemInfo == null ? LauncherAtom.ItemInfo.getDefaultInstance() : atomItemInfo, + null, + srcState, + dstState); + } + /** * Logs an event and accompanying {@link InstanceId} and {@link LauncherAtom.ItemInfo}. */ @@ -171,7 +187,13 @@ public class StatsLogCompatManager extends StatsLogManager { )).build(); } } + write(event, instanceId, atomInfo, info, srcState, dstState); + } + private static void write(EventEnum event, InstanceId instanceId, + LauncherAtom.ItemInfo atomInfo, + @Nullable ItemInfo info, + int srcState, int dstState) { if (IS_VERBOSE) { String name = (event instanceof Enum) ? ((Enum) event).name() : event.getId() + ""; diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java index e95c062c09..fee91b00a9 100644 --- a/src/com/android/launcher3/logging/StatsLogManager.java +++ b/src/com/android/launcher3/logging/StatsLogManager.java @@ -21,6 +21,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.LauncherState; import com.android.launcher3.R; +import com.android.launcher3.logger.LauncherAtom; import com.android.launcher3.logging.StatsLogUtils.LogStateProvider; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.util.ResourceBasedOverride; @@ -216,6 +217,16 @@ public class StatsLogManager implements ResourceBasedOverride { public void log(EventEnum event, @Nullable ItemInfo itemInfo) { } + /** + * Logs an event and accompanying {@link LauncherState}s. + * + * @param event an enum implementing EventEnum interface. + * @param launcherAtomItemInfo item typically containing app or task launch related information. + */ + public void log(EventEnum event, @Nullable LauncherAtom.ItemInfo launcherAtomItemInfo, + int srcState, int dstState) { + } + /** * Logs an event. * From 8e90ee03629ecab6075a4b4758beddcd67ed8977 Mon Sep 17 00:00:00 2001 From: Samuel Fufa Date: Sun, 14 Jun 2020 18:29:20 -0700 Subject: [PATCH 28/35] [race condition] Improve hotseat availability when launcher is recreated In cases where onCreate does not get called before bindPredictedItems, mHotseatPredictionController will be null. This results in the hotseat remaining empty until AiAi sends predictions. Bug: 158867468 Test: Manual Change-Id: I4f3c3fc41f489e96a9f91dc9505202ae9ce9cce1 --- .../com/android/launcher3/uioverrides/QuickstepLauncher.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index 3b45ec955d..77d71a3ff2 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -29,7 +29,6 @@ import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON; import android.content.Intent; import android.content.res.Configuration; -import android.os.Bundle; import android.util.Log; import android.view.View; @@ -90,8 +89,8 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { SystemUiProxy.INSTANCE.get(context).setShelfHeight(arg1 != 0, arg2); @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + protected void setupViews() { + super.setupViews(); if (FeatureFlags.ENABLE_HYBRID_HOTSEAT.get()) { mHotseatPredictionController = new HotseatPredictionController(this); mHotseatPredictionController.createPredictor(); From f6a179d3ae567122e77ebfc7959da0026a442d1a Mon Sep 17 00:00:00 2001 From: vadimt Date: Mon, 15 Jun 2020 10:19:15 -0700 Subject: [PATCH 29/35] Remove a comment that a line of code is a workaround Bug: 157099707 Change-Id: I417df10735438caf6fd7fd5833817b5c43a1e856 --- .../src/com/android/quickstep/StartLauncherViaGestureTests.java | 1 - 1 file changed, 1 deletion(-) diff --git a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java index 5f49805347..0c5b9ada5d 100644 --- a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java +++ b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java @@ -100,7 +100,6 @@ public class StartLauncherViaGestureTests extends AbstractQuickStepTest { // The test action. mLauncher.getBackground().switchToOverview(); } - // Workaround for b/157099707 mLauncher.pressHome(); } } \ No newline at end of file From b10e865e48bc7042b6f43b461346e688cb48e3a1 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Fri, 12 Jun 2020 16:41:08 -0700 Subject: [PATCH 30/35] Preventing parallel motion event dispatching from view system and event proxy 1) When view system is already dispatching an event, proxy-dispatch is restricted to gesture only and follow the gesture dispatching rule. 2) If a full-proxy-dispatch is going on, and view-dispatch comes in, view-dispatch takes over and proxy-dispatch is cancelled. 3) During gesture-only proxy dispatch, if view-dispatch already started a gesture, proxy dispatch is ignored. Otherwise view-dispatch is restricted to non-gesture dispatching only (and proxy-dispatch is already restricted to gesture only). Bug: 158130948 Change-Id: Ied351663e16beda5acf49a52bdefea881c18b9cf --- .../inputconsumers/OverviewInputConsumer.java | 20 +-- .../launcher3/views/BaseDragLayer.java | 120 +++++++++++------- 2 files changed, 77 insertions(+), 63 deletions(-) diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java index 11fee2f32a..32b1c580ba 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java @@ -36,8 +36,6 @@ import com.android.quickstep.util.ActiveGestureLog; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.InputMonitorCompat; -import java.util.function.Predicate; - /** * Input consumer for handling touch on the recents/Launcher activity. */ @@ -50,8 +48,6 @@ public class OverviewInputConsumer> private final InputMonitorCompat mInputMonitor; private final int[] mLocationOnScreen = new int[2]; - private final boolean mProxyTouch; - private final Predicate mEventReceiver; private final boolean mStartingInActivityBounds; private boolean mTargetHandledTouch; @@ -64,15 +60,7 @@ public class OverviewInputConsumer> mActivityInterface = gestureState.getActivityInterface(); mTarget = activity.getDragLayer(); - if (startingInActivityBounds) { - mEventReceiver = mTarget::dispatchTouchEvent; - mProxyTouch = true; - } else { - // Only proxy touches to controllers if we are starting touch from nav bar. - mEventReceiver = mTarget::proxyTouchEvent; - mTarget.getLocationOnScreen(mLocationOnScreen); - mProxyTouch = mTarget.prepareProxyEventStarting(); - } + mTarget.getLocationOnScreen(mLocationOnScreen); } @Override @@ -87,10 +75,6 @@ public class OverviewInputConsumer> @Override public void onMotionEvent(MotionEvent ev) { - if (!mProxyTouch) { - return; - } - int flags = ev.getEdgeFlags(); if (!mStartingInActivityBounds) { ev.setEdgeFlags(flags | Utilities.EDGE_NAV_BAR); @@ -99,7 +83,7 @@ public class OverviewInputConsumer> if (TestProtocol.sDebugTracing) { Log.d(TestProtocol.PAUSE_NOT_DETECTED, "OverviewInputConsumer"); } - boolean handled = mEventReceiver.test(ev); + boolean handled = mTarget.proxyTouchEvent(ev, mStartingInActivityBounds); ev.offsetLocation(mLocationOnScreen[0], mLocationOnScreen[1]); ev.setEdgeFlags(flags); diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java index f54edc223f..b010b4b94b 100644 --- a/src/com/android/launcher3/views/BaseDragLayer.java +++ b/src/com/android/launcher3/views/BaseDragLayer.java @@ -90,13 +90,23 @@ public abstract class BaseDragLayer } }; - // Touch is being dispatched through the normal view dispatch system - private static final int TOUCH_DISPATCHING_VIEW = 1 << 0; + // Touch coming from normal view system is being dispatched. + private static final int TOUCH_DISPATCHING_FROM_VIEW = 1 << 0; // Touch is being dispatched through the normal view dispatch system, and started at the - // system gesture region - private static final int TOUCH_DISPATCHING_GESTURE = 1 << 1; - // Touch is being dispatched through a proxy from InputMonitor - private static final int TOUCH_DISPATCHING_PROXY = 1 << 2; + // system gesture region. In this case we prevent internal gesture handling and only allow + // normal view event handling. + private static final int TOUCH_DISPATCHING_FROM_VIEW_GESTURE_REGION = 1 << 1; + // Touch coming from InputMonitor proxy is being dispatched 'only to gestures'. Note that both + // this and view-system can be active at the same time where view-system would go to the views, + // and this would go to the gestures. + // Note that this is not set when events are coming from proxy, but going through full dispatch + // process (both views and gestures) to allow view-system to easily take over in case it + // comes later. + private static final int TOUCH_DISPATCHING_FROM_PROXY = 1 << 2; + // ACTION_DOWN has been dispatched to child views and ACTION_UP or ACTION_CANCEL is pending. + // Note that the event source can either be view-dispatching or proxy-dispatching based on if + // TOUCH_DISPATCHING_VIEW is present or not. + private static final int TOUCH_DISPATCHING_TO_VIEW_IN_PROGRESS = 1 << 3; protected final float[] mTmpXY = new float[2]; protected final float[] mTmpRectPoints = new float[4]; @@ -204,7 +214,8 @@ public abstract class BaseDragLayer protected boolean findActiveController(MotionEvent ev) { mActiveController = null; - if ((mTouchDispatchState & (TOUCH_DISPATCHING_GESTURE | TOUCH_DISPATCHING_PROXY)) == 0) { + if ((mTouchDispatchState & (TOUCH_DISPATCHING_FROM_VIEW_GESTURE_REGION + | TOUCH_DISPATCHING_FROM_PROXY)) == 0) { // Only look for controllers if we are not dispatching from gesture area and proxy is // not active mActiveController = findControllerToHandleTouch(ev); @@ -283,19 +294,28 @@ public abstract class BaseDragLayer public boolean dispatchTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case ACTION_DOWN: { - mTouchDispatchState |= TOUCH_DISPATCHING_VIEW; + if ((mTouchDispatchState & TOUCH_DISPATCHING_TO_VIEW_IN_PROGRESS) != 0) { + // Cancel the previous touch + int action = ev.getAction(); + ev.setAction(ACTION_CANCEL); + super.dispatchTouchEvent(ev); + ev.setAction(action); + } + mTouchDispatchState |= TOUCH_DISPATCHING_FROM_VIEW + | TOUCH_DISPATCHING_TO_VIEW_IN_PROGRESS; if (isEventInLauncher(ev)) { - mTouchDispatchState &= ~TOUCH_DISPATCHING_GESTURE; + mTouchDispatchState &= ~TOUCH_DISPATCHING_FROM_VIEW_GESTURE_REGION; } else { - mTouchDispatchState |= TOUCH_DISPATCHING_GESTURE; + mTouchDispatchState |= TOUCH_DISPATCHING_FROM_VIEW_GESTURE_REGION; } break; } case ACTION_CANCEL: case ACTION_UP: - mTouchDispatchState &= ~TOUCH_DISPATCHING_GESTURE; - mTouchDispatchState &= ~TOUCH_DISPATCHING_VIEW; + mTouchDispatchState &= ~TOUCH_DISPATCHING_FROM_VIEW_GESTURE_REGION; + mTouchDispatchState &= ~TOUCH_DISPATCHING_FROM_VIEW; + mTouchDispatchState &= ~TOUCH_DISPATCHING_TO_VIEW_IN_PROGRESS; break; } super.dispatchTouchEvent(ev); @@ -304,44 +324,54 @@ public abstract class BaseDragLayer return true; } - /** - * Called before we are about to receive proxy events. - * - * @return false if we can't handle proxy at this time - */ - public boolean prepareProxyEventStarting() { - mProxyTouchController = null; - if ((mTouchDispatchState & TOUCH_DISPATCHING_VIEW) != 0 && mActiveController != null) { - // We are already dispatching using view system and have an active controller, we can't - // handle another controller. - - // This flag was already cleared in proxy ACTION_UP or ACTION_CANCEL. Added here just - // to be safe - mTouchDispatchState &= ~TOUCH_DISPATCHING_PROXY; - return false; - } - - mTouchDispatchState |= TOUCH_DISPATCHING_PROXY; - return true; - } - /** * Proxies the touch events to the gesture handlers */ - public boolean proxyTouchEvent(MotionEvent ev) { - boolean handled; - if (mProxyTouchController != null) { - handled = mProxyTouchController.onControllerTouchEvent(ev); + public boolean proxyTouchEvent(MotionEvent ev, boolean allowViewDispatch) { + int actionMasked = ev.getActionMasked(); + boolean isViewDispatching = (mTouchDispatchState & TOUCH_DISPATCHING_FROM_VIEW) != 0; + + // Only do view dispatch if another view-dispatching is not running, or we already started + // proxy-dispatching before. Note that view-dispatching can always take over the proxy + // dispatching at anytime, but not vice-versa. + allowViewDispatch = allowViewDispatch && !isViewDispatching + && (actionMasked == ACTION_DOWN + || ((mTouchDispatchState & TOUCH_DISPATCHING_TO_VIEW_IN_PROGRESS) != 0)); + + if (allowViewDispatch) { + mTouchDispatchState |= TOUCH_DISPATCHING_TO_VIEW_IN_PROGRESS; + super.dispatchTouchEvent(ev); + + if (actionMasked == ACTION_UP || actionMasked == ACTION_CANCEL) { + mTouchDispatchState &= ~TOUCH_DISPATCHING_TO_VIEW_IN_PROGRESS; + mTouchDispatchState &= ~TOUCH_DISPATCHING_FROM_PROXY; + } + return true; } else { - mProxyTouchController = findControllerToHandleTouch(ev); - handled = mProxyTouchController != null; + boolean handled; + if (mProxyTouchController != null) { + handled = mProxyTouchController.onControllerTouchEvent(ev); + } else { + if (actionMasked == ACTION_DOWN) { + if (isViewDispatching && mActiveController != null) { + // A controller is already active, we can't initiate our own controller + mTouchDispatchState &= ~TOUCH_DISPATCHING_FROM_PROXY; + } else { + // We will control the handler via proxy + mTouchDispatchState |= TOUCH_DISPATCHING_FROM_PROXY; + } + } + if ((mTouchDispatchState & TOUCH_DISPATCHING_FROM_PROXY) != 0) { + mProxyTouchController = findControllerToHandleTouch(ev); + } + handled = mProxyTouchController != null; + } + if (actionMasked == ACTION_UP || actionMasked == ACTION_CANCEL) { + mProxyTouchController = null; + mTouchDispatchState &= ~TOUCH_DISPATCHING_FROM_PROXY; + } + return handled; } - int action = ev.getAction(); - if (action == ACTION_UP || action == ACTION_CANCEL) { - mProxyTouchController = null; - mTouchDispatchState &= ~TOUCH_DISPATCHING_PROXY; - } - return handled; } /** From f3cd3762c9e45ad5738158211d284d3e6a26755f Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Fri, 12 Jun 2020 18:07:13 -0500 Subject: [PATCH 31/35] Don't set mLikelyToStartNewTask=true before slop for first gesture We should only set it to true before the slop when continuing the gesture, otherwise gestures to home could attach the adjacent task view before the transition even starts. Bug: 158855957 Change-Id: I86eba9bad9c85e05d5274d7396160762a28e5cf1 --- .../inputconsumers/OtherActivityInputConsumer.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java index 14215a1f67..a9f138edbb 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java @@ -267,10 +267,6 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC if (!mPassedSlopOnThisGesture && passedSlop) { mPassedSlopOnThisGesture = true; } - // Until passing slop, we don't know what direction we're going, so assume we might - // be quick switching to avoid translating recents away when continuing the gesture. - boolean isLikelyToStartNewTask = !mPassedSlopOnThisGesture - || horizontalDist > upDist; if (!mPassedPilferInputSlop) { if (passedSlop) { @@ -304,6 +300,13 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC } if (mDeviceState.isFullyGesturalNavMode()) { + // Until passing slop, we don't know what direction we're going, so assume + // we're quick switching to avoid translating recents away when continuing + // the gesture. + boolean haveNotPassedSlopOnContinuedGesture = + !mPassedSlopOnThisGesture && mPassedPilferInputSlop; + boolean isLikelyToStartNewTask = haveNotPassedSlopOnContinuedGesture + || horizontalDist > upDist; mMotionPauseDetector.setDisallowPause(upDist < mMotionPauseMinDisplacement || isLikelyToStartNewTask); mMotionPauseDetector.addPosition(ev); From 730c238b8dd726f62efe844bdd5b481a96d19b83 Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Fri, 12 Jun 2020 00:44:34 -0700 Subject: [PATCH 32/35] Call displayCompletions couple frames after selectAll is called Bug: 158710542 Change-Id: I295adce9d84bb82c4af27b7e54693ce4c64004cc --- src/com/android/launcher3/folder/FolderNameEditText.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/com/android/launcher3/folder/FolderNameEditText.java b/src/com/android/launcher3/folder/FolderNameEditText.java index edf2c705e9..6038a053d6 100644 --- a/src/com/android/launcher3/folder/FolderNameEditText.java +++ b/src/com/android/launcher3/folder/FolderNameEditText.java @@ -70,8 +70,11 @@ public class FolderNameEditText extends ExtendedEditText { for (int i = 0; i < cnt; i++) { cInfo[i] = new CompletionInfo(i, i, suggestList.get(i)); } - post(() -> getContext().getSystemService(InputMethodManager.class) - .displayCompletions(this, cInfo)); + // post it to future frame so that onSelectionChanged, onFocusChanged, all other + // TextView flag change and IME animation has settled. Ideally, there should be IMM + // callback to notify when the IME animation and state handling is finished. + postDelayed(() -> getContext().getSystemService(InputMethodManager.class) + .displayCompletions(this, cInfo), 40 /* 2~3 frame delay */); } /** From f1a8f47a4abbb91ff176fa1101852e4ba40d9c7b Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Mon, 15 Jun 2020 16:41:50 -0500 Subject: [PATCH 33/35] Add null check before applying fullscreen params Bug: 159026796 Change-Id: I5c1a0ca26c8e4a187e2217870b27289ecf18238e --- .../src/com/android/quickstep/views/TaskView.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java index 3b1210e2ae..f2e4127537 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java @@ -975,6 +975,9 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { } void updateCurrentFullscreenParams(PreviewPositionHelper previewPositionHelper) { + if (getRecentsView() == null) { + return; + } mCurrentFullscreenParams.setProgress( mFullscreenProgress, getRecentsView().getScaleX(), From 817054d0005b038c26e21cab8055648ecb4c5275 Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Mon, 15 Jun 2020 14:12:53 -0700 Subject: [PATCH 34/35] fix a11y issue where scroll next can still be triggered on final page in RecentsView Bug: 151450844 Test: manual verification with following steps 1. launch a few apps 2. swipe up from bottom to bring up RecentsView 3. enable talkback 4. perform a scroll next a11y gesture (without lifting finger, swipe right then left) 5. verify nothing happens (as opposed to pushing the page back a little) Change-Id: I6dea2559592bdaa7227a2e12ce0565d6d7b7f4a1 --- .../src/com/android/quickstep/views/RecentsView.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java index 873c672625..2066d52c36 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java @@ -2111,6 +2111,12 @@ public abstract class RecentsView extends PagedView impl return mClearAllButton; } + @Override + protected boolean onOverscroll(int amount) { + // overscroll should only be accepted on -1 direction (for clear all button) + if ((amount > 0 && !mIsRtl) || (amount < 0 && mIsRtl)) return false; + return super.onOverscroll(amount); + } /** * @return How many pixels the running task is offset on the currently laid out dominant axis. From e9c4f401bd8a9728e77483e45b41adeaaff2653c Mon Sep 17 00:00:00 2001 From: Samuel Fufa Date: Sun, 14 Jun 2020 22:39:51 -0700 Subject: [PATCH 35/35] [WW logging] Log rankings for app launches Bug: 158219113 Change-Id: Ib6db4e73e48ff27ca9d3a5348eea42e1f534dba1 --- .../PredictionUiStateManager.java | 52 ++++++++++++++----- .../HotseatPredictionController.java | 48 ++++++++++++++++- .../uioverrides/QuickstepLauncher.java | 11 ++++ .../logging/StatsLogCompatManager.java | 23 +++++++- .../launcher3/BaseDraggingActivity.java | 9 +++- .../launcher3/logging/InstanceIdSequence.java | 7 +++ .../launcher3/logging/StatsLogManager.java | 17 +++++- 7 files changed, 149 insertions(+), 18 deletions(-) diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java index f881610b77..01135700db 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java @@ -18,12 +18,12 @@ package com.android.launcher3.appprediction; import static com.android.launcher3.LauncherState.BACKGROUND_APP; import static com.android.launcher3.LauncherState.OVERVIEW; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALL_APPS_RANKED; import android.app.prediction.AppPredictor; import android.app.prediction.AppTarget; import android.content.ComponentName; import android.content.Context; -import android.os.Process; import androidx.annotation.NonNull; @@ -36,9 +36,10 @@ import com.android.launcher3.LauncherState; import com.android.launcher3.Utilities; import com.android.launcher3.allapps.AllAppsContainerView; import com.android.launcher3.allapps.AllAppsStore.OnUpdateListener; -import com.android.launcher3.hybridhotseat.HotseatFileLog; import com.android.launcher3.hybridhotseat.HotseatPredictionController; import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver; +import com.android.launcher3.logger.LauncherAtom; +import com.android.launcher3.logging.InstanceId; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.ItemInfoWithIcon; import com.android.launcher3.shortcuts.ShortcutKey; @@ -50,6 +51,7 @@ import com.android.launcher3.util.MainThreadInitializedObject; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.OptionalInt; import java.util.stream.IntStream; /** @@ -303,6 +305,41 @@ public class PredictionUiStateManager implements StateListener, return mCurrentState; } + /** + * Logs ranking info for launched app within all apps prediction. + * Only applicable when {@link ItemInfo#itemType} is one of the followings: + * {@link LauncherSettings.Favorites#ITEM_TYPE_APPLICATION}, + * {@link LauncherSettings.Favorites#ITEM_TYPE_SHORTCUT}, + * {@link LauncherSettings.Favorites#ITEM_TYPE_DEEP_SHORTCUT} + */ + public void logLaunchedAppRankingInfo(@NonNull ItemInfo itemInfo, InstanceId instanceId) { + if (itemInfo.getTargetComponent() == null || itemInfo.user == null + || (itemInfo.itemType != LauncherSettings.Favorites.ITEM_TYPE_APPLICATION + && itemInfo.itemType != LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT + && itemInfo.itemType != LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT)) { + return; + } + + Launcher launcher = Launcher.getLauncher(mAppsView.getContext()); + final ComponentKey k = new ComponentKey(itemInfo.getTargetComponent(), itemInfo.user); + final List predictedApps = getCurrentState().apps; + OptionalInt rank = IntStream.range(0, predictedApps.size()) + .filter((i) -> k.equals(predictedApps.get(i).getComponentKey())) + .findFirst(); + if (!rank.isPresent()) { + return; + } + + LauncherAtom.ItemInfo.Builder atomBuilder = LauncherAtom.ItemInfo.newBuilder(); + atomBuilder.setRank(rank.getAsInt()); + atomBuilder.setContainerInfo( + LauncherAtom.ContainerInfo.newBuilder().setPredictionContainer( + LauncherAtom.PredictionContainer.newBuilder().build()).build()); + launcher.getStatsLogManager().log(LAUNCHER_ALL_APPS_RANKED, instanceId, + atomBuilder.build()); + } + + /** * Fill in predicted_rank field based on app prediction. * Only applicable when {@link ItemInfo#itemType} is one of the followings: @@ -313,17 +350,6 @@ public class PredictionUiStateManager implements StateListener, public static void fillInPredictedRank( @NonNull ItemInfo itemInfo, @NonNull LauncherLogProto.Target target) { - HotseatFileLog hotseatFileLog = HotseatFileLog.INSTANCE.getNoCreate(); - - if (hotseatFileLog != null && itemInfo != null && Utilities.IS_DEBUG_DEVICE) { - final String pkg = itemInfo.getTargetComponent() != null - ? itemInfo.getTargetComponent().getPackageName() : "unknown"; - hotseatFileLog.log("UserEvent", - "appLaunch: packageName:" + pkg + ",isWorkApp:" + (itemInfo.user != null - && !Process.myUserHandle().equals(itemInfo.user)) - + ",launchLocation:" + itemInfo.container); - } - final PredictionUiStateManager manager = PredictionUiStateManager.INSTANCE.getNoCreate(); if (manager == null || itemInfo.getTargetComponent() == null || itemInfo.user == null || (itemInfo.itemType != LauncherSettings.Favorites.ITEM_TYPE_APPLICATION diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java index 6ca07bb4a0..30a34e46eb 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java @@ -18,6 +18,7 @@ package com.android.launcher3.hybridhotseat; import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_GRID; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; import static com.android.launcher3.hybridhotseat.HotseatEduController.SETTINGS_ACTION; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOTSEAT_RANKED; import android.animation.Animator; import android.animation.AnimatorSet; @@ -29,6 +30,7 @@ import android.app.prediction.AppTarget; import android.app.prediction.AppTargetEvent; import android.content.ComponentName; import android.content.Intent; +import android.os.Process; import android.util.Log; import android.view.View; import android.view.ViewGroup; @@ -52,6 +54,8 @@ import com.android.launcher3.appprediction.DynamicItemCache; import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.icons.IconCache; +import com.android.launcher3.logger.LauncherAtom; +import com.android.launcher3.logging.InstanceId; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; @@ -185,7 +189,6 @@ public class HotseatPredictionController implements DragController.DragListener, /** * Returns if hotseat client has predictions - * @return */ public boolean hasPredictions() { return !mComponentKeyMappers.isEmpty(); @@ -358,6 +361,7 @@ public class HotseatPredictionController implements DragController.DragListener, updateDependencies(); bindItems(items, false, null); } + private void setPredictedApps(List appTargets) { mComponentKeyMappers.clear(); if (appTargets.isEmpty()) { @@ -635,6 +639,48 @@ public class HotseatPredictionController implements DragController.DragListener, mHotseat.fillInLogContainerData(childInfo, child, parents); } + /** + * Logs rank info based on current list of predicted items + */ + public void logLaunchedAppRankingInfo(@NonNull ItemInfo itemInfo, InstanceId instanceId) { + if (Utilities.IS_DEBUG_DEVICE) { + final String pkg = itemInfo.getTargetComponent() != null + ? itemInfo.getTargetComponent().getPackageName() : "unknown"; + HotseatFileLog.INSTANCE.get(mLauncher).log("UserEvent", + "appLaunch: packageName:" + pkg + ",isWorkApp:" + (itemInfo.user != null + && !Process.myUserHandle().equals(itemInfo.user)) + + ",launchLocation:" + itemInfo.container); + } + + final ComponentKey k = new ComponentKey(itemInfo.getTargetComponent(), itemInfo.user); + + final List predictedApps = new ArrayList<>(mComponentKeyMappers); + OptionalInt rank = IntStream.range(0, predictedApps.size()) + .filter((i) -> k.equals(predictedApps.get(i).getComponentKey())) + .findFirst(); + if (!rank.isPresent()) { + return; + } + LauncherAtom.PredictedHotseatContainer.Builder containerBuilder = + LauncherAtom.PredictedHotseatContainer.newBuilder(); + LauncherAtom.ItemInfo.Builder atomBuilder = LauncherAtom.ItemInfo.newBuilder(); + int cardinality = 0; + for (PredictedAppIcon icon : getPredictedIcons()) { + ItemInfo info = (ItemInfo) icon.getTag(); + cardinality |= 1 << info.screenId; + } + containerBuilder.setCardinality(cardinality); + atomBuilder.setRank(rank.getAsInt()); + if (itemInfo.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION) { + containerBuilder.setIndex(rank.getAsInt()); + } + atomBuilder.setContainerInfo( + LauncherAtom.ContainerInfo.newBuilder().setPredictedHotseatContainer( + containerBuilder).build()); + mLauncher.getStatsLogManager().log(LAUNCHER_HOTSEAT_RANKED, instanceId, + atomBuilder.build()); + } + private class PinPrediction extends SystemShortcut { private PinPrediction(QuickstepLauncher target, ItemInfo itemInfo) { diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index 3b45ec955d..4d307e2a5d 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -42,10 +42,12 @@ import com.android.launcher3.LauncherState; import com.android.launcher3.Workspace; import com.android.launcher3.allapps.DiscoveryBounce; import com.android.launcher3.anim.AnimatorPlaybackController; +import com.android.launcher3.appprediction.PredictionUiStateManager; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.folder.Folder; import com.android.launcher3.hybridhotseat.HotseatEduController; import com.android.launcher3.hybridhotseat.HotseatPredictionController; +import com.android.launcher3.logging.InstanceId; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; @@ -112,6 +114,15 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { } } + @Override + protected void logAppLaunch(ItemInfo info, InstanceId instanceId) { + super.logAppLaunch(info, instanceId); + if (mHotseatPredictionController != null) { + mHotseatPredictionController.logLaunchedAppRankingInfo(info, instanceId); + } + PredictionUiStateManager.INSTANCE.get(this).logLaunchedAppRankingInfo(info, instanceId); + } + @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java index ebb44e2466..e820b3f6c5 100644 --- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java +++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java @@ -78,7 +78,7 @@ public class StatsLogCompatManager extends StatsLogManager { */ @Override public void log(EventEnum event) { - log(event, DEFAULT_INSTANCE_ID, null); + log(event, DEFAULT_INSTANCE_ID, (ItemInfo) null); } /** @@ -86,7 +86,7 @@ public class StatsLogCompatManager extends StatsLogManager { */ @Override public void log(EventEnum event, InstanceId instanceId) { - log(event, instanceId, null); + log(event, instanceId, (ItemInfo) null); } /** @@ -97,6 +97,25 @@ public class StatsLogCompatManager extends StatsLogManager { log(event, DEFAULT_INSTANCE_ID, info); } + /** + * Logs an event. + * + * @param event an enum implementing EventEnum interface. + * @param atomInfo item typically containing app or task launch related information. + */ + public void log(EventEnum event, InstanceId instanceId, LauncherAtom.ItemInfo atomInfo) { + LauncherAppState.getInstance(sContext).getModel().enqueueModelUpdateTask( + new BaseModelUpdateTask() { + @Override + public void execute(LauncherAppState app, BgDataModel dataModel, + AllAppsList apps) { + write(event, instanceId, atomInfo, null, + LAUNCHER_UICHANGED__DST_STATE__HOME, + LAUNCHER_UICHANGED__DST_STATE__BACKGROUND); + } + }); + } + /** * Logs an event. * diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java index 88dbfd6e37..61ecdd7da6 100644 --- a/src/com/android/launcher3/BaseDraggingActivity.java +++ b/src/com/android/launcher3/BaseDraggingActivity.java @@ -43,6 +43,8 @@ import android.widget.Toast; import androidx.annotation.Nullable; import com.android.launcher3.LauncherSettings.Favorites; +import com.android.launcher3.logging.InstanceId; +import com.android.launcher3.logging.InstanceIdSequence; import com.android.launcher3.model.AppLaunchTracker; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; @@ -188,7 +190,8 @@ public abstract class BaseDraggingActivity extends BaseActivity } getUserEventDispatcher().logAppLaunch(v, intent, user); if (item != null) { - getStatsLogManager().log(LAUNCHER_APP_LAUNCH_TAP, item); + InstanceId instanceId = new InstanceIdSequence().newInstanceId(); + logAppLaunch(item, instanceId); } return true; } catch (NullPointerException|ActivityNotFoundException|SecurityException e) { @@ -198,6 +201,10 @@ public abstract class BaseDraggingActivity extends BaseActivity return false; } + protected void logAppLaunch(ItemInfo info, InstanceId instanceId) { + getStatsLogManager().log(LAUNCHER_APP_LAUNCH_TAP, instanceId, info); + } + private void startShortcutIntentSafely(Intent intent, Bundle optsBundle, ItemInfo info, @Nullable String sourceContainer) { try { diff --git a/src/com/android/launcher3/logging/InstanceIdSequence.java b/src/com/android/launcher3/logging/InstanceIdSequence.java index a4b795352a..ee6a5a42ba 100644 --- a/src/com/android/launcher3/logging/InstanceIdSequence.java +++ b/src/com/android/launcher3/logging/InstanceIdSequence.java @@ -44,6 +44,13 @@ public class InstanceIdSequence { mInstanceIdMax = min(max(1, instanceIdMax), InstanceId.INSTANCE_ID_MAX); } + /** + * Constructs a sequence with identifiers [1, InstanceId.INSTANCE_ID_MAX]. + */ + public InstanceIdSequence() { + this(InstanceId.INSTANCE_ID_MAX); + } + /** * Gets the next instance from the sequence. Safe for concurrent use. * @return new InstanceId diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java index fee91b00a9..c84b9fe487 100644 --- a/src/com/android/launcher3/logging/StatsLogManager.java +++ b/src/com/android/launcher3/logging/StatsLogManager.java @@ -143,7 +143,13 @@ public class StatsLogManager implements ResourceBasedOverride { LAUNCHER_HOTSEAT_EDU_DENY(481), @UiEvent(doc = "Hotseat education tip shown") - LAUNCHER_HOTSEAT_EDU_ONLY_TIP(482); + LAUNCHER_HOTSEAT_EDU_ONLY_TIP(482), + + @UiEvent(doc = "App launch ranking logged for all apps predictions") + LAUNCHER_ALL_APPS_RANKED(552), + + @UiEvent(doc = "App launch ranking logged for hotseat predictions)") + LAUNCHER_HOTSEAT_RANKED(553); // ADD MORE private final int mId; @@ -217,6 +223,15 @@ public class StatsLogManager implements ResourceBasedOverride { public void log(EventEnum event, @Nullable ItemInfo itemInfo) { } + /** + * Logs an event. + * + * @param event an enum implementing EventEnum interface. + * @param atomInfo item typically containing app or task launch related information. + */ + public void log(EventEnum event, InstanceId instanceId, LauncherAtom.ItemInfo atomInfo) { + } + /** * Logs an event and accompanying {@link LauncherState}s. *