diff --git a/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java b/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java index ad21106759..e649ce1de4 100644 --- a/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java +++ b/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java @@ -18,9 +18,12 @@ package com.android.launcher3.testing; import static android.graphics.Bitmap.Config.ARGB_8888; +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; + import android.content.Context; import android.graphics.Bitmap; import android.graphics.Color; +import android.os.Binder; import android.os.Bundle; import android.os.Debug; import android.system.Os; @@ -28,6 +31,9 @@ import android.view.View; import androidx.annotation.Keep; +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherSettings; + import java.util.ArrayList; import java.util.Collection; import java.util.LinkedList; @@ -165,6 +171,19 @@ public class DebugTestInformationHandler extends TestInformationHandler { return response; } + case TestProtocol.REQUEST_CLEAR_DATA: { + final long identity = Binder.clearCallingIdentity(); + try { + LauncherSettings.Settings.call(mContext.getContentResolver(), + LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB); + MAIN_EXECUTOR.submit(() -> + LauncherAppState.getInstance(mContext).getModel().forceReload()); + return response; + } finally { + Binder.restoreCallingIdentity(identity); + } + } + default: return super.call(method); } diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto index 98ce9af2d6..561196941c 100644 --- a/protos/launcher_atom.proto +++ b/protos/launcher_atom.proto @@ -71,6 +71,15 @@ message PredictionContainer { // Represents the apps container within search results. message SearchResultContainer { + + // Length of search term. + optional int32 query_length = 1; + + // Container from where search was invoked. + oneof ParentContainer { + WorkspaceContainer workspace = 2; + AllAppsContainer all_apps_container = 3; + } } // Container for package specific shortcuts to deep links and notifications. diff --git a/quickstep/recents_ui_overrides/res/layout/predicted_hotseat_edu.xml b/quickstep/recents_ui_overrides/res/layout/predicted_hotseat_edu.xml index 36c9b00e07..1dab48267b 100644 --- a/quickstep/recents_ui_overrides/res/layout/predicted_hotseat_edu.xml +++ b/quickstep/recents_ui_overrides/res/layout/predicted_hotseat_edu.xml @@ -90,6 +90,7 @@ android:layout_height="wrap_content" android:background="?android:attr/selectableItemBackground" android:text="@string/hotseat_edu_dismiss" + android:layout_gravity="start|center_vertical" android:textColor="@android:color/white"/> diff --git a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java index 3375c53124..cf5659c7d4 100644 --- a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java +++ b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java @@ -68,13 +68,13 @@ class OrientationTouchTransformer { private Resources mResources; private OrientationRectF mLastRectTouched; /** - * The rotation of the last touched nav bar. Derived from {@link #mLastRectTouched}, but has a - * longer lifetime than the rect. Note this is different than {@link #mQuickStepStartingRotation} - * as it always updates its value on every touch whereas mQuickstepStartingRotation only - * updates when device rotation matches touch rotation. Maybe this will be only one necessary - * after TODO(b/154580671) is in. TBD. + * The rotation of the last touched nav bar, whether that be through the last region the user + * touched down on or valid rotation user turned their device to. + * Note this is different than + * {@link #mQuickStepStartingRotation} as it always updates its value on every touch whereas + * mQuickstepStartingRotation only updates when device rotation matches touch rotation. */ - private int mLastRectRotation; + private int mActiveTouchRotation; private SysUINavigationMode.Mode mMode; private QuickStepContractInfo mContractInfo; @@ -159,12 +159,26 @@ class OrientationTouchTransformer { if (mEnableMultipleRegions) { mQuickStepStartingRotation = info.rotation; } else { - mLastRectRotation = 0; + mActiveTouchRotation = 0; mQuickStepStartingRotation = QUICKSTEP_ROTATION_UNINITIALIZED; } resetSwipeRegions(info); } + /** + * Call when removing multiple regions to swipe from, but still in active quickswitch mode (task + * list is still frozen). + * Ex. This would be called when user has quickswitched to the same app rotation that + * they started quickswitching in, indicating that extra nav regions can be ignored. Calling + * this will update the value of {@link #mActiveTouchRotation} + * + * @param displayInfo The display whos rotation will be used as the current active rotation + */ + void setSingleActiveRegion(DefaultDisplay.Info displayInfo) { + mActiveTouchRotation = displayInfo.rotation; + resetSwipeRegions(displayInfo); + } + /** * Only saves the swipe region represented by {@param region}, clears the * rest from {@link #mSwipeTouchRegions} @@ -258,7 +272,7 @@ class OrientationTouchTransformer { } int getCurrentActiveRotation() { - return mLastRectRotation; + return mActiveTouchRotation; } int getQuickStepStartingRotation() { @@ -303,8 +317,9 @@ class OrientationTouchTransformer { Log.d(TestProtocol.NO_SWIPE_TO_HOME, "setting mLastRectTouched"); } mLastRectTouched = rect; - mLastRectRotation = rect.mRotation; - if (mEnableMultipleRegions && mCurrentDisplayRotation == mLastRectRotation) { + mActiveTouchRotation = rect.mRotation; + if (mEnableMultipleRegions + && mCurrentDisplayRotation == mActiveTouchRotation) { // TODO(b/154580671) might make this block unnecessary // Start a touch session for the default nav region for the display mQuickStepStartingRotation = mLastRectTouched.mRotation; diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java index 79b38f23e1..0a70bd6cfe 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java @@ -151,7 +151,7 @@ public class RecentsAnimationDeviceState implements * sysui to adjust the navbar. */ private OrientationEventListener mOrientationListener; - private int mPreviousRotation = ROTATION_0; + private int mSensorRotation = ROTATION_0; /** * This is the configuration of the foreground app or the app that will be in the foreground * once a quickstep gesture finishes. @@ -246,18 +246,18 @@ public class RecentsAnimationDeviceState implements @Override public void onOrientationChanged(int degrees) { int newRotation = RecentsOrientedState.getRotationForUserDegreesRotated(degrees, - mPreviousRotation); - if (newRotation == mPreviousRotation) { + mSensorRotation); + if (newRotation == mSensorRotation) { return; } - mPreviousRotation = newRotation; + mSensorRotation = newRotation; mPrioritizeDeviceRotation = true; if (newRotation == mCurrentAppRotation) { // When user rotates device to the orientation of the foreground app after // quickstepping - toggleSecondaryNavBarsForRotation(false); + toggleSecondaryNavBarsForRotation(); } } }; @@ -339,14 +339,16 @@ public class RecentsAnimationDeviceState implements 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) + * a) if this is coming from an activity rotation OR + * aa) we launch an app in the orientation that user is already in + * b) We're not in overview, since overview will always be portrait (w/o home rotation) + * c) We're actively in quickswitch mode */ if ((mPrioritizeDeviceRotation - || mCurrentAppRotation == mPreviousRotation) // switch to an app of orientation user is in - && !mInOverview) { - toggleSecondaryNavBarsForRotation(false); + || mCurrentAppRotation == mSensorRotation) // switch to an app of orientation user is in + && !mInOverview + && mTaskListFrozen) { + toggleSecondaryNavBarsForRotation(); } } @@ -461,7 +463,9 @@ public class RecentsAnimationDeviceState implements * @return whether SystemUI is in a state where we can start a system gesture. */ public boolean canStartSystemGesture() { - return (mSystemUiStateFlags & SYSUI_STATE_NAV_BAR_HIDDEN) == 0 + boolean canStartWithNavHidden = (mSystemUiStateFlags & SYSUI_STATE_NAV_BAR_HIDDEN) == 0 + || mTaskListFrozen; + return canStartWithNavHidden && (mSystemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) == 0 && (mSystemUiStateFlags & SYSUI_STATE_QUICK_SETTINGS_EXPANDED) == 0 && ((mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) == 0 @@ -634,29 +638,26 @@ public class RecentsAnimationDeviceState implements } private void enableMultipleRegions(boolean enable) { - toggleSecondaryNavBarsForRotation(enable); - if (enable && !TestProtocol.sDisableSensorRotation) { + mOrientationTouchTransformer.enableMultipleRegions(enable, mDefaultDisplay.getInfo()); + notifySysuiOfCurrentRotation(mOrientationTouchTransformer.getQuickStepStartingRotation()); + if (enable && !mInOverview && !TestProtocol.sDisableSensorRotation) { + // Clear any previous state from sensor manager + mSensorRotation = mCurrentAppRotation; mOrientationListener.enable(); } else { mOrientationListener.disable(); } } - private void notifySysuiForRotation(int rotation) { - UI_HELPER_EXECUTOR.execute(() -> - SystemUiProxy.INSTANCE.get(mContext).onQuickSwitchToNewTask(rotation)); - } - public void onStartGesture() { if (mTaskListFrozen) { // Prioritize whatever nav bar user touches once in quickstep // This case is specifically when user changes what nav bar they are using mid // quickswitch session before tasks list is unfrozen - notifySysuiForRotation(mOrientationTouchTransformer.getCurrentActiveRotation()); + notifySysuiOfCurrentRotation(mOrientationTouchTransformer.getCurrentActiveRotation()); } } - void onEndTargetCalculated(GestureState.GestureEndTarget endTarget, BaseActivityInterface activityInterface) { if (endTarget == GestureState.GestureEndTarget.RECENTS) { @@ -673,7 +674,8 @@ public class RecentsAnimationDeviceState implements // First gesture to start quickswitch enableMultipleRegions(true); } else { - notifySysuiForRotation(mOrientationTouchTransformer.getCurrentActiveRotation()); + notifySysuiOfCurrentRotation( + mOrientationTouchTransformer.getCurrentActiveRotation()); } // A new gesture is starting, reset the current device rotation @@ -685,7 +687,7 @@ public class RecentsAnimationDeviceState implements // touched nav bar but didn't go anywhere and not quickswitching, do nothing return; } - notifySysuiForRotation(mOrientationTouchTransformer.getCurrentActiveRotation()); + notifySysuiOfCurrentRotation(mOrientationTouchTransformer.getCurrentActiveRotation()); } } @@ -697,13 +699,10 @@ public class RecentsAnimationDeviceState implements /** * 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()); + private void toggleSecondaryNavBarsForRotation() { + mOrientationTouchTransformer.setSingleActiveRegion(mDefaultDisplay.getInfo()); + notifySysuiOfCurrentRotation(mOrientationTouchTransformer.getCurrentActiveRotation()); } public int getCurrentActiveRotation() { diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java index 20348017fe..eac45e9907 100644 --- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java +++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java @@ -17,7 +17,7 @@ package com.android.quickstep.logging; import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.FOLDER; -import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.PREDICTED_HOTSEAT_CONTAINER; +import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.SEARCH_RESULT_CONTAINER; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WORKSPACE_SNAPSHOT; import static com.android.systemui.shared.system.SysUiStatsLog.LAUNCHER_UICHANGED__DST_STATE__ALLAPPS; import static com.android.systemui.shared.system.SysUiStatsLog.LAUNCHER_UICHANGED__DST_STATE__BACKGROUND; @@ -75,6 +75,7 @@ public class StatsLogCompatManager extends StatsLogManager { // 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; + private static final int SEARCH_RESULT_HIERARCHY_OFFSET = 200; public StatsLogCompatManager(Context context) { sContext = context; @@ -156,10 +157,10 @@ public class StatsLogCompatManager extends StatsLogManager { getComponentName(info) /* component_name */, getGridX(info, false) /* grid_x */, getGridY(info, false) /* grid_y */, - getPageId(info, false) /* page_id */, + getPageId(info) /* page_id */, getGridX(info, true) /* grid_x_parent */, getGridY(info, true) /* grid_y_parent */, - getPageId(info, true) /* page_id_parent */, + getParentPageId(info) /* page_id_parent */, getHierarchy(info) /* hierarchy */, info.getIsWork() /* is_work_profile */, info.getAttribute().getNumber() /* origin */, @@ -321,10 +322,10 @@ public class StatsLogCompatManager extends StatsLogManager { getComponentName(atomInfo) /* component_name */, getGridX(atomInfo, false) /* grid_x */, getGridY(atomInfo, false) /* grid_y */, - getPageId(atomInfo, false) /* page_id */, + getPageId(atomInfo) /* page_id */, getGridX(atomInfo, true) /* grid_x_parent */, getGridY(atomInfo, true) /* grid_y_parent */, - getPageId(atomInfo, true) /* page_id_parent */, + getParentPageId(atomInfo) /* page_id_parent */, getHierarchy(atomInfo) /* hierarchy */, atomInfo.getIsWork() /* is_work_profile */, atomInfo.getRank() /* rank */, @@ -336,9 +337,14 @@ public class StatsLogCompatManager extends StatsLogManager { } private static int getCardinality(LauncherAtom.ItemInfo info) { - return info.getContainerInfo().getContainerCase().equals(PREDICTED_HOTSEAT_CONTAINER) - ? info.getContainerInfo().getPredictedHotseatContainer().getCardinality() - : info.getFolderIcon().getCardinality(); + switch (info.getContainerInfo().getContainerCase()){ + case PREDICTED_HOTSEAT_CONTAINER: + return info.getContainerInfo().getPredictedHotseatContainer().getCardinality(); + case SEARCH_RESULT_CONTAINER: + return info.getContainerInfo().getSearchResultContainer().getQueryLength(); + default: + return info.getFolderIcon().getCardinality(); + } } private static String getPackageName(LauncherAtom.ItemInfo info) { @@ -395,15 +401,24 @@ public class StatsLogCompatManager extends StatsLogManager { } } - private static int getPageId(LauncherAtom.ItemInfo info, boolean parent) { - if (info.getContainerInfo().getContainerCase() == FOLDER) { - if (parent) { - return info.getContainerInfo().getFolder().getWorkspace().getPageIndex(); - } else { + private static int getPageId(LauncherAtom.ItemInfo info) { + switch (info.getContainerInfo().getContainerCase()) { + case FOLDER: return info.getContainerInfo().getFolder().getPageIndex(); - } - } else { - return info.getContainerInfo().getWorkspace().getPageIndex(); + default: + return info.getContainerInfo().getWorkspace().getPageIndex(); + } + } + + private static int getParentPageId(LauncherAtom.ItemInfo info) { + switch (info.getContainerInfo().getContainerCase()) { + case FOLDER: + return info.getContainerInfo().getFolder().getWorkspace().getPageIndex(); + case SEARCH_RESULT_CONTAINER: + return info.getContainerInfo().getSearchResultContainer().getWorkspace() + .getPageIndex(); + default: + return info.getContainerInfo().getWorkspace().getPageIndex(); } } @@ -411,6 +426,9 @@ public class StatsLogCompatManager extends StatsLogManager { if (info.getContainerInfo().getContainerCase() == FOLDER) { return info.getContainerInfo().getFolder().getParentContainerCase().getNumber() + FOLDER_HIERARCHY_OFFSET; + } else if (info.getContainerInfo().getContainerCase() == SEARCH_RESULT_CONTAINER) { + return info.getContainerInfo().getSearchResultContainer().getParentContainerCase() + .getNumber() + SEARCH_RESULT_HIERARCHY_OFFSET; } else { return info.getContainerInfo().getContainerCase().getNumber(); } diff --git a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java b/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java index 25a2c695f1..ebdfa8c820 100644 --- a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java +++ b/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java @@ -248,10 +248,10 @@ public class GridSizeMigrationTaskV2 { /** Return what's in the src but not in the dest */ private static List calcDiff(List src, List dest) { Set destIntentSet = new HashSet<>(); - Set> destFolderIntentSet = new HashSet<>(); + Set> destFolderIntentSet = new HashSet<>(); for (DbEntry entry : dest) { if (entry.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) { - destFolderIntentSet.add(entry.mFolderItems.keySet()); + destFolderIntentSet.add(getFolderIntents(entry)); } else { destIntentSet.add(entry.mIntent); } @@ -259,7 +259,7 @@ public class GridSizeMigrationTaskV2 { List diff = new ArrayList<>(); for (DbEntry entry : src) { if (entry.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) { - if (!destFolderIntentSet.contains(entry.mFolderItems.keySet())) { + if (!destFolderIntentSet.contains(getFolderIntents(entry))) { diff.add(entry); } } else { @@ -271,13 +271,23 @@ public class GridSizeMigrationTaskV2 { return diff; } + private static Map getFolderIntents(DbEntry entry) { + Map folder = new HashMap<>(); + for (String intent : entry.mFolderItems.keySet()) { + folder.put(intent, entry.mFolderItems.get(intent).size()); + } + return folder; + } + private static void insertEntryInDb(SQLiteDatabase db, Context context, DbEntry entry, String srcTableName, String destTableName) { int id = copyEntryAndUpdate(db, context, entry, srcTableName, destTableName); if (entry.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) { - for (int itemId : entry.mFolderItems.values()) { - copyEntryAndUpdate(db, context, itemId, id, srcTableName, destTableName); + for (Set itemIds : entry.mFolderItems.values()) { + for (int itemId : itemIds) { + copyEntryAndUpdate(db, context, itemId, id, srcTableName, destTableName); + } } } } @@ -675,7 +685,10 @@ public class GridSizeMigrationTaskV2 { String intent = c.getString(1); verifyIntent(intent); total++; - entry.mFolderItems.put(intent, id); + if (!entry.mFolderItems.containsKey(intent)) { + entry.mFolderItems.put(intent, new HashSet<>()); + } + entry.mFolderItems.get(intent).add(id); } catch (Exception e) { removeEntryFromDb(mDb, mTableName, IntArray.wrap(c.getInt(0))); } @@ -714,7 +727,7 @@ public class GridSizeMigrationTaskV2 { private String mIntent; private String mProvider; - private Map mFolderItems = new HashMap<>(); + private Map> mFolderItems = new HashMap<>(); /** Comparator according to the reading order */ @Override @@ -748,9 +761,5 @@ public class GridSizeMigrationTaskV2 { values.put(LauncherSettings.Favorites.SPANX, spanX); values.put(LauncherSettings.Favorites.SPANY, spanY); } - - public String getIntentStr() { - return mIntent; - } } } diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java index 3082b6e341..0d3ddad183 100644 --- a/src/com/android/launcher3/model/data/ItemInfo.java +++ b/src/com/android/launcher3/model/data/ItemInfo.java @@ -344,7 +344,7 @@ public class ItemInfo { return itemBuilder; } - ContainerInfo getContainerInfo() { + protected ContainerInfo getContainerInfo() { switch (container) { case CONTAINER_HOTSEAT: return ContainerInfo.newBuilder() diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java index 49da7b3d8d..3ca08fd8ec 100644 --- a/src/com/android/launcher3/testing/TestProtocol.java +++ b/src/com/android/launcher3/testing/TestProtocol.java @@ -91,6 +91,7 @@ public final class TestProtocol { public static final String REQUEST_START_EVENT_LOGGING = "start-event-logging"; public static final String REQUEST_GET_TEST_EVENTS = "get-test-events"; public static final String REQUEST_STOP_EVENT_LOGGING = "stop-event-logging"; + public static final String REQUEST_CLEAR_DATA = "clear-data"; public static boolean sDebugTracing = false; public static final String REQUEST_ENABLE_DEBUG_TRACING = "enable-debug-tracing"; diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java index 3d39d254b1..858e183ab7 100644 --- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java +++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java @@ -300,17 +300,9 @@ public abstract class AbstractLauncherUiTest { checkDetectedLeaks(mLauncher); } - protected void clearLauncherData() throws IOException, InterruptedException { - if (TestHelpers.isInLauncherProcess()) { - LauncherSettings.Settings.call(mTargetContext.getContentResolver(), - LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB); - resetLoaderState(); - } else { - clearPackageData(mDevice.getLauncherPackageName()); - mLauncher.enableDebugTracing(); - mLauncherPid = mLauncher.getPid(); - mLauncher.waitForLauncherInitialized(); - } + protected void clearLauncherData() { + mLauncher.clearLauncherData(); + mLauncher.waitForLauncherInitialized(); } /** diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index a2c8d33cad..f4274a86dc 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -1335,6 +1335,10 @@ public final class LauncherInstrumentation { return tasks; } + public void clearLauncherData() { + getTestInfo(TestProtocol.REQUEST_CLEAR_DATA); + } + public Closable eventsCheck() { Assert.assertTrue("Nested event checking", mEventChecker == null); disableSensorRotation();