diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml index 31d40710bc..c4ee11a8d1 100644 --- a/quickstep/res/values/config.xml +++ b/quickstep/res/values/config.xml @@ -38,6 +38,7 @@ + com.android.launcher3.uioverrides.SystemApiWrapper diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml index eb9c5f0029..71855eb61f 100644 --- a/quickstep/res/values/strings.xml +++ b/quickstep/res/values/strings.xml @@ -26,6 +26,8 @@ Pin Freeform + + Desktop No recent items diff --git a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java index 3e9272d435..70e01f53a0 100644 --- a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java +++ b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java @@ -240,7 +240,11 @@ public class PredictionRowView icon.reset(); if (predictionCount > i) { icon.setVisibility(View.VISIBLE); - icon.applyFromWorkspaceItem(mPredictedApps.get(i)); + WorkspaceItemInfo predictedItem = mPredictedApps.get(i); + predictedItem.rank = i; + predictedItem.cellX = i; + predictedItem.cellY = 0; + icon.applyFromWorkspaceItem(predictedItem); } else { icon.setVisibility(predictionCount == 0 ? GONE : INVISIBLE); } diff --git a/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt b/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt index 10733fbbea..64fe30c538 100644 --- a/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt +++ b/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt @@ -56,6 +56,11 @@ class DesktopRecentsTransitionController( systemUiProxy.showDesktopApps(desktopTaskView.display.displayId, transition) } + /** Launch desktop tasks from recents view */ + fun moveToDesktop(taskId: Int) { + systemUiProxy.moveToDesktop(taskId) + } + private class RemoteDesktopLaunchTransitionRunner( private val desktopTaskView: DesktopTaskView, private val stateManager: StateManager<*>, @@ -99,8 +104,7 @@ class DesktopRecentsTransitionController( finishCallback: IRemoteTransitionFinishedCallback ) {} - override fun onTransitionConsumed(transition: IBinder?, aborted: Boolean) { - } + override fun onTransitionConsumed(transition: IBinder?, aborted: Boolean) {} } companion object { diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java index 672bd1decf..1c5a75dd1c 100644 --- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java +++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java @@ -499,7 +499,7 @@ public class HotseatPredictionController implements DragController.DragListener, @Override public void onClick(View view) { - dismissTaskMenuView(mTarget); + dismissTaskMenuView(); pinPrediction(mItemInfo); } } diff --git a/quickstep/src/com/android/launcher3/model/WellbeingModel.java b/quickstep/src/com/android/launcher3/model/WellbeingModel.java index 3d04cb6828..ee1c6004dd 100644 --- a/quickstep/src/com/android/launcher3/model/WellbeingModel.java +++ b/quickstep/src/com/android/launcher3/model/WellbeingModel.java @@ -44,7 +44,6 @@ import androidx.annotation.MainThread; import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; -import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.R; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.popup.RemoteActionShortcut; @@ -53,6 +52,7 @@ import com.android.launcher3.util.BgObjectWithLooper; import com.android.launcher3.util.MainThreadInitializedObject; import com.android.launcher3.util.Preconditions; import com.android.launcher3.util.SimpleBroadcastReceiver; +import com.android.launcher3.views.ActivityContext; import java.util.Arrays; import java.util.HashMap; @@ -147,7 +147,7 @@ public final class WellbeingModel extends BgObjectWithLooper { @MainThread private SystemShortcut getShortcutForApp(String packageName, int userId, - BaseDraggingActivity activity, ItemInfo info, View originalView) { + Context context, ItemInfo info, View originalView) { Preconditions.assertUIThread(); // Work profile apps are not recognized by digital wellbeing. if (userId != UserHandle.myUserId()) { @@ -171,7 +171,7 @@ public final class WellbeingModel extends BgObjectWithLooper { "getShortcutForApp [" + packageName + "]: action: '" + action.getTitle() + "'"); } - return new RemoteActionShortcut(action, activity, info, originalView); + return new RemoteActionShortcut(action, context, info, originalView); } } @@ -305,9 +305,10 @@ public final class WellbeingModel extends BgObjectWithLooper { /** * Shortcut factory for generating wellbeing action */ - public static final SystemShortcut.Factory SHORTCUT_FACTORY = - (activity, info, originalView) -> (info.getTargetComponent() == null) ? null - : INSTANCE.get(activity).getShortcutForApp( + public static final SystemShortcut.Factory SHORTCUT_FACTORY = + (context, info, originalView) -> + (info.getTargetComponent() == null) ? null + : INSTANCE.get(originalView.getContext()).getShortcutForApp( info.getTargetComponent().getPackageName(), info.user.getIdentifier(), - activity, info, originalView); + originalView.getContext(), info, originalView); } diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java index 176091a141..c0dacf1daa 100644 --- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java +++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java @@ -48,7 +48,7 @@ public class DesktopVisibilityController { "persist.wm.debug.desktop_stashing", false); private final Launcher mLauncher; - private int mVisibleFreeformTasksCount; + private int mVisibleDesktopTasksCount; private boolean mInOverviewState; private boolean mBackgroundStateEnabled; private boolean mGestureInProgress; @@ -73,7 +73,7 @@ public class DesktopVisibilityController { if (DEBUG) { Log.d(TAG, "desktop visible tasks count changed=" + visibleTasksCount); } - setVisibleFreeformTasksCount(visibleTasksCount); + setVisibleDesktopTasksCount(visibleTasksCount); } }); } @@ -108,51 +108,51 @@ public class DesktopVisibilityController { } /** - * Whether freeform windows are visible in desktop mode. + * Whether desktop tasks are visible in desktop mode. */ - public boolean areFreeformTasksVisible() { - boolean freeformTasksVisible = mVisibleFreeformTasksCount > 0; + public boolean areDesktopTasksVisible() { + boolean desktopTasksVisible = mVisibleDesktopTasksCount > 0; if (DEBUG) { - Log.d(TAG, "areFreeformTasksVisible: freeformVisible=" + freeformTasksVisible + Log.d(TAG, "areDesktopTasksVisible: desktopVisible=" + desktopTasksVisible + " overview=" + mInOverviewState); } - return freeformTasksVisible && !mInOverviewState; + return desktopTasksVisible && !mInOverviewState; } /** - * Number of visible freeform windows in desktop mode. + * Number of visible desktop windows in desktop mode. */ - public int getVisibleFreeformTasksCount() { - return mVisibleFreeformTasksCount; + public int getVisibleDesktopTasksCount() { + return mVisibleDesktopTasksCount; } /** - * Sets the number of freeform windows that are visible and updates launcher visibility based on + * Sets the number of desktop windows that are visible and updates launcher visibility based on * it. */ - public void setVisibleFreeformTasksCount(int visibleTasksCount) { + public void setVisibleDesktopTasksCount(int visibleTasksCount) { if (DEBUG) { - Log.d(TAG, "setVisibleFreeformTasksCount: visibleTasksCount=" + visibleTasksCount - + " currentValue=" + mVisibleFreeformTasksCount); + Log.d(TAG, "setVisibleDesktopTasksCount: visibleTasksCount=" + visibleTasksCount + + " currentValue=" + mVisibleDesktopTasksCount); } - if (visibleTasksCount != mVisibleFreeformTasksCount) { - final boolean wasVisible = mVisibleFreeformTasksCount > 0; + if (visibleTasksCount != mVisibleDesktopTasksCount) { + final boolean wasVisible = mVisibleDesktopTasksCount > 0; final boolean isVisible = visibleTasksCount > 0; - mVisibleFreeformTasksCount = visibleTasksCount; + mVisibleDesktopTasksCount = visibleTasksCount; if (wasVisible != isVisible) { - if (mVisibleFreeformTasksCount > 0) { + if (mVisibleDesktopTasksCount > 0) { setLauncherViewsVisibility(View.INVISIBLE); if (!mInOverviewState) { - // When freeform is visible & we're not in overview, we want launcher to - // appear paused, this ensures that taskbar displays. + // When desktop tasks are visible & we're not in overview, we want launcher + // to appear paused, this ensures that taskbar displays. markLauncherPaused(); } } else { setLauncherViewsVisibility(View.VISIBLE); - // If freeform isn't visible ensure that launcher appears resumed to behave - // normally. + // If desktop tasks aren't visible, ensure that launcher appears resumed to + // behave normally. markLauncherResumed(); } } @@ -181,9 +181,9 @@ public class DesktopVisibilityController { if (mInOverviewState) { setLauncherViewsVisibility(View.VISIBLE); markLauncherResumed(); - } else if (areFreeformTasksVisible() && !mGestureInProgress) { + } else if (areDesktopTasksVisible() && !mGestureInProgress) { // Switching out of overview state and gesture finished. - // If freeform tasks are still visible, hide launcher again. + // If desktop tasks are still visible, hide launcher again. setLauncherViewsVisibility(View.INVISIBLE); markLauncherPaused(); } @@ -200,8 +200,8 @@ public class DesktopVisibilityController { if (mBackgroundStateEnabled) { setLauncherViewsVisibility(View.VISIBLE); markLauncherResumed(); - } else if (areFreeformTasksVisible() && !mGestureInProgress) { - // Switching out of background state. If freeform tasks are visible, pause launcher. + } else if (areDesktopTasksVisible() && !mGestureInProgress) { + // Switching out of background state. If desktop tasks are visible, pause launcher. setLauncherViewsVisibility(View.INVISIBLE); markLauncherPaused(); } @@ -251,7 +251,7 @@ public class DesktopVisibilityController { * Handle launcher moving to home due to home gesture or home button press. */ public void onHomeActionTriggered() { - if (IS_STASHING_ENABLED && areFreeformTasksVisible()) { + if (IS_STASHING_ENABLED && areDesktopTasksVisible()) { SystemUiProxy.INSTANCE.get(mLauncher).stashDesktopApps(mLauncher.getDisplayId()); } } @@ -270,7 +270,7 @@ public class DesktopVisibilityController { dragLayer.setVisibility(visibility); } if (mLauncher instanceof QuickstepLauncher ql && ql.getTaskbarUIController() != null - && mVisibleFreeformTasksCount != 0) { + && mVisibleDesktopTasksCount != 0) { ql.getTaskbarUIController().onLauncherVisibilityChanged(visibility == VISIBLE); } } diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java index d89f49b6aa..584106bc05 100644 --- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java +++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java @@ -115,7 +115,7 @@ public final class KeyboardQuickSwitchController implements DesktopVisibilityController desktopController = LauncherActivityInterface.INSTANCE.getDesktopVisibilityController(); final boolean onDesktop = - desktopController != null && desktopController.areFreeformTasksVisible(); + desktopController != null && desktopController.areDesktopTasksVisible(); if (mModel.isTaskListValid(mTaskListChangeId)) { // When we are opening the KQS with no focus override, check if the first task is diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java index 23380d67bd..03c28053c1 100644 --- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java @@ -219,7 +219,7 @@ public class LauncherTaskbarUIController extends TaskbarUIController { DesktopVisibilityController desktopController = LauncherActivityInterface.INSTANCE.getDesktopVisibilityController(); final boolean onDesktop = - desktopController != null && desktopController.areFreeformTasksVisible(); + desktopController != null && desktopController.areDesktopTasksVisible(); if (onDesktop) { isVisible = false; } @@ -425,15 +425,15 @@ public class LauncherTaskbarUIController extends TaskbarUIController { } @Override - protected boolean isInOverview() { - return mTaskbarLauncherStateController.isInOverview(); + protected boolean isInOverviewUi() { + return mTaskbarLauncherStateController.isInOverviewUi(); } @Override protected boolean canToggleHomeAllApps() { return mLauncher.isResumed() - && !mTaskbarLauncherStateController.isInOverview() - && !mLauncher.areFreeformTasksVisible(); + && !mTaskbarLauncherStateController.isInOverviewUi() + && !mLauncher.areDesktopTasksVisible(); } @Override diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index 390dec9a66..49d4afeb17 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -113,8 +113,8 @@ import com.android.launcher3.testing.TestLogging; import com.android.launcher3.testing.shared.TestProtocol; import com.android.launcher3.touch.ItemClickHandler; import com.android.launcher3.touch.ItemClickHandler.ItemClickProxy; -import com.android.launcher3.uioverrides.ApiWrapper; import com.android.launcher3.util.ActivityOptionsWrapper; +import com.android.launcher3.util.ApiWrapper; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.Executors; @@ -665,7 +665,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext { LauncherAtom.TaskBarContainer.Builder taskbarBuilder = LauncherAtom.TaskBarContainer.newBuilder(); - if (mControllers.uiController.isInOverview()) { + if (mControllers.uiController.isInOverviewUi()) { taskbarBuilder.setTaskSwitcherContainer( LauncherAtom.TaskSwitcherContainer.newBuilder()); } @@ -1120,7 +1120,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext { } else if (info.isPromise()) { TestLogging.recordEvent( TestProtocol.SEQUENCE_MAIN, "start: taskbarPromiseIcon"); - intent = ApiWrapper.getAppMarketActivityIntent(this, + intent = ApiWrapper.INSTANCE.get(this).getAppMarketActivityIntent( info.getTargetPackage(), Process.myUserHandle()); startActivity(intent); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt index 8dc81cf461..6163dadca6 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt @@ -375,7 +375,7 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas ) { // Taskbar has some touchable elements, take over the full taskbar area if ( - controllers.uiController.isInOverview && + controllers.uiController.isInOverviewUi && DisplayController.isTransientTaskbar(context) ) { val region = diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java index b0abbe9e57..17dcacea3c 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java @@ -666,8 +666,8 @@ public class TaskbarLauncherStateController { && !mLauncher.getWorkspace().isOverlayShown(); } - boolean isInOverview() { - return mLauncherState == LauncherState.OVERVIEW; + boolean isInOverviewUi() { + return mLauncherState.overviewUi; } private void playStateTransitionAnim(AnimatorSet animatorSet, long duration, diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java index 5d418fab3d..e47640b1c7 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java @@ -58,6 +58,7 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.launcher3.DeviceProfile; +import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.statemanager.StatefulActivity; @@ -339,12 +340,12 @@ public class TaskbarManager { /** * Toggles All Apps for Taskbar or Launcher depending on the current state. - * - * @param homeAllAppsIntent Intent used if Taskbar is not enabled or Launcher is resumed. */ - public void toggleAllApps(Intent homeAllAppsIntent) { + public void toggleAllApps() { if (mTaskbarActivityContext == null || mTaskbarActivityContext.canToggleHomeAllApps()) { - mContext.startActivity(homeAllAppsIntent); + // Home All Apps should be toggled from this class, because the controllers are not + // initialized when Taskbar is disabled (i.e. TaskbarActivityContext is null). + if (mActivity instanceof Launcher l) l.toggleAllAppsSearch(); } else { mTaskbarActivityContext.toggleAllAppsSearch(); } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java index 7e74c27264..15be8e7415 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java @@ -985,7 +985,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba DesktopVisibilityController visibilityController = LauncherActivityInterface.INSTANCE.getDesktopVisibilityController(); if (visibilityController != null && mActivity.isHardwareKeyboard() - && mActivity.isThreeButtonNav() && visibilityController.areFreeformTasksVisible()) { + && mActivity.isThreeButtonNav() && visibilityController.areDesktopTasksVisible()) { return false; } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java index cb0fa406e8..2e78489692 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java @@ -193,7 +193,7 @@ public class TaskbarUIController { } /** Returns {@code true} if Taskbar is currently within overview. */ - protected boolean isInOverview() { + protected boolean isInOverviewUi() { return false; } diff --git a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java deleted file mode 100644 index 873dea80e3..0000000000 --- a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (C) 2017 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.uioverrides; - -import android.app.ActivityOptions; -import android.app.PendingIntent; -import android.app.Person; -import android.content.Context; -import android.content.Intent; -import android.content.IntentSender; -import android.content.pm.ActivityInfo; -import android.content.pm.LauncherActivityInfo; -import android.content.pm.LauncherApps; -import android.content.pm.LauncherUserInfo; -import android.content.pm.ShortcutInfo; -import android.graphics.drawable.ColorDrawable; -import android.net.Uri; -import android.os.UserHandle; -import android.os.UserManager; -import android.util.ArrayMap; -import android.window.RemoteTransition; - -import com.android.launcher3.Flags; -import com.android.launcher3.Utilities; -import com.android.launcher3.proxy.ProxyActivityStarter; -import com.android.launcher3.util.StartActivityParams; -import com.android.launcher3.util.UserIconInfo; -import com.android.quickstep.util.FadeOutRemoteTransition; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -/** - * A wrapper for the hidden API calls - */ -public class ApiWrapper { - - public static final boolean TASKBAR_DRAWN_IN_PROCESS = true; - - public static Person[] getPersons(ShortcutInfo si) { - Person[] persons = si.getPersons(); - return persons == null ? Utilities.EMPTY_PERSON_ARRAY : persons; - } - - public static Map getActivityOverrides(Context context) { - return context.getSystemService(LauncherApps.class).getActivityOverrides(); - } - - /** - * Creates an ActivityOptions to play fade-out animation on closing targets - */ - public static ActivityOptions createFadeOutAnimOptions(Context context) { - ActivityOptions options = ActivityOptions.makeBasic(); - options.setRemoteTransition(new RemoteTransition(new FadeOutRemoteTransition())); - return options; - } - - /** - * Returns a map of all users on the device to their corresponding UI properties - */ - public static Map queryAllUsers(Context context) { - UserManager um = context.getSystemService(UserManager.class); - Map users = new ArrayMap<>(); - List usersActual = um.getUserProfiles(); - if (usersActual != null) { - for (UserHandle user : usersActual) { - if (android.os.Flags.allowPrivateProfile() && Flags.enablePrivateSpace()) { - LauncherApps launcherApps = context.getSystemService(LauncherApps.class); - LauncherUserInfo launcherUserInfo = launcherApps.getLauncherUserInfo(user); - if (launcherUserInfo == null) { - continue; - } - // UserTypes not supported in Launcher are deemed to be the current - // Foreground User. - int userType = switch (launcherUserInfo.getUserType()) { - case UserManager.USER_TYPE_PROFILE_MANAGED -> UserIconInfo.TYPE_WORK; - case UserManager.USER_TYPE_PROFILE_CLONE -> UserIconInfo.TYPE_CLONED; - case UserManager.USER_TYPE_PROFILE_PRIVATE -> UserIconInfo.TYPE_PRIVATE; - default -> UserIconInfo.TYPE_MAIN; - }; - long serial = launcherUserInfo.getUserSerialNumber(); - users.put(user, new UserIconInfo(user, userType, serial)); - } else { - long serial = um.getSerialNumberForUser(user); - - // Simple check to check if the provided user is work profile - // TODO: Migrate to a better platform API - NoopDrawable d = new NoopDrawable(); - boolean isWork = (d != context.getPackageManager().getUserBadgedIcon(d, user)); - UserIconInfo info = new UserIconInfo( - user, - isWork ? UserIconInfo.TYPE_WORK : UserIconInfo.TYPE_MAIN, - serial); - users.put(user, info); - } - } - } - return users; - } - - /** - * Returns the list of the system packages that are installed at user creation. - * An empty list denotes that all system packages are installed for that user at creation. - */ - public static List getPreInstalledSystemPackages(Context context, UserHandle user) { - LauncherApps launcherApps = context.getSystemService(LauncherApps.class); - if (android.os.Flags.allowPrivateProfile() && Flags.enablePrivateSpace() - && Flags.privateSpaceSysAppsSeparation()) { - return launcherApps.getPreInstalledSystemPackages(user); - } else { - return new ArrayList<>(); - } - } - - /** - * Returns an intent which can be used to start the App Market activity (Installer - * Activity). - */ - public static Intent getAppMarketActivityIntent(Context context, String packageName, - UserHandle user) { - LauncherApps launcherApps = context.getSystemService(LauncherApps.class); - if (android.os.Flags.allowPrivateProfile() - && Flags.enablePrivateSpace() - && (Flags.privateSpaceAppInstallerButton() - || Flags.enablePrivateSpaceInstallShortcut())) { - StartActivityParams params = new StartActivityParams((PendingIntent) null, 0); - params.intentSender = launcherApps.getAppMarketActivityIntent(packageName, user); - ActivityOptions options = ActivityOptions.makeBasic() - .setPendingIntentBackgroundActivityStartMode(ActivityOptions - .MODE_BACKGROUND_ACTIVITY_START_ALLOWED); - params.options = options.toBundle(); - params.requireActivityResult = false; - return ProxyActivityStarter.getLaunchIntent(context, params); - } else { - return new Intent(Intent.ACTION_VIEW) - .setData(new Uri.Builder() - .scheme("market") - .authority("details") - .appendQueryParameter("id", packageName) - .build()) - .putExtra(Intent.EXTRA_REFERRER, new Uri.Builder().scheme("android-app") - .authority(context.getPackageName()).build()); - } - } - - /** - * Returns an intent which can be used to open Private Space Settings. - */ - public static Intent getPrivateSpaceSettingsIntent(Context context) { - if (android.os.Flags.allowPrivateProfile() && Flags.enablePrivateSpace()) { - LauncherApps launcherApps = context.getSystemService(LauncherApps.class); - IntentSender intentSender = launcherApps.getPrivateSpaceSettingsIntent(); - if (intentSender == null) { - return null; - } - StartActivityParams params = new StartActivityParams((PendingIntent) null, 0); - params.intentSender = intentSender; - ActivityOptions options = ActivityOptions.makeBasic() - .setPendingIntentBackgroundActivityStartMode(ActivityOptions - .MODE_BACKGROUND_ACTIVITY_START_ALLOWED); - params.options = options.toBundle(); - params.requireActivityResult = false; - return ProxyActivityStarter.getLaunchIntent(context, params); - } - return null; - } - - /** - * Checks if an activity is flagged as non-resizeable. - */ - public static boolean isNonResizeableActivity(LauncherActivityInfo lai) { - return lai.getActivityInfo().resizeMode == ActivityInfo.RESIZE_MODE_UNRESIZEABLE; - } - - private static class NoopDrawable extends ColorDrawable { - @Override - public int getIntrinsicHeight() { - return 1; - } - - @Override - public int getIntrinsicWidth() { - return 1; - } - } -} diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index c5c009210f..6c05bfe752 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -181,6 +181,7 @@ import com.android.quickstep.util.unfold.ProxyUnfoldTransitionProvider; import com.android.quickstep.views.FloatingTaskView; import com.android.quickstep.views.OverviewActionsView; import com.android.quickstep.views.RecentsView; +import com.android.quickstep.views.RecentsViewContainer; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -204,7 +205,7 @@ import java.util.function.BiConsumer; import java.util.function.Predicate; import java.util.stream.Stream; -public class QuickstepLauncher extends Launcher { +public class QuickstepLauncher extends Launcher implements RecentsViewContainer { private static final boolean TRACE_LAYOUTS = SystemProperties.getBoolean("persist.debug.trace_layouts", false); private static final String TRACE_RELAYOUT_CLASS = @@ -218,7 +219,8 @@ public class QuickstepLauncher extends Launcher { private DepthController mDepthController; private @Nullable DesktopVisibilityController mDesktopVisibilityController; private QuickstepTransitionManager mAppTransitionManager; - private OverviewActionsView mActionsView; + + private OverviewActionsView mActionsView; private TISBindHelper mTISBindHelper; private @Nullable LauncherTaskbarUIController mTaskbarUIController; // Will be updated when dragging from taskbar. @@ -244,12 +246,16 @@ public class QuickstepLauncher extends Launcher { private boolean mIsPredictiveBackToHomeInProgress; + public static QuickstepLauncher getLauncher(Context context) { + return fromContext(context); + } + @Override protected void setupViews() { super.setupViews(); mActionsView = findViewById(R.id.overview_actions_view); - RecentsView overviewPanel = getOverviewPanel(); + RecentsView overviewPanel = getOverviewPanel(); SystemUiProxy systemUiProxy = SystemUiProxy.INSTANCE.get(this); mSplitSelectStateController = new SplitSelectStateController(this, mHandler, getStateManager(), @@ -937,7 +943,7 @@ public class QuickstepLauncher extends Launcher { @Override public void setResumed() { if (mDesktopVisibilityController != null - && mDesktopVisibilityController.areFreeformTasksVisible() + && mDesktopVisibilityController.areDesktopTasksVisible() && !mDesktopVisibilityController.isRecentsGestureInProgress()) { // Return early to skip setting activity to appear as resumed // TODO(b/255649902): shouldn't be needed when we have a separate launcher state @@ -1055,8 +1061,9 @@ public class QuickstepLauncher extends Launcher { .playPlaceholderDismissAnim(this, splitDismissEvent); } - public T getActionsView() { - return (T) mActionsView; + @Override + public OverviewActionsView getActionsView() { + return mActionsView; } @Override @@ -1284,9 +1291,9 @@ public class QuickstepLauncher extends Launcher { } @Override - public boolean areFreeformTasksVisible() { + public boolean areDesktopTasksVisible() { if (mDesktopVisibilityController != null) { - return mDesktopVisibilityController.areFreeformTasksVisible(); + return mDesktopVisibilityController.areDesktopTasksVisible(); } return false; } @@ -1369,25 +1376,25 @@ public class QuickstepLauncher extends Launcher { } private static final class LauncherTaskViewController extends - TaskViewTouchController { + TaskViewTouchController { - LauncherTaskViewController(Launcher activity) { + LauncherTaskViewController(QuickstepLauncher activity) { super(activity); } @Override protected boolean isRecentsInteractive() { - return mActivity.isInState(OVERVIEW) || mActivity.isInState(OVERVIEW_MODAL_TASK); + return mContainer.isInState(OVERVIEW) || mContainer.isInState(OVERVIEW_MODAL_TASK); } @Override protected boolean isRecentsModal() { - return mActivity.isInState(OVERVIEW_MODAL_TASK); + return mContainer.isInState(OVERVIEW_MODAL_TASK); } @Override protected void onUserControlledAnimationCreated(AnimatorPlaybackController animController) { - mActivity.getStateManager().setCurrentUserControlledAnimation(animController); + mContainer.getStateManager().setCurrentUserControlledAnimation(animController); } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt b/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt new file mode 100644 index 0000000000..535b4c2986 --- /dev/null +++ b/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2024 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.uioverrides + +import android.app.ActivityOptions +import android.app.PendingIntent +import android.content.Context +import android.content.Intent +import android.content.pm.ActivityInfo +import android.content.pm.LauncherActivityInfo +import android.content.pm.LauncherApps +import android.content.pm.ShortcutInfo +import android.os.Flags.allowPrivateProfile +import android.os.UserHandle +import android.os.UserManager +import android.util.ArrayMap +import android.window.RemoteTransition +import com.android.launcher3.Flags.enablePrivateSpace +import com.android.launcher3.Flags.enablePrivateSpaceInstallShortcut +import com.android.launcher3.Flags.privateSpaceAppInstallerButton +import com.android.launcher3.Flags.privateSpaceSysAppsSeparation +import com.android.launcher3.Utilities +import com.android.launcher3.proxy.ProxyActivityStarter +import com.android.launcher3.util.ApiWrapper +import com.android.launcher3.util.StartActivityParams +import com.android.launcher3.util.UserIconInfo +import com.android.quickstep.util.FadeOutRemoteTransition + +/** A wrapper for the hidden API calls */ +class SystemApiWrapper(context: Context?) : ApiWrapper(context) { + + override fun getPersons(si: ShortcutInfo) = si.persons ?: Utilities.EMPTY_PERSON_ARRAY + + override fun getActivityOverrides(): Map = + mContext.getSystemService(LauncherApps::class.java)!!.activityOverrides + + override fun createFadeOutAnimOptions(): ActivityOptions = + ActivityOptions.makeBasic().apply { + remoteTransition = RemoteTransition(FadeOutRemoteTransition()) + } + + override fun queryAllUsers(): Map { + if (!allowPrivateProfile() || !enablePrivateSpace()) { + return super.queryAllUsers() + } + val users = ArrayMap() + mContext.getSystemService(UserManager::class.java)!!.userProfiles?.forEach { user -> + mContext.getSystemService(LauncherApps::class.java)!!.getLauncherUserInfo(user)?.apply { + users[user] = + UserIconInfo( + user, + when (userType) { + UserManager.USER_TYPE_PROFILE_MANAGED -> UserIconInfo.TYPE_WORK + UserManager.USER_TYPE_PROFILE_CLONE -> UserIconInfo.TYPE_CLONED + UserManager.USER_TYPE_PROFILE_PRIVATE -> UserIconInfo.TYPE_PRIVATE + else -> UserIconInfo.TYPE_MAIN + }, + userSerialNumber.toLong() + ) + } + } + return users + } + + override fun getPreInstalledSystemPackages(user: UserHandle): List = + if (allowPrivateProfile() && enablePrivateSpace() && privateSpaceSysAppsSeparation()) + mContext + .getSystemService(LauncherApps::class.java)!! + .getPreInstalledSystemPackages(user) + else ArrayList() + + override fun getAppMarketActivityIntent(packageName: String, user: UserHandle): Intent = + if ( + allowPrivateProfile() && + enablePrivateSpace() && + (privateSpaceAppInstallerButton() || enablePrivateSpaceInstallShortcut()) + ) + ProxyActivityStarter.getLaunchIntent( + mContext, + StartActivityParams(null as PendingIntent?, 0).apply { + intentSender = + mContext + .getSystemService(LauncherApps::class.java)!! + .getAppMarketActivityIntent(packageName, user) + options = + ActivityOptions.makeBasic() + .setPendingIntentBackgroundActivityStartMode( + ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED + ) + .toBundle() + requireActivityResult = false + } + ) + else super.getAppMarketActivityIntent(packageName, user) + + /** Returns an intent which can be used to open Private Space Settings. */ + override fun getPrivateSpaceSettingsIntent(): Intent? = + if (allowPrivateProfile() && enablePrivateSpace()) + ProxyActivityStarter.getLaunchIntent( + mContext, + StartActivityParams(null as PendingIntent?, 0).apply { + intentSender = + mContext + .getSystemService(LauncherApps::class.java) + ?.privateSpaceSettingsIntent + ?: return null + options = + ActivityOptions.makeBasic() + .setPendingIntentBackgroundActivityStartMode( + ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED + ) + .toBundle() + requireActivityResult = false + } + ) + else null + + override fun isNonResizeableActivity(lai: LauncherActivityInfo) = + lai.activityInfo.resizeMode == ActivityInfo.RESIZE_MODE_UNRESIZEABLE +} diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java index 547de77f64..7fa121dadb 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java @@ -22,7 +22,6 @@ import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITION import android.content.Context; import android.graphics.Color; -import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.allapps.AllAppsTransitionController; @@ -63,7 +62,7 @@ public class BackgroundAppState extends OverviewState { @Override public float[] getOverviewScaleAndOffset(Launcher launcher) { - return getOverviewScaleAndOffsetForBackgroundState(launcher); + return getOverviewScaleAndOffsetForBackgroundState(launcher.getOverviewPanel()); } @Override @@ -91,8 +90,8 @@ public class BackgroundAppState extends OverviewState { @Override protected float getDepthUnchecked(Context context) { - if (Launcher.getLauncher(context).areFreeformTasksVisible()) { - // Don't blur the background while freeform tasks are visible + if (Launcher.getLauncher(context).areDesktopTasksVisible()) { + // Don't blur the background while desktop tasks are visible return BaseDepthController.DEPTH_0_PERCENT; } else if (enableScalingRevealHomeAnimation()) { return BaseDepthController.DEPTH_70_PERCENT; @@ -125,9 +124,7 @@ public class BackgroundAppState extends OverviewState { } public static float[] getOverviewScaleAndOffsetForBackgroundState( - BaseDraggingActivity activity) { - return new float[] { - ((RecentsView) activity.getOverviewPanel()).getMaxScaleForFullScreen(), - NO_OFFSET}; + RecentsView recentsView) { + return new float[] {recentsView.getMaxScaleForFullScreen(), NO_OFFSET}; } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java index c63eaebc89..3c291e6095 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java @@ -20,7 +20,6 @@ import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERV import android.content.Context; import android.graphics.Rect; -import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.Flags; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; @@ -51,7 +50,7 @@ public class OverviewModalTaskState extends OverviewState { @Override public float[] getOverviewScaleAndOffset(Launcher launcher) { - return getOverviewScaleAndOffsetForModalState(launcher); + return getOverviewScaleAndOffsetForModalState(launcher.getOverviewPanel()); } @Override @@ -72,8 +71,7 @@ public class OverviewModalTaskState extends OverviewState { return super.isTaskbarStashed(launcher); } - public static float[] getOverviewScaleAndOffsetForModalState(BaseDraggingActivity activity) { - RecentsView recentsView = activity.getOverviewPanel(); + public static float[] getOverviewScaleAndOffsetForModalState(RecentsView recentsView) { Rect taskSize = recentsView.getSelectedTaskBounds(); Rect modalTaskSize = new Rect(); recentsView.getModalTaskSize(modalTaskSize); diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java index 7fb811d4b7..dfad4096bc 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java @@ -45,8 +45,8 @@ public class QuickSwitchState extends BackgroundAppState { @Override public int getWorkspaceScrimColor(Launcher launcher) { - if (launcher.areFreeformTasksVisible()) { - // No scrim while freeform tasks are visible + if (launcher.areDesktopTasksVisible()) { + // No scrim while desktop tasks are visible return Color.TRANSPARENT; } DeviceProfile dp = launcher.getDeviceProfile(); diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java index b40186819f..0368f3a86d 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java @@ -94,7 +94,7 @@ public class QuickstepAtomicAnimationFactory extends @Override public void prepareForAtomicAnimation(LauncherState fromState, LauncherState toState, StateAnimationConfig config) { - RecentsView overview = mActivity.getOverviewPanel(); + RecentsView overview = mContainer.getOverviewPanel(); if ((fromState == OVERVIEW || fromState == OVERVIEW_SPLIT_SELECT) && toState == NORMAL) { overview.switchToScreenshot(() -> overview.finishRecentsAnimation(true /* toRecents */, null)); @@ -118,7 +118,7 @@ public class QuickstepAtomicAnimationFactory extends config.setInterpolator(ANIM_WORKSPACE_SCALE, DECELERATE); config.setInterpolator(ANIM_WORKSPACE_FADE, ACCELERATE); - if (DisplayController.getNavigationMode(mActivity).hasGestures + if (DisplayController.getNavigationMode(mContainer).hasGestures && overview.getTaskViewCount() > 0) { // Overview is going offscreen, so keep it at its current scale and opacity. config.setInterpolator(ANIM_OVERVIEW_SCALE, FINAL_FRAME); @@ -136,7 +136,7 @@ public class QuickstepAtomicAnimationFactory extends config.duration = Math.max(config.duration, scrollDuration); // Sync scroll so that it ends before or at the same time as the taskbar animation. - if (mActivity.getDeviceProfile().isTaskbarPresent) { + if (mContainer.getDeviceProfile().isTaskbarPresent) { config.duration = Math.min( config.duration, QuickstepTransitionManager.getTaskbarToHomeDuration()); } @@ -147,7 +147,7 @@ public class QuickstepAtomicAnimationFactory extends config.setInterpolator(ANIM_OVERVIEW_FADE, DECELERATE_1_7); } - Workspace workspace = mActivity.getWorkspace(); + Workspace workspace = mContainer.getWorkspace(); // Start from a higher workspace scale, but only if we're invisible so we don't jump. boolean isWorkspaceVisible = workspace.getVisibility() == VISIBLE; if (isWorkspaceVisible) { @@ -160,7 +160,7 @@ public class QuickstepAtomicAnimationFactory extends workspace.setScaleX(WORKSPACE_PREPARE_SCALE); workspace.setScaleY(WORKSPACE_PREPARE_SCALE); } - Hotseat hotseat = mActivity.getHotseat(); + Hotseat hotseat = mContainer.getHotseat(); boolean isHotseatVisible = hotseat.getVisibility() == VISIBLE && hotseat.getAlpha() > 0; if (!isHotseatVisible) { hotseat.setScaleX(WORKSPACE_PREPARE_SCALE); @@ -168,7 +168,7 @@ public class QuickstepAtomicAnimationFactory extends } } else if ((fromState == NORMAL || fromState == HINT_STATE || fromState == HINT_STATE_TWO_BUTTON) && toState == OVERVIEW) { - if (DisplayController.getNavigationMode(mActivity).hasGestures) { + if (DisplayController.getNavigationMode(mContainer).hasGestures) { config.setInterpolator(ANIM_WORKSPACE_SCALE, fromState == NORMAL ? ACCELERATE : OVERSHOOT_1_2); config.setInterpolator(ANIM_WORKSPACE_TRANSLATE, ACCELERATE); @@ -201,18 +201,18 @@ public class QuickstepAtomicAnimationFactory extends } else if (fromState == HINT_STATE && toState == NORMAL) { config.setInterpolator(ANIM_DEPTH, DECELERATE_3); if (mHintToNormalDuration == -1) { - ValueAnimator va = getWorkspaceSpringScaleAnimator(mActivity, - mActivity.getWorkspace(), - toState.getWorkspaceScaleAndTranslation(mActivity).scale); + ValueAnimator va = getWorkspaceSpringScaleAnimator(mContainer, + mContainer.getWorkspace(), + toState.getWorkspaceScaleAndTranslation(mContainer).scale); mHintToNormalDuration = (int) va.getDuration(); } config.duration = Math.max(config.duration, mHintToNormalDuration); } else if (fromState == ALL_APPS && toState == NORMAL) { - AllAppsSwipeController.applyAllAppsToNormalConfig(mActivity, config); + AllAppsSwipeController.applyAllAppsToNormalConfig(mContainer, config); } else if (fromState == NORMAL && toState == ALL_APPS) { - AllAppsSwipeController.applyNormalToAllAppsAnimConfig(mActivity, config); + AllAppsSwipeController.applyNormalToAllAppsAnimConfig(mContainer, config); } else if (fromState == OVERVIEW && toState == OVERVIEW_SPLIT_SELECT) { - SplitAnimationTimings timings = mActivity.getDeviceProfile().isTablet + SplitAnimationTimings timings = mContainer.getDeviceProfile().isTablet ? SplitAnimationTimings.TABLET_OVERVIEW_TO_SPLIT : SplitAnimationTimings.PHONE_OVERVIEW_TO_SPLIT; config.setInterpolator(ANIM_OVERVIEW_ACTIONS_FADE, clampToProgress(LINEAR, diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java index e8b508168d..615e3e326e 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java @@ -47,6 +47,7 @@ import com.android.launcher3.compat.AccessibilityManagerCompat; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.statemanager.StateManager; import com.android.launcher3.touch.SingleAxisSwipeDetector; +import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.TouchController; import com.android.quickstep.TaskUtils; diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java index 8ef35c06eb..5a19ed42db 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java @@ -84,7 +84,6 @@ import com.android.quickstep.util.AnimatorControllerWithResistance; import com.android.quickstep.util.LayoutUtils; import com.android.quickstep.util.MotionPauseDetector; import com.android.quickstep.util.WorkspaceRevealAnim; -import com.android.quickstep.views.LauncherRecentsView; import com.android.quickstep.views.RecentsView; import com.android.systemui.shared.system.InteractionJankMonitorWrapper; @@ -108,7 +107,7 @@ public class NoButtonQuickSwitchTouchController implements TouchController, private final float mMaxYProgress; private final MotionPauseDetector mMotionPauseDetector; private final float mMotionPauseMinDisplacement; - private final LauncherRecentsView mRecentsView; + private final RecentsView mRecentsView; protected final AnimatorListener mClearStateOnCancelListener = newCancelListener(this::clearState); diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java index de73630666..05a55d0856 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java @@ -38,12 +38,12 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_O import android.view.MotionEvent; -import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.Utilities; import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.touch.AbstractStateChangeTouchController; import com.android.launcher3.touch.SingleAxisSwipeDetector; +import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.NavigationMode; import com.android.quickstep.SystemUiProxy; @@ -58,11 +58,12 @@ public class QuickSwitchTouchController extends AbstractStateChangeTouchControll protected final RecentsView mOverviewPanel; - public QuickSwitchTouchController(Launcher launcher) { + public QuickSwitchTouchController(QuickstepLauncher launcher) { this(launcher, SingleAxisSwipeDetector.HORIZONTAL); } - protected QuickSwitchTouchController(Launcher l, SingleAxisSwipeDetector.Direction dir) { + protected QuickSwitchTouchController(QuickstepLauncher l, + SingleAxisSwipeDetector.Direction dir) { super(l, dir); mOverviewPanel = l.getOverviewPanel(); } diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java index e9f2d4f019..300d697fff 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java @@ -21,6 +21,7 @@ import static com.android.launcher3.touch.SingleAxisSwipeDetector.DIRECTION_BOTH import android.animation.Animator; import android.animation.AnimatorListenerAdapter; +import android.content.Context; import android.os.VibrationEffect; import android.view.MotionEvent; import android.view.View; @@ -28,7 +29,6 @@ import android.view.animation.Interpolator; import com.android.app.animation.Interpolators; import com.android.launcher3.AbstractFloatingView; -import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.LauncherAnimUtils; import com.android.launcher3.R; import com.android.launcher3.Utilities; @@ -44,12 +44,13 @@ import com.android.launcher3.views.BaseDragLayer; import com.android.quickstep.orientation.RecentsPagedOrientationHandler; import com.android.quickstep.util.VibrationConstants; import com.android.quickstep.views.RecentsView; +import com.android.quickstep.views.RecentsViewContainer; import com.android.quickstep.views.TaskView; /** * Touch controller for handling task view card swipes */ -public abstract class TaskViewTouchController +public abstract class TaskViewTouchController extends AnimatorListenerAdapter implements TouchController, SingleAxisSwipeDetector.Listener { @@ -63,7 +64,7 @@ public abstract class TaskViewTouchController public static final VibrationEffect TASK_DISMISS_VIBRATION_FALLBACK = VibrationConstants.EFFECT_TEXTURE_TICK; - protected final T mActivity; + protected final CONTAINER mContainer; private final SingleAxisSwipeDetector mDetector; private final RecentsView mRecentsView; private final int[] mTempCords = new int[2]; @@ -87,13 +88,13 @@ public abstract class TaskViewTouchController private boolean mIsDismissHapticRunning = false; - public TaskViewTouchController(T activity) { - mActivity = activity; - mRecentsView = activity.getOverviewPanel(); - mIsRtl = Utilities.isRtl(activity.getResources()); + public TaskViewTouchController(CONTAINER container) { + mContainer = container; + mRecentsView = container.getOverviewPanel(); + mIsRtl = Utilities.isRtl(container.getResources()); SingleAxisSwipeDetector.Direction dir = mRecentsView.getPagedOrientationHandler().getUpDownSwipeDirection(); - mDetector = new SingleAxisSwipeDetector(activity, this, dir); + mDetector = new SingleAxisSwipeDetector(container, this, dir); } private boolean canInterceptTouch(MotionEvent ev) { @@ -113,7 +114,7 @@ public abstract class TaskViewTouchController return true; } if (AbstractFloatingView.getTopOpenViewWithType( - mActivity, TYPE_TOUCH_CONTROLLER_NO_INTERCEPT) != null) { + mContainer, TYPE_TOUCH_CONTROLLER_NO_INTERCEPT) != null) { return false; } return isRecentsInteractive(); @@ -159,7 +160,7 @@ public abstract class TaskViewTouchController for (int i = 0; i < mRecentsView.getTaskViewCount(); i++) { TaskView view = mRecentsView.getTaskViewAt(i); - if (mRecentsView.isTaskViewVisible(view) && mActivity.getDragLayer() + if (mRecentsView.isTaskViewVisible(view) && mContainer.getDragLayer() .isEventOverView(view, ev)) { // Disable swiping up and down if the task overlay is modal. if (isRecentsModal()) { @@ -179,7 +180,7 @@ public abstract class TaskViewTouchController // - It's the focused task if in grid view // - The task is snapped mAllowGoingDown = i == mRecentsView.getCurrentPage() - && DisplayController.getNavigationMode(mActivity).hasGestures + && DisplayController.getNavigationMode(mContainer).hasGestures && (!mRecentsView.showAsGrid() || mTaskBeingDragged.isFocusedTask()) && mRecentsView.isTaskInExpectedScrollPosition(i); @@ -228,7 +229,7 @@ public abstract class TaskViewTouchController RecentsPagedOrientationHandler orientationHandler = mRecentsView.getPagedOrientationHandler(); mCurrentAnimationIsGoingUp = goingUp; - BaseDragLayer dl = mActivity.getDragLayer(); + BaseDragLayer dl = mContainer.getDragLayer(); final int secondaryLayerDimension = orientationHandler.getSecondaryDimension(dl); long maxDuration = 2 * secondaryLayerDimension; int verticalFactor = orientationHandler.getTaskDragDisplacementFactor(mIsRtl); @@ -372,10 +373,10 @@ public abstract class TaskViewTouchController MIN_TASK_DISMISS_ANIMATION_DURATION, MAX_TASK_DISMISS_ANIMATION_DURATION); mCurrentAnimation.setEndAction(this::clearState); - mCurrentAnimation.startWithVelocity(mActivity, goingToEnd, Math.abs(velocity), + mCurrentAnimation.startWithVelocity(mContainer, goingToEnd, Math.abs(velocity), mEndDisplacement, animationDuration); if (goingUp && goingToEnd && !mIsDismissHapticRunning) { - VibratorWrapper.INSTANCE.get(mActivity).vibrate(TASK_DISMISS_VIBRATION_PRIMITIVE, + VibratorWrapper.INSTANCE.get(mContainer).vibrate(TASK_DISMISS_VIBRATION_PRIMITIVE, TASK_DISMISS_VIBRATION_PRIMITIVE_SCALE, TASK_DISMISS_VIBRATION_FALLBACK); mIsDismissHapticRunning = true; } diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TransposedQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TransposedQuickSwitchTouchController.java index 8f9c01441e..b70cabe76d 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TransposedQuickSwitchTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TransposedQuickSwitchTouchController.java @@ -15,13 +15,13 @@ */ package com.android.launcher3.uioverrides.touchcontrollers; -import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.touch.SingleAxisSwipeDetector; +import com.android.launcher3.uioverrides.QuickstepLauncher; public class TransposedQuickSwitchTouchController extends QuickSwitchTouchController { - public TransposedQuickSwitchTouchController(Launcher launcher) { + public TransposedQuickSwitchTouchController(QuickstepLauncher launcher) { super(launcher, SingleAxisSwipeDetector.VERTICAL); } diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarTouchController.java index 9f2c1d479f..31c9b3e7c0 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarTouchController.java @@ -27,10 +27,10 @@ import android.os.SystemClock; import android.view.MotionEvent; import com.android.launcher3.AbstractFloatingView; -import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.touch.AbstractStateChangeTouchController; import com.android.launcher3.touch.SingleAxisSwipeDetector; +import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.quickstep.SystemUiProxy; import com.android.quickstep.util.LayoutUtils; import com.android.quickstep.views.AllAppsEduView; @@ -51,7 +51,7 @@ public class TwoButtonNavbarTouchController extends AbstractStateChangeTouchCont private int mContinuousTouchCount = 0; - public TwoButtonNavbarTouchController(Launcher l) { + public TwoButtonNavbarTouchController(QuickstepLauncher l) { super(l, l.getDeviceProfile().isVerticalBarLayout() ? SingleAxisSwipeDetector.HORIZONTAL : SingleAxisSwipeDetector.VERTICAL); mIsTransposed = l.getDeviceProfile().isVerticalBarLayout(); diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index 7ee7751362..cceaf278b4 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -108,7 +108,6 @@ import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.logging.StatsLogManager.StatsLogger; import com.android.launcher3.statehandlers.DesktopVisibilityController; import com.android.launcher3.statemanager.BaseState; -import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.taskbar.TaskbarThresholdUtils; import com.android.launcher3.taskbar.TaskbarUIController; import com.android.launcher3.uioverrides.QuickstepLauncher; @@ -136,6 +135,7 @@ import com.android.quickstep.util.SwipePipToHomeAnimator; import com.android.quickstep.util.TaskViewSimulator; import com.android.quickstep.util.TransformParams; import com.android.quickstep.views.RecentsView; +import com.android.quickstep.views.RecentsViewContainer; import com.android.quickstep.views.TaskView; import com.android.quickstep.views.TaskView.TaskIdAttributeContainer; import com.android.systemui.shared.recents.model.Task; @@ -160,7 +160,7 @@ import java.util.function.Consumer; /** * Handles the navigation gestures when Launcher is the default home activity. */ -public abstract class AbsSwipeUpHandler, +public abstract class AbsSwipeUpHandler> extends SwipeUpAnimationLogic implements OnApplyWindowInsetsListener, RecentsAnimationCallbacks.RecentsAnimationListener { @@ -171,7 +171,7 @@ public abstract class AbsSwipeUpHandler, // Fraction of the scroll and transform animation in which the current task fades out private static final float KQS_TASK_FADE_ANIMATION_FRACTION = 0.4f; - protected final BaseActivityInterface mActivityInterface; + protected final BaseContainerInterface mContainerInterface; protected final InputConsumerProxy mInputConsumerProxy; protected final ActivityInitListener mActivityInitListener; // Callbacks to be made once the recents animation starts @@ -182,7 +182,7 @@ public abstract class AbsSwipeUpHandler, protected @Nullable RecentsAnimationController mRecentsAnimationController; protected @Nullable RecentsAnimationController mDeferredCleanupRecentsAnimationController; protected RecentsAnimationTargets mRecentsAnimationTargets; - protected @Nullable T mActivity; + protected @Nullable T mContainer; protected @Nullable Q mRecentsView; protected Runnable mGestureEndCallback; protected MultiStateCallback mStateCallback; @@ -192,7 +192,7 @@ public abstract class AbsSwipeUpHandler, private final Runnable mLauncherOnDestroyCallback = () -> { ActiveGestureLog.INSTANCE.addLog("Launcher destroyed", LAUNCHER_DESTROYED); mRecentsView = null; - mActivity = null; + mContainer = null; mStateCallback.clearState(STATE_LAUNCHER_PRESENT); }; @@ -347,8 +347,9 @@ public abstract class AbsSwipeUpHandler, long touchTimeMs, boolean continuingLastGesture, InputConsumerController inputConsumer) { super(context, deviceState, gestureState); - mActivityInterface = gestureState.getActivityInterface(); - mActivityInitListener = mActivityInterface.createActivityInitListener(this::onActivityInit); + mContainerInterface = gestureState.getContainerInterface(); + mActivityInitListener = + mContainerInterface.createActivityInitListener(this::onActivityInit); mInputConsumerProxy = new InputConsumerProxy(context, /* rotationSupplier = */ () -> { if (mRecentsView == null) { @@ -358,7 +359,7 @@ public abstract class AbsSwipeUpHandler, }, inputConsumer, /* onTouchDownCallback = */ () -> { endRunningWindowAnim(mGestureState.getEndTarget() == HOME /* cancel */); endLauncherTransitionController(); - }, new InputProxyHandlerFactory(mActivityInterface, mGestureState)); + }, new InputProxyHandlerFactory(mContainerInterface, mGestureState)); mTaskAnimationManager = taskAnimationManager; mTouchTimeMs = touchTimeMs; mContinuingLastGesture = continuingLastGesture; @@ -375,8 +376,8 @@ public abstract class AbsSwipeUpHandler, initStateCallbacks(); mIsTransientTaskbar = mDp.isTaskbarPresent - && DisplayController.isTransientTaskbar(mActivity); - TaskbarUIController controller = mActivityInterface.getTaskbarController(); + && DisplayController.isTransientTaskbar(context); + TaskbarUIController controller = mContainerInterface.getTaskbarController(); mTaskbarAlreadyOpen = controller != null && !controller.isTaskbarStashed(); mIsTaskbarAllAppsOpen = controller != null && controller.isTaskbarAllAppsOpen(); mTaskbarAppWindowThreshold = @@ -473,16 +474,16 @@ public abstract class AbsSwipeUpHandler, return false; } - T createdActivity = mActivityInterface.getCreatedActivity(); - if (createdActivity != null) { - initTransitionEndpoints(createdActivity.getDeviceProfile()); + T createdContainer = (T) mContainerInterface.getCreatedContainer(); + if (createdContainer != null) { + initTransitionEndpoints(createdContainer.getDeviceProfile()); } - final T activity = mActivityInterface.getCreatedActivity(); - if (mActivity == activity) { + final T container = (T) mContainerInterface.getCreatedContainer(); + if (mContainer == container) { return true; } - if (mActivity != null) { + if (mContainer != null) { if (mStateCallback.hasStates(STATE_GESTURE_COMPLETED)) { // If the activity has restarted between setting the page scroll settling callback // and actually receiving the callback, just mark the gesture completed @@ -497,23 +498,23 @@ public abstract class AbsSwipeUpHandler, mStateCallback.setState(oldState); } mWasLauncherAlreadyVisible = alreadyOnHome; - mActivity = activity; + mContainer = container; // Override the visibility of the activity until the gesture actually starts and we swipe // up, or until we transition home and the home animation is composed if (alreadyOnHome) { - mActivity.clearForceInvisibleFlag(STATE_HANDLER_INVISIBILITY_FLAGS); + mContainer.clearForceInvisibleFlag(STATE_HANDLER_INVISIBILITY_FLAGS); } else { - mActivity.addForceInvisibleFlag(STATE_HANDLER_INVISIBILITY_FLAGS); + mContainer.addForceInvisibleFlag(STATE_HANDLER_INVISIBILITY_FLAGS); } - mRecentsView = activity.getOverviewPanel(); + mRecentsView = container.getOverviewPanel(); mRecentsView.setOnPageTransitionEndCallback(null); mStateCallback.setState(STATE_LAUNCHER_PRESENT); if (alreadyOnHome) { onLauncherStart(); } else { - activity.addEventCallback(EVENT_STARTED, mLauncherOnStartCallback); + container.addEventCallback(EVENT_STARTED, mLauncherOnStartCallback); } // Set up a entire animation lifecycle callback to notify the current recents view when @@ -538,8 +539,8 @@ public abstract class AbsSwipeUpHandler, setupRecentsViewUi(); mRecentsView.runOnPageScrollsInitialized(this::linkRecentsViewScroll); - mActivity.runOnBindToTouchInteractionService(this::onLauncherBindToService); - mActivity.addEventCallback(EVENT_DESTROYED, mLauncherOnDestroyCallback); + mContainer.runOnBindToTouchInteractionService(this::onLauncherBindToService); + mContainer.addEventCallback(EVENT_DESTROYED, mLauncherOnDestroyCallback); return true; } @@ -551,8 +552,8 @@ public abstract class AbsSwipeUpHandler, } private void onLauncherStart() { - final T activity = mActivityInterface.getCreatedActivity(); - if (activity == null || mActivity != activity) { + final T container = (T) mContainerInterface.getCreatedContainer(); + if (container == null || mContainer != container) { return; } if (mStateCallback.hasStates(STATE_HANDLER_INVALIDATED)) { @@ -568,7 +569,7 @@ public abstract class AbsSwipeUpHandler, // as that will set the state as BACKGROUND_APP, overriding the animation to NORMAL. if (mGestureState.getEndTarget() != HOME) { Runnable initAnimFactory = () -> { - mAnimationFactory = mActivityInterface.prepareRecentsUI(mDeviceState, + mAnimationFactory = mContainerInterface.prepareRecentsUI(mDeviceState, mWasLauncherAlreadyVisible, this::onAnimatorPlaybackControllerCreated); maybeUpdateRecentsAttachedState(false /* animate */); if (mGestureState.getEndTarget() != null) { @@ -585,14 +586,14 @@ public abstract class AbsSwipeUpHandler, initAnimFactory.run(); } } - AbstractFloatingView.closeAllOpenViewsExcept(activity, mWasLauncherAlreadyVisible, + AbstractFloatingView.closeAllOpenViewsExcept(container, mWasLauncherAlreadyVisible, AbstractFloatingView.TYPE_LISTENER); if (mWasLauncherAlreadyVisible) { mStateCallback.setState(STATE_LAUNCHER_DRAWN); } else { SafeCloseable traceToken = TraceHelper.INSTANCE.beginAsyncSection("WTS-init"); - View dragLayer = activity.getDragLayer(); + View dragLayer = container.getDragLayer(); dragLayer.getViewTreeObserver().addOnDrawListener(new OnDrawListener() { boolean mHandled = false; @@ -606,7 +607,7 @@ public abstract class AbsSwipeUpHandler, traceToken.close(); dragLayer.post(() -> dragLayer.getViewTreeObserver().removeOnDrawListener(this)); - if (activity != mActivity) { + if (container != mContainer) { return; } @@ -615,7 +616,7 @@ public abstract class AbsSwipeUpHandler, }); } - activity.getRootView().setOnApplyWindowInsetsListener(this); + container.getRootView().setOnApplyWindowInsetsListener(this); mStateCallback.setState(STATE_LAUNCHER_STARTED); } @@ -631,21 +632,21 @@ public abstract class AbsSwipeUpHandler, // For the duration of the gesture, in cases where an activity is launched while the // activity is not yet resumed, finish the animation to ensure we get resumed - mGestureState.getActivityInterface().setOnDeferredActivityLaunchCallback( + mGestureState.getContainerInterface().setOnDeferredActivityLaunchCallback( mOnDeferredActivityLaunch); mGestureState.runOnceAtState(STATE_END_TARGET_SET, () -> { mDeviceState.getRotationTouchHelper() .onEndTargetCalculated(mGestureState.getEndTarget(), - mActivityInterface); + mContainerInterface); }); notifyGestureStarted(); } private void onDeferredActivityLaunch() { - mActivityInterface.switchRunningTaskViewToScreenshot( + mContainerInterface.switchRunningTaskViewToScreenshot( null, () -> { mTaskAnimationManager.finishRunningRecentsAnimation(true /* toHome */); }); @@ -706,7 +707,7 @@ public abstract class AbsSwipeUpHandler, public void onMotionPauseDetected() { mHasMotionEverBeenPaused = true; maybeUpdateRecentsAttachedState(true/* animate */, true/* moveRunningTask */); - Optional.ofNullable(mActivityInterface.getTaskbarController()) + Optional.ofNullable(mContainerInterface.getTaskbarController()) .ifPresent(TaskbarUIController::startTranslationSpring); if (!mIsInAllAppsRegion) { performHapticFeedback(); @@ -812,7 +813,7 @@ public abstract class AbsSwipeUpHandler, */ private void setIsInAllAppsRegion(boolean isInAllAppsRegion) { if (mIsInAllAppsRegion == isInAllAppsRegion - || !mActivityInterface.allowAllAppsFromOverview()) { + || !mContainerInterface.allowAllAppsFromOverview()) { return; } mIsInAllAppsRegion = isInAllAppsRegion; @@ -821,8 +822,9 @@ public abstract class AbsSwipeUpHandler, VibratorWrapper.INSTANCE.get(mContext).vibrate(OVERVIEW_HAPTIC); maybeUpdateRecentsAttachedState(true); - if (mActivity != null) { - mActivity.getAppsView().getSearchUiManager().prepareToFocusEditText(mIsInAllAppsRegion); + if (mContainer != null) { + mContainer.getAppsView().getSearchUiManager() + .prepareToFocusEditText(mIsInAllAppsRegion); } // Draw active task below Launcher so that All Apps can appear over it. @@ -835,7 +837,7 @@ public abstract class AbsSwipeUpHandler, if (!canCreateNewOrUpdateExistingLauncherTransitionController()) { return; } - initTransitionEndpoints(mActivity.getDeviceProfile()); + initTransitionEndpoints(mContainer.getDeviceProfile()); mAnimationFactory.createActivityInterface(mTransitionDragLength); } @@ -846,7 +848,7 @@ public abstract class AbsSwipeUpHandler, */ private boolean canCreateNewOrUpdateExistingLauncherTransitionController() { return mGestureState.getEndTarget() != HOME - && !mHasEndedLauncherTransition && mActivity != null; + && !mHasEndedLauncherTransition && mContainer != null; } @Override @@ -930,11 +932,11 @@ public abstract class AbsSwipeUpHandler, // needs to be canceled mRecentsAnimationController.setWillFinishToHome(swipeUpThresholdPassed); - if (mActivity == null) return; + if (mContainer == null) return; if (swipeUpThresholdPassed) { - mActivity.getSystemUiController().updateUiState(UI_STATE_FULLSCREEN_TASK, 0); + mContainer.getSystemUiController().updateUiState(UI_STATE_FULLSCREEN_TASK, 0); } else { - mActivity.getSystemUiController().updateUiState( + mContainer.getSystemUiController().updateUiState( UI_STATE_FULLSCREEN_TASK, centermostTaskFlags); } } @@ -962,7 +964,7 @@ public abstract class AbsSwipeUpHandler, // Only initialize the device profile, if it has not been initialized before, as in some // configurations targets.homeContentInsets may not be correct. - if (mActivity == null) { + if (mContainer == null) { RemoteAnimationTarget primaryTaskTarget = targets.apps[0]; // orientation state is independent of which remote target handle we use since both // should be pointing to the same one. Just choose index 0 for now since that works for @@ -971,7 +973,7 @@ public abstract class AbsSwipeUpHandler, .getOrientationState(); DeviceProfile dp = orientationState.getLauncherDeviceProfile(); if (targets.minimizedHomeBounds != null && primaryTaskTarget != null) { - Rect overviewStackBounds = mActivityInterface + Rect overviewStackBounds = mContainerInterface .getOverviewWindowBounds(targets.minimizedHomeBounds, primaryTaskTarget); dp = dp.getMultiWindowProfile(mContext, new WindowBounds(overviewStackBounds, targets.homeContentInsets)); @@ -1014,7 +1016,7 @@ public abstract class AbsSwipeUpHandler, @UiThread public void onGestureStarted(boolean isLikelyToStartNewTask) { - mActivityInterface.closeOverlay(); + mContainerInterface.closeOverlay(); TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS); if (mRecentsView != null) { @@ -1074,11 +1076,11 @@ public abstract class AbsSwipeUpHandler, */ @UiThread private void notifyGestureStarted() { - final T curActivity = mActivity; + final T curActivity = mContainer; if (curActivity != null) { // Once the gesture starts, we can no longer transition home through the button, so // reset the force override of the activity visibility - mActivity.clearForceInvisibleFlag(STATE_HANDLER_INVISIBILITY_FLAGS); + mContainer.clearForceInvisibleFlag(STATE_HANDLER_INVISIBILITY_FLAGS); } } @@ -1147,7 +1149,7 @@ public abstract class AbsSwipeUpHandler, maybeUpdateRecentsAttachedState(false); final GestureEndTarget endTarget = mGestureState.getEndTarget(); // Wait until the given View (if supplied) draws before resuming the last task. - View postResumeLastTask = mActivityInterface.onSettledOnEndTarget(endTarget); + View postResumeLastTask = mContainerInterface.onSettledOnEndTarget(endTarget); if (endTarget != NEW_TASK) { InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_QUICK_SWITCH); @@ -1168,7 +1170,7 @@ public abstract class AbsSwipeUpHandler, // Notify the SysUI to use fade-in animation when entering PiP SystemUiProxy.INSTANCE.get(mContext).setPipAnimationTypeToAlpha(); DesktopVisibilityController desktopVisibilityController = - mActivityInterface.getDesktopVisibilityController(); + mContainerInterface.getDesktopVisibilityController(); if (desktopVisibilityController != null) { // Notify the SysUI to stash desktop apps if they are visible desktopVisibilityController.onHomeActionTriggered(); @@ -1357,7 +1359,7 @@ public abstract class AbsSwipeUpHandler, } } Interpolator interpolator; - S state = mActivityInterface.stateFromGestureEndTarget(endTarget); + S state = mContainerInterface.stateFromGestureEndTarget(endTarget); if (isKeyboardTaskFocusPending()) { interpolator = EMPHASIZED; } else if (state.displayOverviewTasksAsGrid(mDp)) { @@ -1372,7 +1374,7 @@ public abstract class AbsSwipeUpHandler, mInputConsumerProxy.enable(); } if (endTarget == HOME) { - duration = mActivity != null && mActivity.getDeviceProfile().isTaskbarPresent + duration = mContainer != null && mContainer.getDeviceProfile().isTaskbarPresent ? StaggeredWorkspaceAnim.DURATION_TASKBAR_MS : StaggeredWorkspaceAnim.DURATION_MS; // Early detach the nav bar once the endTarget is determined as HOME @@ -1509,14 +1511,14 @@ public abstract class AbsSwipeUpHandler, if (mGestureState.getEndTarget().isLauncher) { // This is also called when the launcher is resumed, in order to clear the pending // widgets that have yet to be configured. - if (mActivity != null) { - DragView.removeAllViews(mActivity); + if (mContainer != null) { + DragView.removeAllViews(mContainer); } TaskStackChangeListeners.getInstance().registerTaskStackListener( mActivityRestartListener); - mParallelRunningAnim = mActivityInterface.getParallelAnimationToLauncher( + mParallelRunningAnim = mContainerInterface.getParallelAnimationToLauncher( mGestureState.getEndTarget(), duration, mTaskAnimationManager.getCurrentCallbacks()); if (mParallelRunningAnim != null) { @@ -1614,7 +1616,7 @@ public abstract class AbsSwipeUpHandler, if (windowAnimation == null) { continue; } - DeviceProfile dp = mActivity == null ? null : mActivity.getDeviceProfile(); + DeviceProfile dp = mContainer == null ? null : mContainer.getDeviceProfile(); windowAnimation.start(mContext, dp, velocityPxPerMs); mRunningWindowAnim[i] = RunningWindowAnim.wrap(windowAnimation); } @@ -1867,7 +1869,7 @@ public abstract class AbsSwipeUpHandler, } // Make sure recents is in its final state maybeUpdateRecentsAttachedState(false); - mActivityInterface.onSwipeUpToHomeComplete(mDeviceState); + mContainerInterface.onSwipeUpToHomeComplete(mDeviceState); } }); if (mRecentsAnimationTargets != null) { @@ -1941,8 +1943,8 @@ public abstract class AbsSwipeUpHandler, private void reset() { mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED); - if (mActivity != null) { - mActivity.removeEventCallback(EVENT_DESTROYED, mLauncherOnDestroyCallback); + if (mContainer != null) { + mContainer.removeEventCallback(EVENT_DESTROYED, mLauncherOnDestroyCallback); } } @@ -1966,7 +1968,7 @@ public abstract class AbsSwipeUpHandler, } private void invalidateHandler() { - if (!mActivityInterface.isInLiveTileMode() || mGestureState.getEndTarget() != RECENTS) { + if (!mContainerInterface.isInLiveTileMode() || mGestureState.getEndTarget() != RECENTS) { mInputConsumerProxy.destroy(); mTaskAnimationManager.setLiveTileCleanUpHandler(null); } @@ -2013,11 +2015,11 @@ public abstract class AbsSwipeUpHandler, * continued quick switch gesture, which cancels the previous handler but doesn't invalidate it. */ private void resetLauncherListeners() { - if (mActivity != null) { - mActivity.removeEventCallback(EVENT_STARTED, mLauncherOnStartCallback); - mActivity.removeEventCallback(EVENT_DESTROYED, mLauncherOnDestroyCallback); + if (mContainer != null) { + mContainer.removeEventCallback(EVENT_STARTED, mLauncherOnStartCallback); + mContainer.removeEventCallback(EVENT_DESTROYED, mLauncherOnDestroyCallback); - mActivity.getRootView().setOnApplyWindowInsetsListener(null); + mContainer.getRootView().setOnApplyWindowInsetsListener(null); } if (mRecentsView != null) { mRecentsView.removeOnScrollChangedListener(mOnRecentsScrollListener); @@ -2026,11 +2028,11 @@ public abstract class AbsSwipeUpHandler, private void resetStateForAnimationCancel() { boolean wasVisible = mWasLauncherAlreadyVisible || mGestureStarted; - mActivityInterface.onTransitionCancelled(wasVisible, mGestureState.getEndTarget()); + mContainerInterface.onTransitionCancelled(wasVisible, mGestureState.getEndTarget()); // Leave the pending invisible flag, as it may be used by wallpaper open animation. - if (mActivity != null) { - mActivity.clearForceInvisibleFlag(INVISIBLE_BY_STATE_HANDLER); + if (mContainer != null) { + mContainer.clearForceInvisibleFlag(INVISIBLE_BY_STATE_HANDLER); } } @@ -2296,14 +2298,14 @@ public abstract class AbsSwipeUpHandler, onRestartPreviouslyAppearedTask(); } } else { - mActivityInterface.onLaunchTaskFailed(); + mContainerInterface.onLaunchTaskFailed(); if (mRecentsAnimationController != null) { mRecentsAnimationController.finish(true /* toRecents */, null); } } }, true /* freezeTaskList */); } else { - mActivityInterface.onLaunchTaskFailed(); + mContainerInterface.onLaunchTaskFailed(); Toast.makeText(mContext, R.string.activity_not_available, LENGTH_SHORT).show(); if (mRecentsAnimationController != null) { mRecentsAnimationController.finish(true /* toRecents */, null); @@ -2395,12 +2397,12 @@ public abstract class AbsSwipeUpHandler, finishRecentsAnimationOnTasksAppeared(null /* onFinishComplete */); return; } - if (mActivity == null) { + if (mContainer == null) { ActiveGestureLog.INSTANCE.addLog("Activity destroyed"); finishRecentsAnimationOnTasksAppeared(null /* onFinishComplete */); return; } - animateSplashScreenExit(mActivity, appearedTaskTargets, taskTarget.leash); + animateSplashScreenExit(mContainer, appearedTaskTargets, taskTarget.leash); } private void animateSplashScreenExit( @@ -2515,7 +2517,7 @@ public abstract class AbsSwipeUpHandler, transaction.setAlpha(app.leash, 1f - fadeProgress); transaction.setPosition(app.leash, /* x= */ app.startBounds.left - + (mActivity.getDeviceProfile().overviewPageSpacing + + (mContainer.getDeviceProfile().overviewPageSpacing * (mRecentsView.isRtl() ? fadeProgress : -fadeProgress)), /* y= */ 0f); transaction.setScale(app.leash, 1f, 1f); @@ -2566,7 +2568,7 @@ public abstract class AbsSwipeUpHandler, // Scaling of RecentsView during quick switch based on amount of recents scroll private float getScaleProgressDueToScroll() { - if (mActivity == null || !mActivity.getDeviceProfile().isTablet || mRecentsView == null + if (mContainer == null || !mContainer.getDeviceProfile().isTablet || mRecentsView == null || !shouldLinkRecentsViewScroll()) { return 0; } diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java index a3f6be032b..00cd60b1d6 100644 --- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java +++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java @@ -18,11 +18,9 @@ package com.android.quickstep; import static com.android.app.animation.Interpolators.ACCELERATE_2; import static com.android.app.animation.Interpolators.INSTANT; import static com.android.app.animation.Interpolators.LINEAR; -import static com.android.launcher3.LauncherAnimUtils.VIEW_BACKGROUND_COLOR; import static com.android.launcher3.MotionEventsUtils.isTrackpadMultiFingerSwipe; import static com.android.quickstep.AbsSwipeUpHandler.RECENTS_ATTACH_DURATION; import static com.android.quickstep.GestureState.GestureEndTarget.LAST_TASK; -import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS; import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_FADE_ANIM; import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_TRANSLATE_X_ANIM; import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET; @@ -33,23 +31,12 @@ import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; -import android.content.Context; -import android.content.res.Resources; import android.graphics.Color; -import android.graphics.PointF; -import android.graphics.Rect; -import android.view.Gravity; import android.view.MotionEvent; -import android.view.RemoteAnimationTarget; -import android.view.View; import androidx.annotation.Nullable; import androidx.annotation.UiThread; -import com.android.launcher3.DeviceProfile; -import com.android.launcher3.Flags; -import com.android.launcher3.R; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.statehandlers.DepthController; @@ -57,29 +44,23 @@ import com.android.launcher3.statehandlers.DesktopVisibilityController; import com.android.launcher3.statemanager.BaseState; import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.taskbar.TaskbarUIController; -import com.android.launcher3.touch.PagedOrientationHandler; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.NavigationMode; -import com.android.launcher3.views.ScrimView; -import com.android.quickstep.orientation.RecentsPagedOrientationHandler; -import com.android.quickstep.util.ActivityInitListener; import com.android.quickstep.util.AnimatorControllerWithResistance; import com.android.quickstep.views.RecentsView; +import com.android.quickstep.views.RecentsViewContainer; import com.android.systemui.shared.recents.model.ThumbnailData; import java.util.HashMap; import java.util.Optional; import java.util.function.Consumer; -import java.util.function.Predicate; /** * Utility class which abstracts out the logical differences between Launcher and RecentsActivity. */ public abstract class BaseActivityInterface, - ACTIVITY_TYPE extends StatefulActivity> { - - public final boolean rotationSupportedByActivity; - + ACTIVITY_TYPE extends StatefulActivity & RecentsViewContainer> extends + BaseContainerInterface { private final STATE_TYPE mBackgroundState; private STATE_TYPE mTargetState; @@ -100,7 +81,7 @@ public abstract class BaseActivityInterface callback); - - public abstract ActivityInitListener createActivityInitListener( - Predicate onInitListener); - - /** - * Sets a callback to be run when an activity launch happens while launcher is not yet resumed. - */ - public void setOnDeferredActivityLaunchCallback(Runnable r) {} - @Nullable - public abstract ACTIVITY_TYPE getCreatedActivity(); + public abstract ACTIVITY_TYPE getCreatedContainer(); @Nullable public DepthController getDepthController() { return null; } - @Nullable - public DesktopVisibilityController getDesktopVisibilityController() { - return null; - } - - @Nullable - public abstract TaskbarUIController getTaskbarController(); - public final boolean isResumed() { - ACTIVITY_TYPE activity = getCreatedActivity(); + ACTIVITY_TYPE activity = getCreatedContainer(); return activity != null && activity.hasBeenResumed(); } public final boolean isStarted() { - ACTIVITY_TYPE activity = getCreatedActivity(); + ACTIVITY_TYPE activity = getCreatedContainer(); return activity != null && activity.isStarted(); } @@ -177,14 +130,6 @@ public abstract class BaseActivityInterface thumbnailDatas, Runnable runnable) { - ACTIVITY_TYPE activity = getCreatedActivity(); + ACTIVITY_TYPE activity = getCreatedContainer(); if (activity == null) { return; } @@ -231,230 +162,9 @@ public abstract class BaseActivityInterface callback) { mCallback = callback; - mActivity = getCreatedActivity(); + mActivity = getCreatedContainer(); mStartState = mActivity.getStateManager().getState(); } diff --git a/quickstep/src/com/android/quickstep/BaseContainerInterface.java b/quickstep/src/com/android/quickstep/BaseContainerInterface.java new file mode 100644 index 0000000000..99551834f1 --- /dev/null +++ b/quickstep/src/com/android/quickstep/BaseContainerInterface.java @@ -0,0 +1,377 @@ +/* + * Copyright (C) 2024 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.quickstep; + +import static com.android.app.animation.Interpolators.INSTANT; +import static com.android.app.animation.Interpolators.LINEAR; +import static com.android.launcher3.LauncherAnimUtils.VIEW_BACKGROUND_COLOR; +import static com.android.quickstep.GestureState.GestureEndTarget.LAST_TASK; +import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS; + +import android.animation.Animator; +import android.animation.ObjectAnimator; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Color; +import android.graphics.PointF; +import android.graphics.Rect; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.RemoteAnimationTarget; +import android.view.View; + +import androidx.annotation.Nullable; + +import com.android.launcher3.DeviceProfile; +import com.android.launcher3.Flags; +import com.android.launcher3.R; +import com.android.launcher3.statehandlers.DesktopVisibilityController; +import com.android.launcher3.statemanager.BaseState; +import com.android.launcher3.taskbar.TaskbarUIController; +import com.android.launcher3.touch.PagedOrientationHandler; +import com.android.launcher3.util.DisplayController; +import com.android.launcher3.views.ScrimView; +import com.android.quickstep.orientation.RecentsPagedOrientationHandler; +import com.android.quickstep.util.ActivityInitListener; +import com.android.quickstep.util.AnimatorControllerWithResistance; +import com.android.quickstep.views.RecentsView; +import com.android.quickstep.views.RecentsViewContainer; +import com.android.systemui.shared.recents.model.ThumbnailData; + +import java.util.HashMap; +import java.util.function.Consumer; +import java.util.function.Predicate; + +public abstract class BaseContainerInterface, + CONTAINER_TYPE extends RecentsViewContainer> { + + public boolean rotationSupportedByActivity = false; + + @Nullable + public abstract CONTAINER_TYPE getCreatedContainer(); + + public abstract boolean isInLiveTileMode(); + + public abstract void onAssistantVisibilityChanged(float assistantVisibility); + + public abstract boolean allowMinimizeSplitScreen(); + + public abstract boolean isResumed(); + + public abstract boolean isStarted(); + public abstract boolean deferStartingActivity(RecentsAnimationDeviceState deviceState, + MotionEvent ev); + + /** @return whether to allow going to All Apps from Overview. */ + public abstract boolean allowAllAppsFromOverview(); + + /** + * Returns the color of the scrim behind overview when at rest in this state. + * Return {@link Color#TRANSPARENT} for no scrim. + */ + protected abstract int getOverviewScrimColorForState(CONTAINER_TYPE container, + STATE_TYPE state); + + public abstract int getSwipeUpDestinationAndLength( + DeviceProfile dp, Context context, Rect outRect, + RecentsPagedOrientationHandler orientationHandler); + + @Nullable + public abstract TaskbarUIController getTaskbarController(); + + public abstract BaseActivityInterface.AnimationFactory prepareRecentsUI( + RecentsAnimationDeviceState deviceState, boolean activityVisible, + Consumer callback); + + public abstract ActivityInitListener createActivityInitListener( + Predicate onInitListener); + /** + * Returns the expected STATE_TYPE from the provided GestureEndTarget. + */ + public abstract STATE_TYPE stateFromGestureEndTarget(GestureState.GestureEndTarget endTarget); + + public abstract void switchRunningTaskViewToScreenshot(HashMap thumbnailDatas, Runnable runnable); + + public abstract void closeOverlay(); + + public abstract Rect getOverviewWindowBounds( + Rect homeBounds, RemoteAnimationTarget target); + + public abstract void onLaunchTaskFailed(); + + public abstract void onExitOverview(RotationTouchHelper deviceState, + Runnable exitRunnable); + + /** Called when the animation to home has fully settled. */ + public void onSwipeUpToHomeComplete(RecentsAnimationDeviceState deviceState) {} + + /** + * Sets a callback to be run when an activity launch happens while launcher is not yet resumed. + */ + public void setOnDeferredActivityLaunchCallback(Runnable r) {} + /** + * @return Whether the gesture in progress should be cancelled. + */ + public boolean shouldCancelCurrentGesture() { + return false; + } + + @Nullable + public DesktopVisibilityController getDesktopVisibilityController() { + return null; + } + + /** + * Called when the gesture ends and the animation starts towards the given target. Used to add + * an optional additional animation with the same duration. + */ + public @Nullable Animator getParallelAnimationToLauncher( + GestureState.GestureEndTarget endTarget, long duration, + RecentsAnimationCallbacks callbacks) { + if (endTarget == RECENTS) { + CONTAINER_TYPE container = getCreatedContainer(); + if (container == null) { + return null; + } + RecentsView recentsView = container.getOverviewPanel(); + STATE_TYPE state = stateFromGestureEndTarget(endTarget); + ScrimView scrimView = container.getScrimView(); + ObjectAnimator anim = ObjectAnimator.ofArgb(scrimView, VIEW_BACKGROUND_COLOR, + getOverviewScrimColorForState(container, state)); + anim.setDuration(duration); + anim.setInterpolator(recentsView == null || !recentsView.isKeyboardTaskFocusPending() + ? LINEAR : INSTANT); + return anim; + } + return null; + } + + /** + * Called when the animation to the target has finished, but right before updating the state. + * @return A View that needs to draw before ending the recents animation to LAST_TASK. + * (This is a hack to ensure Taskbar draws its background first to avoid flickering.) + */ + public @Nullable View onSettledOnEndTarget(GestureState.GestureEndTarget endTarget) { + TaskbarUIController taskbarUIController = getTaskbarController(); + if (taskbarUIController != null) { + taskbarUIController.setSystemGestureInProgress(false); + return taskbarUIController.getRootView(); + } + return null; + } + + /** + * Called when the current gesture transition is cancelled. + * @param activityVisible Whether the user can see the changes we make here, so try to animate. + * @param endTarget If the gesture ended before we got cancelled, where we were headed. + */ + public void onTransitionCancelled(boolean activityVisible, + @Nullable GestureState.GestureEndTarget endTarget) { + RecentsViewContainer container = getCreatedContainer(); + if (container == null) { + return; + } + RecentsView recentsView = container.getOverviewPanel(); + BaseState startState = recentsView.getStateManager().getRestState(); + if (endTarget != null) { + // We were on our way to this state when we got canceled, end there instead. + startState = stateFromGestureEndTarget(endTarget); + DesktopVisibilityController controller = getDesktopVisibilityController(); + if (controller != null && controller.areDesktopTasksVisible() + && endTarget == LAST_TASK) { + // When we are cancelling the transition and going back to last task, move to + // rest state instead when desktop tasks are visible. + // If a fullscreen task is visible, launcher goes to normal state when the + // activity is stopped. This does not happen when desktop tasks are visible + // on top of launcher. Force the launcher state to rest state here. + startState = recentsView.getStateManager().getRestState(); + // Do not animate the transition + activityVisible = false; + } + } + recentsView.getStateManager().goToState(startState, activityVisible); + } + + public final void calculateTaskSize(Context context, DeviceProfile dp, Rect outRect, + PagedOrientationHandler orientedState) { + if (dp.isTablet) { + if (Flags.enableGridOnlyOverview()) { + calculateGridTaskSize(context, dp, outRect, orientedState); + } else { + calculateFocusTaskSize(context, dp, outRect); + } + } else { + Resources res = context.getResources(); + float maxScale = res.getFloat(R.dimen.overview_max_scale); + int taskMargin = dp.overviewTaskMarginPx; + calculateTaskSizeInternal( + context, + dp, + dp.overviewTaskThumbnailTopMarginPx, + dp.getOverviewActionsClaimedSpace(), + res.getDimensionPixelSize(R.dimen.overview_minimum_next_prev_size) + taskMargin, + maxScale, + Gravity.CENTER, + outRect); + } + } + + /** + * Calculates the taskView size for carousel during app to overview animation on tablets. + */ + public final void calculateCarouselTaskSize(Context context, DeviceProfile dp, Rect outRect, + PagedOrientationHandler orientedState) { + if (dp.isTablet && dp.isGestureMode) { + Resources res = context.getResources(); + float minScale = res.getFloat(R.dimen.overview_carousel_min_scale); + Rect gridRect = new Rect(); + calculateGridSize(dp, context, gridRect); + calculateTaskSizeInternal(context, dp, gridRect, minScale, Gravity.CENTER | Gravity.TOP, + outRect); + } else { + calculateTaskSize(context, dp, outRect, orientedState); + } + } + + private void calculateFocusTaskSize(Context context, DeviceProfile dp, Rect outRect) { + Resources res = context.getResources(); + float maxScale = res.getFloat(R.dimen.overview_max_scale); + Rect gridRect = new Rect(); + calculateGridSize(dp, context, gridRect); + calculateTaskSizeInternal(context, dp, gridRect, maxScale, Gravity.CENTER, outRect); + } + + private void calculateTaskSizeInternal(Context context, DeviceProfile dp, int claimedSpaceAbove, + int claimedSpaceBelow, int minimumHorizontalPadding, float maxScale, int gravity, + Rect outRect) { + Rect insets = dp.getInsets(); + + Rect potentialTaskRect = new Rect(0, 0, dp.widthPx, dp.heightPx); + potentialTaskRect.inset(insets.left, insets.top, insets.right, insets.bottom); + potentialTaskRect.inset( + minimumHorizontalPadding, + claimedSpaceAbove, + minimumHorizontalPadding, + claimedSpaceBelow); + + calculateTaskSizeInternal(context, dp, potentialTaskRect, maxScale, gravity, outRect); + } + + private void calculateTaskSizeInternal(Context context, DeviceProfile dp, + Rect potentialTaskRect, float targetScale, int gravity, Rect outRect) { + PointF taskDimension = getTaskDimension(context, dp); + + float scale = Math.min( + potentialTaskRect.width() / taskDimension.x, + potentialTaskRect.height() / taskDimension.y); + scale = Math.min(scale, targetScale); + int outWidth = Math.round(scale * taskDimension.x); + int outHeight = Math.round(scale * taskDimension.y); + + Gravity.apply(gravity, outWidth, outHeight, potentialTaskRect, outRect); + } + + private static PointF getTaskDimension(Context context, DeviceProfile dp) { + PointF dimension = new PointF(); + getTaskDimension(context, dp, dimension); + return dimension; + } + + /** + * Gets the dimension of the task in the current system state. + */ + public static void getTaskDimension(Context context, DeviceProfile dp, PointF out) { + out.x = dp.widthPx; + out.y = dp.heightPx; + if (dp.isTablet && !DisplayController.isTransientTaskbar(context)) { + out.y -= dp.taskbarHeight; + } + } + + /** + * Calculates the overview grid size for the provided device configuration. + */ + public final void calculateGridSize(DeviceProfile dp, Context context, Rect outRect) { + Rect insets = dp.getInsets(); + int topMargin = dp.overviewTaskThumbnailTopMarginPx; + int bottomMargin = dp.getOverviewActionsClaimedSpace(); + if (dp.isTaskbarPresent && Flags.enableGridOnlyOverview()) { + topMargin += context.getResources().getDimensionPixelSize( + R.dimen.overview_top_margin_grid_only); + bottomMargin += context.getResources().getDimensionPixelSize( + R.dimen.overview_bottom_margin_grid_only); + } + int sideMargin = dp.overviewGridSideMargin; + + outRect.set(0, 0, dp.widthPx, dp.heightPx); + outRect.inset(Math.max(insets.left, sideMargin), insets.top + topMargin, + Math.max(insets.right, sideMargin), Math.max(insets.bottom, bottomMargin)); + } + + /** + * Calculates the overview grid non-focused task size for the provided device configuration. + */ + public final void calculateGridTaskSize(Context context, DeviceProfile dp, Rect outRect, + PagedOrientationHandler orientedState) { + Resources res = context.getResources(); + Rect potentialTaskRect = new Rect(); + if (Flags.enableGridOnlyOverview()) { + calculateGridSize(dp, context, potentialTaskRect); + } else { + calculateFocusTaskSize(context, dp, potentialTaskRect); + } + + float rowHeight = (potentialTaskRect.height() + dp.overviewTaskThumbnailTopMarginPx + - dp.overviewRowSpacing) / 2f; + + PointF taskDimension = getTaskDimension(context, dp); + float scale = (rowHeight - dp.overviewTaskThumbnailTopMarginPx) / taskDimension.y; + int outWidth = Math.round(scale * taskDimension.x); + int outHeight = Math.round(scale * taskDimension.y); + + int gravity = Gravity.TOP; + gravity |= orientedState.getRecentsRtlSetting(res) ? Gravity.RIGHT : Gravity.LEFT; + Gravity.apply(gravity, outWidth, outHeight, potentialTaskRect, outRect); + } + + /** + * Calculates the modal taskView size for the provided device configuration + */ + public final void calculateModalTaskSize(Context context, DeviceProfile dp, Rect outRect, + PagedOrientationHandler orientedState) { + calculateTaskSize(context, dp, outRect, orientedState); + boolean isGridOnlyOverview = dp.isTablet && Flags.enableGridOnlyOverview(); + int claimedSpaceBelow = isGridOnlyOverview + ? dp.overviewActionsTopMarginPx + dp.overviewActionsHeight + dp.stashedTaskbarHeight + : (dp.heightPx - outRect.bottom - dp.getInsets().bottom); + int minimumHorizontalPadding = 0; + if (!isGridOnlyOverview) { + float maxScale = context.getResources().getFloat(R.dimen.overview_modal_max_scale); + minimumHorizontalPadding = + Math.round((dp.availableWidthPx - outRect.width() * maxScale) / 2); + } + calculateTaskSizeInternal( + context, + dp, + dp.overviewTaskMarginPx, + claimedSpaceBelow, + minimumHorizontalPadding, + 1f /*maxScale*/, + Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, + outRect); + } +} diff --git a/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt new file mode 100644 index 0000000000..aa0f728b8b --- /dev/null +++ b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2024 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.quickstep + +import android.view.View +import com.android.launcher3.AbstractFloatingViewHelper +import com.android.launcher3.R +import com.android.launcher3.logging.StatsLogManager.LauncherEvent +import com.android.launcher3.popup.SystemShortcut +import com.android.quickstep.views.RecentsView +import com.android.quickstep.views.RecentsViewContainer +import com.android.quickstep.views.TaskView.TaskIdAttributeContainer +import com.android.window.flags.Flags + +/** A menu item, "Desktop", that allows the user to bring the current app into Desktop Windowing. */ +class DesktopSystemShortcut( + container: RecentsViewContainer, + private val mTaskContainer: TaskIdAttributeContainer, + abstractFloatingViewHelper: AbstractFloatingViewHelper +) : + SystemShortcut( + R.drawable.ic_caption_desktop_button_foreground, + R.string.recent_task_option_desktop, + container, + mTaskContainer.itemInfo, + mTaskContainer.taskView, + abstractFloatingViewHelper + ) { + override fun onClick(view: View) { + dismissTaskMenuView() + val recentsView = mTarget!!.getOverviewPanel>() + recentsView.moveTaskToDesktop(mTaskContainer) { + mTarget.statsLogManager + .logger() + .withItemInfo(mTaskContainer.itemInfo) + .log(LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_DESKTOP_TAP) + } + } + + companion object { + /** Creates a factory for creating Desktop system shorcuts. */ + @JvmOverloads + fun createFactory( + abstractFloatingViewHelper: AbstractFloatingViewHelper = AbstractFloatingViewHelper() + ): TaskShortcutFactory { + return object : TaskShortcutFactory { + override fun getShortcuts( + container: RecentsViewContainer, + taskContainer: TaskIdAttributeContainer + ): List? { + return if (!Flags.enableDesktopWindowingMode()) null + else if (!taskContainer.task.isDockable) null + else + listOf( + DesktopSystemShortcut( + container, + taskContainer, + abstractFloatingViewHelper + ) + ) + } + + override fun showForSplitscreen() = true + } + } + } +} diff --git a/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt b/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt index 678709c2e2..1cc54d825c 100644 --- a/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt +++ b/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt @@ -44,9 +44,26 @@ class DeviceConfigWrapper private constructor(propReader: PropReader) { "Enable AGSA override for LPNH and LPH timeout and touch slop" ) + val lpnhTimeoutMs = + propReader.get("LPNH_TIMEOUT_MS", 450, "Controls lpnh timeout in milliseconds") + val lpnhSlopPercentage = propReader.get("LPNH_SLOP_PERCENTAGE", 100, "Controls touch slop percentage for lpnh") + val enableLpnhTwoStages = + propReader.get( + "ENABLE_LPNH_TWO_STAGES", + false, + "Enable two stage for LPNH duration and touch slop" + ) + + val twoStageMultiplier = + propReader.get( + "TWO_STAGE_MULTIPLIER", + 2, + "Extends the duration and touch slop if the initial slop is passed" + ) + val animateLpnh = propReader.get("ANIMATE_LPNH", false, "Animates navbar when long pressing") val shrinkNavHandleOnPress = @@ -56,9 +73,6 @@ class DeviceConfigWrapper private constructor(propReader: PropReader) { "Shrinks navbar when long pressing if ANIMATE_LPNH is enabled" ) - val lpnhTimeoutMs = - propReader.get("LPNH_TIMEOUT_MS", 450, "Controls lpnh timeout in milliseconds") - val enableLongPressNavHandle = propReader.get( "ENABLE_LONG_PRESS_NAV_HANDLE", diff --git a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java index 27e8726975..9e896fddc5 100644 --- a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java +++ b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java @@ -96,13 +96,13 @@ public final class FallbackActivityInterface extends @Nullable @Override - public RecentsActivity getCreatedActivity() { + public RecentsActivity getCreatedContainer() { return RecentsActivity.ACTIVITY_TRACKER.getCreatedActivity(); } @Override public FallbackTaskbarUIController getTaskbarController() { - RecentsActivity activity = getCreatedActivity(); + RecentsActivity activity = getCreatedContainer(); if (activity == null) { return null; } @@ -112,7 +112,7 @@ public final class FallbackActivityInterface extends @Nullable @Override public RecentsView getVisibleRecentsView() { - RecentsActivity activity = getCreatedActivity(); + RecentsActivity activity = getCreatedContainer(); if (activity != null) { if (activity.hasBeenResumed() || isInLiveTileMode()) { return activity.getOverviewPanel(); @@ -154,7 +154,7 @@ public final class FallbackActivityInterface extends @Override public void onExitOverview(RotationTouchHelper deviceState, Runnable exitRunnable) { - final StateManager stateManager = getCreatedActivity().getStateManager(); + final StateManager stateManager = getCreatedContainer().getStateManager(); if (stateManager.getState() == HOME) { exitRunnable.run(); notifyRecentsOfOrientation(deviceState); @@ -177,7 +177,7 @@ public final class FallbackActivityInterface extends @Override public boolean isInLiveTileMode() { - RecentsActivity activity = getCreatedActivity(); + RecentsActivity activity = getCreatedContainer(); return activity != null && activity.getStateManager().getState() == DEFAULT && activity.isStarted(); } @@ -185,7 +185,7 @@ public final class FallbackActivityInterface extends @Override public void onLaunchTaskFailed() { // TODO: probably go back to overview instead. - RecentsActivity activity = getCreatedActivity(); + RecentsActivity activity = getCreatedContainer(); if (activity == null) { return; } @@ -209,7 +209,7 @@ public final class FallbackActivityInterface extends private void notifyRecentsOfOrientation(RotationTouchHelper rotationTouchHelper) { // reset layout on swipe to home - RecentsView recentsView = getCreatedActivity().getOverviewPanel(); + RecentsView recentsView = getCreatedContainer().getOverviewPanel(); recentsView.setLayoutRotation(rotationTouchHelper.getCurrentActiveRotation(), rotationTouchHelper.getDisplayRotation()); } diff --git a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java index b42eb067e4..92cdf72c73 100644 --- a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java +++ b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java @@ -223,7 +223,7 @@ public class FallbackSwipeHandler extends public AnimatorPlaybackController createActivityAnimationToHome() { // copied from {@link LauncherSwipeHandlerV2.LauncherHomeAnimationFactory} long accuracy = 2 * Math.max(mDp.widthPx, mDp.heightPx); - return mActivity.getStateManager().createAnimationToNewWorkspace( + return mContainer.getStateManager().createAnimationToNewWorkspace( RecentsState.HOME, accuracy, StateAnimationConfig.SKIP_ALL_ANIMATIONS); } } diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java index d02909c527..6b33c0aacb 100644 --- a/quickstep/src/com/android/quickstep/GestureState.java +++ b/quickstep/src/com/android/quickstep/GestureState.java @@ -37,10 +37,10 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.launcher3.statemanager.BaseState; -import com.android.launcher3.statemanager.StatefulActivity; import com.android.quickstep.TopTaskTracker.CachedTaskInfo; import com.android.quickstep.util.ActiveGestureErrorDetector; import com.android.quickstep.util.ActiveGestureLog; +import com.android.quickstep.views.RecentsViewContainer; import com.android.systemui.shared.recents.model.ThumbnailData; import java.io.PrintWriter; @@ -151,7 +151,7 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL // Needed to interact with the current activity private final Intent mHomeIntent; private final Intent mOverviewIntent; - private final BaseActivityInterface mActivityInterface; + private final BaseContainerInterface mContainerInterface; private final MultiStateCallback mStateCallback; private final int mGestureId; @@ -189,7 +189,7 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL public GestureState(OverviewComponentObserver componentObserver, int gestureId) { mHomeIntent = componentObserver.getHomeIntent(); mOverviewIntent = componentObserver.getOverviewIntent(); - mActivityInterface = componentObserver.getActivityInterface(); + mContainerInterface = componentObserver.getActivityInterface(); mStateCallback = new MultiStateCallback( STATE_NAMES.toArray(new String[0]), GestureState::getTrackedEventForState); mGestureId = gestureId; @@ -198,7 +198,7 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL public GestureState(GestureState other) { mHomeIntent = other.mHomeIntent; mOverviewIntent = other.mOverviewIntent; - mActivityInterface = other.mActivityInterface; + mContainerInterface = other.mContainerInterface; mStateCallback = other.mStateCallback; mGestureId = other.mGestureId; mRunningTask = other.mRunningTask; @@ -212,7 +212,7 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL // Do nothing, only used for initializing the gesture state prior to user unlock mHomeIntent = new Intent(); mOverviewIntent = new Intent(); - mActivityInterface = null; + mContainerInterface = null; mStateCallback = new MultiStateCallback( STATE_NAMES.toArray(new String[0]), GestureState::getTrackedEventForState); mGestureId = -1; @@ -268,9 +268,9 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL /** * @return the interface to the activity handing the UI updates for this gesture. */ - public , - T extends StatefulActivity> BaseActivityInterface getActivityInterface() { - return mActivityInterface; + public , T extends RecentsViewContainer> + BaseContainerInterface getContainerInterface() { + return mContainerInterface; } /** diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java index 7c17e4ee7a..7655c5913e 100644 --- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java +++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java @@ -36,7 +36,6 @@ import androidx.annotation.UiThread; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Flags; -import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAnimUtils; import com.android.launcher3.LauncherInitListener; import com.android.launcher3.LauncherState; @@ -86,7 +85,7 @@ public final class LauncherActivityInterface extends @Override public void onSwipeUpToHomeComplete(RecentsAnimationDeviceState deviceState) { - Launcher launcher = getCreatedActivity(); + QuickstepLauncher launcher = getCreatedContainer(); if (launcher == null) { return; } @@ -103,7 +102,7 @@ public final class LauncherActivityInterface extends @Override public void onAssistantVisibilityChanged(float visibility) { - Launcher launcher = getCreatedActivity(); + QuickstepLauncher launcher = getCreatedContainer(); if (launcher == null) { return; } @@ -145,7 +144,7 @@ public final class LauncherActivityInterface extends @Override public void setOnDeferredActivityLaunchCallback(Runnable r) { - Launcher launcher = getCreatedActivity(); + QuickstepLauncher launcher = getCreatedContainer(); if (launcher == null) { return; } @@ -154,14 +153,14 @@ public final class LauncherActivityInterface extends @Nullable @Override - public QuickstepLauncher getCreatedActivity() { + public QuickstepLauncher getCreatedContainer() { return QuickstepLauncher.ACTIVITY_TRACKER.getCreatedActivity(); } @Nullable @Override public DepthController getDepthController() { - QuickstepLauncher launcher = getCreatedActivity(); + QuickstepLauncher launcher = getCreatedContainer(); if (launcher == null) { return null; } @@ -171,7 +170,7 @@ public final class LauncherActivityInterface extends @Nullable @Override public DesktopVisibilityController getDesktopVisibilityController() { - QuickstepLauncher launcher = getCreatedActivity(); + QuickstepLauncher launcher = getCreatedContainer(); if (launcher == null) { return null; } @@ -181,7 +180,7 @@ public final class LauncherActivityInterface extends @Nullable @Override public LauncherTaskbarUIController getTaskbarController() { - QuickstepLauncher launcher = getCreatedActivity(); + QuickstepLauncher launcher = getCreatedContainer(); if (launcher == null) { return null; } @@ -191,7 +190,7 @@ public final class LauncherActivityInterface extends @Nullable @Override public RecentsView getVisibleRecentsView() { - Launcher launcher = getVisibleLauncher(); + QuickstepLauncher launcher = getVisibleLauncher(); RecentsView recentsView = launcher != null && launcher.getStateManager().getState().overviewUi ? launcher.getOverviewPanel() : null; @@ -205,8 +204,8 @@ public final class LauncherActivityInterface extends @Nullable @UiThread - private Launcher getVisibleLauncher() { - Launcher launcher = getCreatedActivity(); + private QuickstepLauncher getVisibleLauncher() { + QuickstepLauncher launcher = getCreatedContainer(); if (launcher == null) { return null; } @@ -222,7 +221,7 @@ public final class LauncherActivityInterface extends @Override public boolean switchToRecentsIfVisible(Animator.AnimatorListener animatorListener) { - Launcher launcher = getVisibleLauncher(); + QuickstepLauncher launcher = getVisibleLauncher(); if (launcher == null) { return false; } @@ -243,7 +242,7 @@ public final class LauncherActivityInterface extends @Override public void onExitOverview(RotationTouchHelper deviceState, Runnable exitRunnable) { - final StateManager stateManager = getCreatedActivity().getStateManager(); + final StateManager stateManager = getCreatedContainer().getStateManager(); stateManager.addStateListener( new StateManager.StateListener() { @Override @@ -260,7 +259,7 @@ public final class LauncherActivityInterface extends private void notifyRecentsOfOrientation(RotationTouchHelper rotationTouchHelper) { // reset layout on swipe to home - RecentsView recentsView = getCreatedActivity().getOverviewPanel(); + RecentsView recentsView = getCreatedContainer().getOverviewPanel(); recentsView.setLayoutRotation(rotationTouchHelper.getCurrentActiveRotation(), rotationTouchHelper.getDisplayRotation()); } @@ -279,12 +278,12 @@ public final class LauncherActivityInterface extends public boolean allowAllAppsFromOverview() { return FeatureFlags.ENABLE_ALL_APPS_FROM_OVERVIEW.get() // If floating search bar would not show in overview, don't allow all apps gesture. - && OVERVIEW.areElementsVisible(getCreatedActivity(), FLOATING_SEARCH_BAR); + && OVERVIEW.areElementsVisible(getCreatedContainer(), FLOATING_SEARCH_BAR); } @Override public boolean isInLiveTileMode() { - Launcher launcher = getCreatedActivity(); + QuickstepLauncher launcher = getCreatedContainer(); return launcher != null && launcher.getStateManager().getState() == OVERVIEW @@ -294,7 +293,7 @@ public final class LauncherActivityInterface extends @Override public void onLaunchTaskFailed() { - Launcher launcher = getCreatedActivity(); + QuickstepLauncher launcher = getCreatedContainer(); if (launcher == null) { return; } @@ -304,7 +303,7 @@ public final class LauncherActivityInterface extends @Override public void closeOverlay() { super.closeOverlay(); - Launcher launcher = getCreatedActivity(); + QuickstepLauncher launcher = getCreatedContainer(); if (launcher == null) { return; } @@ -337,9 +336,8 @@ public final class LauncherActivityInterface extends } @Override - protected int getOverviewScrimColorForState(QuickstepLauncher launcher, - LauncherState state) { - return state.getWorkspaceScrimColor(launcher); + protected int getOverviewScrimColorForState(QuickstepLauncher activity, LauncherState state) { + return state.getWorkspaceScrimColor(activity); } @Override diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java index f678bea778..6647057776 100644 --- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java +++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java @@ -75,7 +75,7 @@ public class LauncherSwipeHandlerV2 extends protected HomeAnimationFactory createHomeAnimationFactory(ArrayList launchCookies, long duration, boolean isTargetTranslucent, boolean appCanEnterPip, RemoteAnimationTarget runningTaskTarget) { - if (mActivity == null) { + if (mContainer == null) { mStateCallback.addChangeListener(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED, isPresent -> mRecentsView.startHome()); return new HomeAnimationFactory() { @@ -91,9 +91,9 @@ public class LauncherSwipeHandlerV2 extends boolean canUseWorkspaceView = workspaceView != null && workspaceView.isAttachedToWindow() && workspaceView.getHeight() > 0; - mActivity.getRootView().setForceHideBackArrow(true); + mContainer.getRootView().setForceHideBackArrow(true); if (!TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) { - mActivity.setHintUserWillBeActive(); + mContainer.setHintUserWillBeActive(); } if (!canUseWorkspaceView || appCanEnterPip || mIsSwipeForSplit) { @@ -108,10 +108,10 @@ public class LauncherSwipeHandlerV2 extends private HomeAnimationFactory createIconHomeAnimationFactory(View workspaceView) { RectF iconLocation = new RectF(); - FloatingIconView floatingIconView = getFloatingIconView(mActivity, workspaceView, null, - mActivity.getTaskbarUIController() == null + FloatingIconView floatingIconView = getFloatingIconView(mContainer, workspaceView, null, + mContainer.getTaskbarUIController() == null ? null - : mActivity.getTaskbarUIController().findMatchingView(workspaceView), + : mContainer.getTaskbarUIController().findMatchingView(workspaceView), true /* hideOriginal */, iconLocation, false /* isOpening */); // We want the window alpha to be 0 once this threshold is met, so that the @@ -171,7 +171,7 @@ public class LauncherSwipeHandlerV2 extends Size windowSize = new Size(crop.width(), crop.height()); int fallbackBackgroundColor = FloatingWidgetView.getDefaultBackgroundColor(mContext, runningTaskTarget); - FloatingWidgetView floatingWidgetView = FloatingWidgetView.getFloatingWidgetView(mActivity, + FloatingWidgetView floatingWidgetView = FloatingWidgetView.getFloatingWidgetView(mContainer, hostView, backgroundLocation, windowSize, tvs.getCurrentCornerRadius(), isTargetTranslucent, fallbackBackgroundColor); @@ -248,7 +248,7 @@ public class LauncherSwipeHandlerV2 extends } } - return mActivity.getFirstMatchForAppClose(launchCookieItemId, + return mContainer.getFirstMatchForAppClose(launchCookieItemId, runningTaskView.getTask().key.getComponent().getPackageName(), UserHandle.of(runningTaskView.getTask().key.userId), false /* supportsAllAppsState */); @@ -292,18 +292,18 @@ public class LauncherSwipeHandlerV2 extends // Return an empty APC here since we have an non-user controlled animation // to home. long accuracy = 2 * Math.max(mDp.widthPx, mDp.heightPx); - return mActivity.getStateManager().createAnimationToNewWorkspace( + return mContainer.getStateManager().createAnimationToNewWorkspace( NORMAL, accuracy, StateAnimationConfig.SKIP_ALL_ANIMATIONS); } @Override public void playAtomicAnimation(float velocity) { if (enableScalingRevealHomeAnimation()) { - if (mActivity != null) { - new ScalingWorkspaceRevealAnim(mActivity).start(); + if (mContainer != null) { + new ScalingWorkspaceRevealAnim(mContainer).start(); } } else { - new StaggeredWorkspaceAnim(mActivity, velocity, true /* animateOverviewScrim */, + new StaggeredWorkspaceAnim(mContainer, velocity, true /* animateOverviewScrim */, getViewIgnoredInWorkspaceRevealAnimation()) .start(); } diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java index 0db50bfe2d..68923eeccb 100644 --- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java +++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java @@ -40,6 +40,7 @@ import com.android.launcher3.util.RunnableList; import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener; import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.views.RecentsView; +import com.android.quickstep.views.RecentsViewContainer; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.InteractionJankMonitorWrapper; @@ -191,7 +192,8 @@ public class OverviewCommandHelper { * Executes the task and returns true if next task can be executed. If false, then the next * task is deferred until {@link #scheduleNextTask} is called */ - private > boolean executeCommand(CommandInfo cmd) { + private & RecentsViewContainer> boolean executeCommand( + CommandInfo cmd) { if (mWaitForToggleCommandComplete && cmd.type == TYPE_TOGGLE) { return true; } @@ -200,7 +202,7 @@ public class OverviewCommandHelper { RecentsView visibleRecentsView = activityInterface.getVisibleRecentsView(); RecentsView createdRecentsView; if (visibleRecentsView == null) { - T activity = activityInterface.getCreatedActivity(); + T activity = activityInterface.getCreatedContainer(); createdRecentsView = activity == null ? null : activity.getOverviewPanel(); DeviceProfile dp = activity == null ? null : activity.getDeviceProfile(); TaskbarUIController uiController = activityInterface.getTaskbarController(); @@ -296,7 +298,7 @@ public class OverviewCommandHelper { return false; } - final T activity = activityInterface.getCreatedActivity(); + final T activity = activityInterface.getCreatedContainer(); if (activity != null) { InteractionJankMonitorWrapper.begin( activity.getRootView(), @@ -327,7 +329,7 @@ public class OverviewCommandHelper { interactionHandler.onGestureCancelled(); cmd.removeListener(this); - T createdActivity = activityInterface.getCreatedActivity(); + T createdActivity = activityInterface.getCreatedContainer(); if (createdActivity == null) { return; } diff --git a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java index c3a4351d7b..dfbae657dd 100644 --- a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java +++ b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java @@ -208,7 +208,7 @@ public class QuickstepTestInformationHandler extends TestInformationHandler { RecentsAnimationDeviceState rads = new RecentsAnimationDeviceState(mContext); OverviewComponentObserver observer = new OverviewComponentObserver(mContext, rads); try { - return observer.getActivityInterface().getCreatedActivity(); + return observer.getActivityInterface().getCreatedContainer(); } finally { observer.onDestroy(); rads.destroy(); diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java index 81ab6bedcc..f57f4c8440 100644 --- a/quickstep/src/com/android/quickstep/RecentsActivity.java +++ b/quickstep/src/com/android/quickstep/RecentsActivity.java @@ -33,6 +33,7 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.app.ActivityOptions; +import android.content.Context; import android.content.Intent; import android.content.res.Configuration; import android.os.Bundle; @@ -85,6 +86,7 @@ import com.android.quickstep.util.SplitSelectStateController; import com.android.quickstep.util.TISBindHelper; import com.android.quickstep.views.OverviewActionsView; import com.android.quickstep.views.RecentsView; +import com.android.quickstep.views.RecentsViewContainer; import com.android.quickstep.views.TaskView; import java.io.FileDescriptor; @@ -95,7 +97,8 @@ import java.util.List; * A recents activity that shows the recently launched tasks as swipable task cards. * See {@link com.android.quickstep.views.RecentsView}. */ -public final class RecentsActivity extends StatefulActivity { +public final class RecentsActivity extends StatefulActivity implements + RecentsViewContainer { private static final String TAG = "RecentsActivity"; public static final ActivityTracker ACTIVITY_TRACKER = @@ -109,7 +112,7 @@ public final class RecentsActivity extends StatefulActivity { private RecentsDragLayer mDragLayer; private ScrimView mScrimView; private FallbackRecentsView mFallbackRecentsView; - private OverviewActionsView mActionsView; + private OverviewActionsView mActionsView; private TISBindHelper mTISBindHelper; private @Nullable FallbackTaskbarUIController mTaskbarUIController; @@ -224,11 +227,12 @@ public final class RecentsActivity extends StatefulActivity { } @Override - public T getOverviewPanel() { - return (T) mFallbackRecentsView; + public FallbackRecentsView getOverviewPanel() { + return mFallbackRecentsView; } - public OverviewActionsView getActionsView() { + @Override + public OverviewActionsView getActionsView() { return mActionsView; } diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java index 43e564cadf..4b4f914ed2 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java @@ -67,6 +67,7 @@ import com.android.launcher3.util.NavigationMode; import com.android.launcher3.util.SettingsCache; import com.android.quickstep.TopTaskTracker.CachedTaskInfo; import com.android.quickstep.util.ActiveGestureLog; +import com.android.quickstep.util.AssistStateManager; import com.android.quickstep.util.GestureExclusionManager; import com.android.quickstep.util.GestureExclusionManager.ExclusionListener; import com.android.quickstep.util.NavBarPosition; @@ -96,7 +97,7 @@ public class RecentsAnimationDeviceState implements DisplayInfoChangeListener, E private final DisplayController mDisplayController; private final GestureExclusionManager mExclusionManager; - + private final AssistStateManager mAssistStateManager; private final RotationTouchHelper mRotationTouchHelper; private final TaskStackChangeListener mPipListener; @@ -147,6 +148,7 @@ public class RecentsAnimationDeviceState implements DisplayInfoChangeListener, E mContext = context; mDisplayController = DisplayController.INSTANCE.get(context); mExclusionManager = exclusionManager; + mAssistStateManager = AssistStateManager.INSTANCE.get(context); mIsOneHandedModeSupported = SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false); mRotationTouchHelper = RotationTouchHelper.INSTANCE.get(context); if (isInstanceForTouches) { @@ -587,8 +589,8 @@ public class RecentsAnimationDeviceState implements DisplayInfoChangeListener, E : QUICKSTEP_TOUCH_SLOP_RATIO_TWO_BUTTON; float touchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop(); - if (DeviceConfigWrapper.get().getCustomLpnhThresholds()) { - float customSlopMultiplier = DeviceConfigWrapper.get().getLpnhSlopPercentage() / 100f; + if (mAssistStateManager.getLPNHCustomSlopMultiplier().isPresent()) { + float customSlopMultiplier = mAssistStateManager.getLPNHCustomSlopMultiplier().get(); return customSlopMultiplier * slopMultiplier * touchSlop; } else { return slopMultiplier * touchSlop; diff --git a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java index 0ce4d0a597..7f2adedbca 100644 --- a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java +++ b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java @@ -57,7 +57,7 @@ public class RemoteTargetGluer { /** * Use this constructor if remote targets are split-screen independent */ - public RemoteTargetGluer(Context context, BaseActivityInterface sizingStrategy, + public RemoteTargetGluer(Context context, BaseContainerInterface sizingStrategy, RemoteAnimationTargets targets, boolean forDesktop) { init(context, sizingStrategy, targets.apps.length, forDesktop); } @@ -66,11 +66,11 @@ public class RemoteTargetGluer { * Use this constructor if you want the number of handles created to match the number of active * running tasks */ - public RemoteTargetGluer(Context context, BaseActivityInterface sizingStrategy) { + public RemoteTargetGluer(Context context, BaseContainerInterface sizingStrategy) { DesktopVisibilityController desktopVisibilityController = LauncherActivityInterface.INSTANCE.getDesktopVisibilityController(); if (desktopVisibilityController != null) { - int visibleTasksCount = desktopVisibilityController.getVisibleFreeformTasksCount(); + int visibleTasksCount = desktopVisibilityController.getVisibleDesktopTasksCount(); if (visibleTasksCount > 0) { // Allocate +1 to account for a new task added to the desktop mode int numHandles = visibleTasksCount + 1; @@ -84,13 +84,13 @@ public class RemoteTargetGluer { init(context, sizingStrategy, DEFAULT_NUM_HANDLES, false /* forDesktop */); } - private void init(Context context, BaseActivityInterface sizingStrategy, int numHandles, + private void init(Context context, BaseContainerInterface sizingStrategy, int numHandles, boolean forDesktop) { mRemoteTargetHandles = createHandles(context, sizingStrategy, numHandles, forDesktop); } private RemoteTargetHandle[] createHandles(Context context, - BaseActivityInterface sizingStrategy, int numHandles, boolean forDesktop) { + BaseContainerInterface sizingStrategy, int numHandles, boolean forDesktop) { RemoteTargetHandle[] handles = new RemoteTargetHandle[numHandles]; for (int i = 0; i < numHandles; i++) { TaskViewSimulator tvs = new TaskViewSimulator(context, sizingStrategy); diff --git a/quickstep/src/com/android/quickstep/RotationTouchHelper.java b/quickstep/src/com/android/quickstep/RotationTouchHelper.java index 2d47097671..bf50d7022d 100644 --- a/quickstep/src/com/android/quickstep/RotationTouchHelper.java +++ b/quickstep/src/com/android/quickstep/RotationTouchHelper.java @@ -345,14 +345,14 @@ public class RotationTouchHelper implements DisplayInfoChangeListener { } void onEndTargetCalculated(GestureState.GestureEndTarget endTarget, - BaseActivityInterface activityInterface) { + BaseContainerInterface containerInterface) { if (endTarget == GestureState.GestureEndTarget.RECENTS) { mInOverview = true; if (!mTaskListFrozen) { // If we're in landscape w/o ever quickswitching, show the navbar in landscape enableMultipleRegions(true); } - activityInterface.onExitOverview(this, mExitOverviewRunnable); + containerInterface.onExitOverview(this, mExitOverviewRunnable); } else if (endTarget == GestureState.GestureEndTarget.HOME || endTarget == GestureState.GestureEndTarget.ALL_APPS) { enableMultipleRegions(false); diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java index b920c10d05..5ff978746c 100644 --- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java +++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java @@ -86,7 +86,7 @@ public abstract class SwipeUpAnimationLogic implements updateIsGestureForSplit(TopTaskTracker.INSTANCE.get(context) .getRunningSplitTaskIds().length); - mTargetGluer = new RemoteTargetGluer(mContext, mGestureState.getActivityInterface()); + mTargetGluer = new RemoteTargetGluer(mContext, mGestureState.getContainerInterface()); mRemoteTargetHandles = mTargetGluer.getRemoteTargetHandles(); runActionOnRemoteHandles(remoteTargetHandle -> remoteTargetHandle.getTaskViewSimulator().getOrientationState().update( @@ -97,9 +97,10 @@ public abstract class SwipeUpAnimationLogic implements protected void initTransitionEndpoints(DeviceProfile dp) { mDp = dp; - mTransitionDragLength = mGestureState.getActivityInterface().getSwipeUpDestinationAndLength( - dp, mContext, TEMP_RECT, mRemoteTargetHandles[0].getTaskViewSimulator() - .getOrientationState().getOrientationHandler()); + mTransitionDragLength = mGestureState.getContainerInterface() + .getSwipeUpDestinationAndLength(dp, mContext, TEMP_RECT, + mRemoteTargetHandles[0].getTaskViewSimulator().getOrientationState() + .getOrientationHandler()); mDragLengthFactor = (float) dp.heightPx / mTransitionDragLength; for (RemoteTargetHandle remoteHandle : mRemoteTargetHandles) { diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java index 08d54150d5..30bb863508 100644 --- a/quickstep/src/com/android/quickstep/SystemUiProxy.java +++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java @@ -1475,6 +1475,17 @@ public class SystemUiProxy implements ISystemUiProxy, NavHandle { } } + /** Call shell to move a task with given `taskId` to desktop */ + public void moveToDesktop(int taskId) { + if (mDesktopMode != null) { + try { + mDesktopMode.moveToDesktop(taskId); + } catch (RemoteException e) { + Log.w(TAG, "Failed call moveToDesktop", e); + } + } + } + // // Unfold transition // diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java index 4e62d60d2c..3b1ed4662a 100644 --- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java +++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java @@ -77,10 +77,11 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn mLiveTileRestartListener); return; } - BaseActivityInterface activityInterface = mLastGestureState.getActivityInterface(); - if (activityInterface.isInLiveTileMode() - && activityInterface.getCreatedActivity() != null) { - RecentsView recentsView = activityInterface.getCreatedActivity().getOverviewPanel(); + BaseContainerInterface containerInterface = mLastGestureState.getContainerInterface(); + if (containerInterface.isInLiveTileMode() + && containerInterface.getCreatedContainer() != null) { + RecentsView recentsView = containerInterface.getCreatedContainer() + .getOverviewPanel(); if (recentsView != null) { recentsView.launchSideTaskInLiveTileModeForRestartedApp(task.taskId); TaskStackChangeListeners.getInstance().unregisterTaskStackListener( @@ -135,10 +136,10 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn cleanUpRecentsAnimation(mCallbacks); } - final BaseActivityInterface activityInterface = gestureState.getActivityInterface(); + final BaseContainerInterface containerInterface = gestureState.getContainerInterface(); mLastGestureState = gestureState; RecentsAnimationCallbacks newCallbacks = new RecentsAnimationCallbacks( - SystemUiProxy.INSTANCE.get(mCtx), activityInterface.allowMinimizeSplitScreen()); + SystemUiProxy.INSTANCE.get(mCtx), containerInterface.allowMinimizeSplitScreen()); mCallbacks = newCallbacks; mCallbacks.addListener(new RecentsAnimationCallbacks.RecentsAnimationListener() { @Override @@ -208,17 +209,18 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn @Override public void onTasksAppeared(RemoteAnimationTarget[] appearedTaskTargets) { RemoteAnimationTarget appearedTaskTarget = appearedTaskTargets[0]; - BaseActivityInterface activityInterface = mLastGestureState.getActivityInterface(); + BaseContainerInterface containerInterface = + mLastGestureState.getContainerInterface(); for (RemoteAnimationTarget compat : appearedTaskTargets) { if (compat.windowConfiguration.getActivityType() == ACTIVITY_TYPE_HOME - && activityInterface.getCreatedActivity() instanceof RecentsActivity + && containerInterface.getCreatedContainer() instanceof RecentsActivity && DisplayController.getNavigationMode(mCtx) != NO_BUTTON) { // The only time we get onTasksAppeared() in button navigation with a // 3p launcher is if the user goes to overview first, and in this case we // can immediately finish the transition RecentsView recentsView = - activityInterface.getCreatedActivity().getOverviewPanel(); + containerInterface.getCreatedContainer().getOverviewPanel(); if (recentsView != null) { recentsView.finishRecentsAnimation(true, null); } @@ -232,12 +234,12 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn if (nonAppTargets == null) { nonAppTargets = new RemoteAnimationTarget[0]; } - if ((activityInterface.isInLiveTileMode() + if ((containerInterface.isInLiveTileMode() || mLastGestureState.getEndTarget() == RECENTS || isNonRecentsStartedTasksAppeared(appearedTaskTargets)) - && activityInterface.getCreatedActivity() != null) { + && containerInterface.getCreatedContainer() != null) { RecentsView recentsView = - activityInterface.getCreatedActivity().getOverviewPanel(); + containerInterface.getCreatedContainer().getOverviewPanel(); if (recentsView != null) { ActiveGestureLog.INSTANCE.addLog( new ActiveGestureLog.CompoundString("Launching side task id=") @@ -272,13 +274,13 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn @Override public boolean onSwitchToScreenshot(Runnable onFinished) { - if (!activityInterface.isInLiveTileMode() - || activityInterface.getCreatedActivity() == null) { + if (!containerInterface.isInLiveTileMode() + || containerInterface.getCreatedContainer() == null) { // No need to switch since tile is already a screenshot. onFinished.run(); } else { final RecentsView recentsView = - activityInterface.getCreatedActivity().getOverviewPanel(); + containerInterface.getCreatedContainer().getOverviewPanel(); if (recentsView != null) { recentsView.switchToScreenshot(onFinished); } else { @@ -295,7 +297,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn if (ENABLE_SHELL_TRANSITIONS) { final ActivityOptions options = ActivityOptions.makeBasic(); // Use regular (non-transient) launch for all apps page to control IME. - if (!activityInterface.allowAllAppsFromOverview()) { + if (!containerInterface.allowAllAppsFromOverview()) { options.setTransientLaunch(); } options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_RECENTS_ANIMATION, eventTime); @@ -332,10 +334,10 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn if (mLastGestureState == null) { return; } - BaseActivityInterface activityInterface = mLastGestureState.getActivityInterface(); - if (activityInterface.isInLiveTileMode() - && activityInterface.getCreatedActivity() != null) { - RecentsView recentsView = activityInterface.getCreatedActivity().getOverviewPanel(); + BaseContainerInterface containerInterface = mLastGestureState.getContainerInterface(); + if (containerInterface.isInLiveTileMode() + && containerInterface.getCreatedContainer() != null) { + RecentsView recentsView = containerInterface.getCreatedContainer().getOverviewPanel(); if (recentsView != null) { recentsView.switchToScreenshot(null, () -> recentsView.finishRecentsAnimation(true /* toRecents */, diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java index cc582d1e09..18b8e3e0f5 100644 --- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java +++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java @@ -33,7 +33,6 @@ import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; import com.android.launcher3.BaseActivity; -import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.Flags; import com.android.launcher3.R; import com.android.launcher3.model.data.ItemInfo; @@ -46,6 +45,7 @@ import com.android.quickstep.util.RecentsOrientedState; import com.android.quickstep.views.GroupedTaskView; import com.android.quickstep.views.OverviewActionsView; import com.android.quickstep.views.RecentsView; +import com.android.quickstep.views.RecentsViewContainer; import com.android.quickstep.views.TaskThumbnailView; import com.android.quickstep.views.TaskView; import com.android.quickstep.views.TaskView.TaskIdAttributeContainer; @@ -63,14 +63,15 @@ public class TaskOverlayFactory implements ResourceBasedOverride { public static List getEnabledShortcuts(TaskView taskView, TaskIdAttributeContainer taskContainer) { final ArrayList shortcuts = new ArrayList<>(); - final BaseDraggingActivity activity = BaseActivity.fromContext(taskView.getContext()); + final RecentsViewContainer container = + RecentsViewContainer.containerFromContext(taskView.getContext()); boolean hasMultipleTasks = taskView.getTaskIds()[1] != -1; for (TaskShortcutFactory menuOption : MENU_OPTIONS) { if (hasMultipleTasks && !menuOption.showForSplitscreen()) { continue; } - List menuShortcuts = menuOption.getShortcuts(activity, taskContainer); + List menuShortcuts = menuOption.getShortcuts(container, taskContainer); if (menuShortcuts == null) { continue; } @@ -79,15 +80,16 @@ public class TaskOverlayFactory implements ResourceBasedOverride { RecentsOrientedState orientedState = taskView.getRecentsView().getPagedViewOrientedState(); boolean canLauncherRotate = orientedState.isRecentsActivityRotationAllowed(); boolean isInLandscape = orientedState.getTouchRotation() != ROTATION_0; - boolean isTablet = activity.getDeviceProfile().isTablet; + boolean isTablet = container.getDeviceProfile().isTablet; boolean isGridOnlyOverview = isTablet && Flags.enableGridOnlyOverview(); - // Add overview actions to the menu when in in-place rotate landscape mode, or in - // grid-only overview. - if ((!canLauncherRotate && isInLandscape) || isGridOnlyOverview) { + // Add overview actions to the menu when: + // - single task is showing + // - in in-place rotate landscape mode, or in grid-only overview. + if (!hasMultipleTasks && ((!canLauncherRotate && isInLandscape) || isGridOnlyOverview)) { // Add screenshot action to task menu. List screenshotShortcuts = TaskShortcutFactory.SCREENSHOT - .getShortcuts(activity, taskContainer); + .getShortcuts(container, taskContainer); if (screenshotShortcuts != null) { shortcuts.addAll(screenshotShortcuts); } @@ -96,7 +98,7 @@ public class TaskOverlayFactory implements ResourceBasedOverride { // or in grid-only overview. if (orientedState.getDisplayRotation() == ROTATION_0 || isGridOnlyOverview) { List modalShortcuts = TaskShortcutFactory.MODAL - .getShortcuts(activity, taskContainer); + .getShortcuts(container, taskContainer); if (modalShortcuts != null) { shortcuts.addAll(modalShortcuts); } @@ -136,6 +138,7 @@ public class TaskOverlayFactory implements ResourceBasedOverride { TaskShortcutFactory.PIN, TaskShortcutFactory.INSTALL, TaskShortcutFactory.FREE_FORM, + DesktopSystemShortcut.Companion.createFactory(), TaskShortcutFactory.WELLBEING, TaskShortcutFactory.SAVE_APP_PAIR }; @@ -253,9 +256,9 @@ public class TaskOverlayFactory implements ResourceBasedOverride { /** * Gets the system shortcut for the screenshot that will be added to the task menu. */ - public SystemShortcut getScreenshotShortcut(BaseDraggingActivity activity, + public SystemShortcut getScreenshotShortcut(RecentsViewContainer container, ItemInfo iteminfo, View originalView) { - return new ScreenshotSystemShortcut(activity, iteminfo, originalView); + return new ScreenshotSystemShortcut(container, iteminfo, originalView); } /** @@ -303,19 +306,19 @@ public class TaskOverlayFactory implements ResourceBasedOverride { private class ScreenshotSystemShortcut extends SystemShortcut { - private final BaseDraggingActivity mActivity; + private final RecentsViewContainer mContainer; - ScreenshotSystemShortcut(BaseDraggingActivity activity, ItemInfo itemInfo, + ScreenshotSystemShortcut(RecentsViewContainer container, ItemInfo itemInfo, View originalView) { - super(R.drawable.ic_screenshot, R.string.action_screenshot, activity, itemInfo, + super(R.drawable.ic_screenshot, R.string.action_screenshot, container, itemInfo, originalView); - mActivity = activity; + mContainer = container; } @Override public void onClick(View view) { saveScreenshot(mThumbnailView.getTaskView().getTask()); - dismissTaskMenuView(mActivity); + dismissTaskMenuView(); } } diff --git a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java index 147a3e2408..9d10ac146c 100644 --- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java +++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java @@ -22,7 +22,6 @@ import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_FREE_FORM_TAP; import static com.android.window.flags.Flags.enableDesktopWindowingMode; -import android.app.Activity; import android.app.ActivityOptions; import android.graphics.Bitmap; import android.graphics.Color; @@ -39,7 +38,6 @@ import android.window.SplashScreen; import androidx.annotation.Nullable; -import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; import com.android.launcher3.config.FeatureFlags; @@ -50,9 +48,11 @@ import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.popup.SystemShortcut.AppInfo; import com.android.launcher3.util.InstantAppResolver; import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption; +import com.android.launcher3.views.ActivityContext; import com.android.quickstep.orientation.RecentsPagedOrientationHandler; import com.android.quickstep.views.GroupedTaskView; import com.android.quickstep.views.RecentsView; +import com.android.quickstep.views.RecentsViewContainer; import com.android.quickstep.views.TaskThumbnailView; import com.android.quickstep.views.TaskView; import com.android.quickstep.views.TaskView.TaskIdAttributeContainer; @@ -74,7 +74,7 @@ import java.util.stream.Collectors; */ public interface TaskShortcutFactory { @Nullable - default List getShortcuts(BaseDraggingActivity activity, + default List getShortcuts(RecentsViewContainer container, TaskIdAttributeContainer taskContainer) { return null; } @@ -94,7 +94,7 @@ public interface TaskShortcutFactory { TaskShortcutFactory APP_INFO = new TaskShortcutFactory() { @Override - public List getShortcuts(BaseDraggingActivity activity, + public List getShortcuts(RecentsViewContainer container, TaskIdAttributeContainer taskContainer) { TaskView taskView = taskContainer.getTaskView(); AppInfo.SplitAccessibilityInfo accessibilityInfo = @@ -102,7 +102,7 @@ public interface TaskShortcutFactory { TaskUtils.getTitle(taskView.getContext(), taskContainer.getTask()), taskContainer.getA11yNodeId() ); - return Collections.singletonList(new AppInfo(activity, taskContainer.getItemInfo(), + return Collections.singletonList(new AppInfo(container, taskContainer.getItemInfo(), taskView, accessibilityInfo)); } @@ -116,9 +116,9 @@ public interface TaskShortcutFactory { private final TaskView mTaskView; private final SplitPositionOption mSplitPositionOption; - public SplitSelectSystemShortcut(BaseDraggingActivity target, TaskView taskView, + public SplitSelectSystemShortcut(RecentsViewContainer container, TaskView taskView, SplitPositionOption option) { - super(option.iconResId, option.textResId, target, taskView.getItemInfo(), taskView); + super(option.iconResId, option.textResId, container, taskView.getItemInfo(), taskView); mTaskView = taskView; mSplitPositionOption = option; } @@ -133,25 +133,26 @@ public interface TaskShortcutFactory { * A menu item, "Save app pair", that allows the user to preserve the current app combination as * one persistent icon on the Home screen, allowing for quick split screen launching. */ - class SaveAppPairSystemShortcut extends SystemShortcut { + class SaveAppPairSystemShortcut extends SystemShortcut { private final GroupedTaskView mTaskView; - public SaveAppPairSystemShortcut(BaseDraggingActivity activity, GroupedTaskView taskView, - int iconResId) { - super(iconResId, R.string.save_app_pair, activity, + + public SaveAppPairSystemShortcut(RecentsViewContainer container, GroupedTaskView taskView, + int iconResId) { + super(iconResId, R.string.save_app_pair, container, taskView.getItemInfo(), taskView); mTaskView = taskView; } @Override public void onClick(View view) { - dismissTaskMenuView(mTarget); + dismissTaskMenuView(); ((RecentsView) mTarget.getOverviewPanel()) .getSplitSelectController().getAppPairsController().saveAppPair(mTaskView); } } - class FreeformSystemShortcut extends SystemShortcut { + class FreeformSystemShortcut extends SystemShortcut { private static final String TAG = "FreeformSystemShortcut"; private Handler mHandler; @@ -161,20 +162,20 @@ public interface TaskShortcutFactory { private final TaskView mTaskView; private final LauncherEvent mLauncherEvent; - public FreeformSystemShortcut(int iconRes, int textRes, BaseDraggingActivity activity, + public FreeformSystemShortcut(int iconRes, int textRes, RecentsViewContainer container, TaskIdAttributeContainer taskContainer, LauncherEvent launcherEvent) { - super(iconRes, textRes, activity, taskContainer.getItemInfo(), + super(iconRes, textRes, container, taskContainer.getItemInfo(), taskContainer.getTaskView()); mLauncherEvent = launcherEvent; mHandler = new Handler(Looper.getMainLooper()); mTaskView = taskContainer.getTaskView(); - mRecentsView = activity.getOverviewPanel(); + mRecentsView = container.getOverviewPanel(); mThumbnailView = taskContainer.getThumbnailView(); } @Override public void onClick(View view) { - dismissTaskMenuView(mTarget); + dismissTaskMenuView(); RecentsView rv = mTarget.getOverviewPanel(); rv.switchToScreenshot(() -> { rv.finishRecentsAnimation(true /* toRecents */, false /* shouldPip */, () -> { @@ -252,11 +253,11 @@ public interface TaskShortcutFactory { } } - private ActivityOptions makeLaunchOptions(Activity activity) { + private ActivityOptions makeLaunchOptions(RecentsViewContainer container) { ActivityOptions activityOptions = ActivityOptions.makeBasic(); activityOptions.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM); // Arbitrary bounds only because freeform is in dev mode right now - final View decorView = activity.getWindow().getDecorView(); + final View decorView = container.getWindow().getDecorView(); final WindowInsets insets = decorView.getRootWindowInsets(); final Rect r = new Rect(0, 0, decorView.getWidth() / 2, decorView.getHeight() / 2); r.offsetTo(insets.getSystemWindowInsetLeft() + 50, @@ -277,9 +278,9 @@ public interface TaskShortcutFactory { */ TaskShortcutFactory SPLIT_SELECT = new TaskShortcutFactory() { @Override - public List getShortcuts(BaseDraggingActivity activity, + public List getShortcuts(RecentsViewContainer container, TaskIdAttributeContainer taskContainer) { - DeviceProfile deviceProfile = activity.getDeviceProfile(); + DeviceProfile deviceProfile = container.getDeviceProfile(); final Task task = taskContainer.getTask(); final int intentFlags = task.key.baseIntent.getFlags(); final TaskView taskView = taskContainer.getTaskView(); @@ -291,7 +292,7 @@ public interface TaskShortcutFactory { !deviceProfile.isTaskbarPresent && recentsView.getTaskViewCount() < 2; boolean isTaskSplitNotSupported = !task.isDockable || (intentFlags & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0; - boolean hideForExistingMultiWindow = activity.getDeviceProfile().isMultiWindowMode; + boolean hideForExistingMultiWindow = container.getDeviceProfile().isMultiWindowMode; boolean isFocusedTask = deviceProfile.isTablet && taskView.isFocusedTask(); boolean isTaskInExpectedScrollPosition = recentsView.isTaskInExpectedScrollPosition(recentsView.indexOfChild(taskView)); @@ -304,7 +305,7 @@ public interface TaskShortcutFactory { return orientationHandler.getSplitPositionOptions(deviceProfile) .stream() .map((Function) option -> - new SplitSelectSystemShortcut(activity, taskView, option)) + new SplitSelectSystemShortcut(container, taskView, option)) .collect(Collectors.toList()); } }; @@ -312,9 +313,9 @@ public interface TaskShortcutFactory { TaskShortcutFactory SAVE_APP_PAIR = new TaskShortcutFactory() { @Nullable @Override - public List getShortcuts(BaseDraggingActivity activity, + public List getShortcuts(RecentsViewContainer container, TaskIdAttributeContainer taskContainer) { - DeviceProfile deviceProfile = activity.getDeviceProfile(); + DeviceProfile deviceProfile = container.getDeviceProfile(); final TaskView taskView = taskContainer.getTaskView(); final RecentsView recentsView = taskView.getRecentsView(); boolean isLargeTileFocusedTask = deviceProfile.isTablet && taskView.isFocusedTask(); @@ -348,7 +349,8 @@ public interface TaskShortcutFactory { : R.drawable.ic_save_app_pair_up_down; return Collections.singletonList( - new SaveAppPairSystemShortcut(activity, (GroupedTaskView) taskView, iconResId)); + new SaveAppPairSystemShortcut(container, + (GroupedTaskView) taskView, iconResId)); } @Override @@ -359,25 +361,25 @@ public interface TaskShortcutFactory { TaskShortcutFactory FREE_FORM = new TaskShortcutFactory() { @Override - public List getShortcuts(BaseDraggingActivity activity, + public List getShortcuts(RecentsViewContainer container, TaskIdAttributeContainer taskContainer) { final Task task = taskContainer.getTask(); if (!task.isDockable) { return null; } - if (!isAvailable(activity, task.key.displayId)) { + if (!isAvailable(container)) { return null; } return Collections.singletonList(new FreeformSystemShortcut( R.drawable.ic_caption_desktop_button_foreground, - R.string.recent_task_option_freeform, activity, taskContainer, + R.string.recent_task_option_freeform, container, taskContainer, LAUNCHER_SYSTEM_SHORTCUT_FREE_FORM_TAP)); } - private boolean isAvailable(BaseDraggingActivity activity, int displayId) { + private boolean isAvailable(RecentsViewContainer container) { return Settings.Global.getInt( - activity.getContentResolver(), + container.asContext().getContentResolver(), Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0 && !enableDesktopWindowingMode(); } @@ -385,9 +387,9 @@ public interface TaskShortcutFactory { TaskShortcutFactory PIN = new TaskShortcutFactory() { @Override - public List getShortcuts(BaseDraggingActivity activity, + public List getShortcuts(RecentsViewContainer container, TaskIdAttributeContainer taskContainer) { - if (!SystemUiProxy.INSTANCE.get(activity).isActive()) { + if (!SystemUiProxy.INSTANCE.get(container.asContext()).isActive()) { return null; } if (!ActivityManagerWrapper.getInstance().isScreenPinningEnabled()) { @@ -397,17 +399,17 @@ public interface TaskShortcutFactory { // We shouldn't be able to pin while an app is locked. return null; } - return Collections.singletonList(new PinSystemShortcut(activity, taskContainer)); + return Collections.singletonList(new PinSystemShortcut(container, taskContainer)); } }; - class PinSystemShortcut extends SystemShortcut { + class PinSystemShortcut extends SystemShortcut { private static final String TAG = "PinSystemShortcut"; private final TaskView mTaskView; - public PinSystemShortcut(BaseDraggingActivity target, + public PinSystemShortcut(RecentsViewContainer target, TaskIdAttributeContainer taskContainer) { super(R.drawable.ic_pin, R.string.recent_task_option_pin, target, taskContainer.getItemInfo(), taskContainer.getTaskView()); @@ -417,10 +419,10 @@ public interface TaskShortcutFactory { @Override public void onClick(View view) { if (mTaskView.launchTaskAnimated() != null) { - SystemUiProxy.INSTANCE.get(mTarget).startScreenPinning( + SystemUiProxy.INSTANCE.get(mTarget.asContext()).startScreenPinning( mTaskView.getTask().key.id); } - dismissTaskMenuView(mTarget); + dismissTaskMenuView(); mTarget.getStatsLogManager().logger().withItemInfo(mTaskView.getItemInfo()) .log(LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_PIN_TAP); } @@ -428,12 +430,12 @@ public interface TaskShortcutFactory { TaskShortcutFactory INSTALL = new TaskShortcutFactory() { @Override - public List getShortcuts(BaseDraggingActivity activity, + public List getShortcuts(RecentsViewContainer container, TaskIdAttributeContainer taskContainer) { Task t = taskContainer.getTask(); - return InstantAppResolver.newInstance(activity).isInstantApp( + return InstantAppResolver.newInstance(container.asContext()).isInstantApp( t.getTopComponent().getPackageName(), t.getKey().userId) - ? Collections.singletonList(new SystemShortcut.Install(activity, + ? Collections.singletonList(new SystemShortcut.Install(container, taskContainer.getItemInfo(), taskContainer.getTaskView())) : null; } @@ -441,10 +443,10 @@ public interface TaskShortcutFactory { TaskShortcutFactory WELLBEING = new TaskShortcutFactory() { @Override - public List getShortcuts(BaseDraggingActivity activity, + public List getShortcuts(RecentsViewContainer container, TaskIdAttributeContainer taskContainer) { - SystemShortcut wellbeingShortcut = - WellbeingModel.SHORTCUT_FACTORY.getShortcut(activity, + SystemShortcut wellbeingShortcut = + WellbeingModel.SHORTCUT_FACTORY.getShortcut(container, taskContainer.getItemInfo(), taskContainer.getTaskView()); return createSingletonShortcutList(wellbeingShortcut); } @@ -452,11 +454,11 @@ public interface TaskShortcutFactory { TaskShortcutFactory SCREENSHOT = new TaskShortcutFactory() { @Override - public List getShortcuts(BaseDraggingActivity activity, + public List getShortcuts(RecentsViewContainer container, TaskIdAttributeContainer taskContainer) { SystemShortcut screenshotShortcut = taskContainer.getThumbnailView().getTaskOverlay() - .getScreenshotShortcut(activity, taskContainer.getItemInfo(), + .getScreenshotShortcut(container, taskContainer.getItemInfo(), taskContainer.getTaskView()); return createSingletonShortcutList(screenshotShortcut); } @@ -464,7 +466,7 @@ public interface TaskShortcutFactory { TaskShortcutFactory MODAL = new TaskShortcutFactory() { @Override - public List getShortcuts(BaseDraggingActivity activity, + public List getShortcuts(RecentsViewContainer container, TaskIdAttributeContainer taskContainer) { SystemShortcut modalStateSystemShortcut = taskContainer.getThumbnailView().getTaskOverlay() diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java index f2ee3f1483..5564b1873d 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -120,6 +120,7 @@ import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.ActiveGestureLog.CompoundString; import com.android.quickstep.util.AssistStateManager; import com.android.quickstep.util.AssistUtils; +import com.android.quickstep.views.RecentsViewContainer; import com.android.systemui.shared.recents.IOverviewProxy; import com.android.systemui.shared.recents.ISystemUiProxy; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -317,7 +318,7 @@ public class TouchInteractionService extends Service { public void enterStageSplitFromRunningApp(boolean leftOrTop) { executeForTouchInteractionService(tis -> { StatefulActivity activity = - tis.mOverviewComponentObserver.getActivityInterface().getCreatedActivity(); + tis.mOverviewComponentObserver.getActivityInterface().getCreatedContainer(); if (activity != null) { activity.enterStageSplitFromRunningApp(leftOrTop); } @@ -594,7 +595,7 @@ public class TouchInteractionService extends Service { mAllAppsActionManager.setHomeAndOverviewSame(isHomeAndOverviewSame); StatefulActivity newOverviewActivity = mOverviewComponentObserver.getActivityInterface() - .getCreatedActivity(); + .getCreatedContainer(); if (newOverviewActivity != null) { mTaskbarManager.setActivity(newOverviewActivity); } @@ -602,23 +603,21 @@ public class TouchInteractionService extends Service { } private PendingIntent createAllAppsPendingIntent() { - final Intent homeIntent = new Intent(mOverviewComponentObserver.getHomeIntent()) - .setAction(INTENT_ACTION_ALL_APPS_TOGGLE); - if (FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) { return new PendingIntent(new IIntentSender.Stub() { @Override public void send(int code, Intent intent, String resolvedType, IBinder allowlistToken, IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) { - MAIN_EXECUTOR.execute(() -> mTaskbarManager.toggleAllApps(homeIntent)); + MAIN_EXECUTOR.execute(() -> mTaskbarManager.toggleAllApps()); } }); } else { return PendingIntent.getActivity( this, GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS, - homeIntent, + new Intent(mOverviewComponentObserver.getHomeIntent()) + .setAction(INTENT_ACTION_ALL_APPS_TOGGLE), PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); } } @@ -830,8 +829,8 @@ public class TouchInteractionService extends Service { } } - boolean cancelGesture = mGestureState.getActivityInterface() != null - && mGestureState.getActivityInterface().shouldCancelCurrentGesture(); + boolean cancelGesture = mGestureState.getContainerInterface() != null + && mGestureState.getContainerInterface().shouldCancelCurrentGesture(); boolean cleanUpConsumer = (action == ACTION_UP || action == ACTION_CANCEL || cancelGesture) && mConsumer != null && !mConsumer.getActiveConsumerInHierarchy().isConsumerDetachedFromGesture(); @@ -1148,7 +1147,7 @@ public class TouchInteractionService extends Service { TopTaskTracker.CachedTaskInfo runningTask = gestureState.getRunningTask(); // Use overview input consumer for sharesheets on top of home. - boolean forceOverviewInputConsumer = gestureState.getActivityInterface().isStarted() + boolean forceOverviewInputConsumer = gestureState.getContainerInterface().isStarted() && runningTask != null && runningTask.isRootChooseActivity(); @@ -1172,7 +1171,7 @@ public class TouchInteractionService extends Service { // with shell-transitions, home is resumed during recents animation, so // explicitly check against recents animation too. boolean launcherResumedThroughShellTransition = - gestureState.getActivityInterface().isResumed() + gestureState.getContainerInterface().isResumed() && !previousGestureState.isRecentsAnimationRunning(); // If a task fragment within Launcher is resumed boolean launcherChildActivityResumed = useActivityOverlay() @@ -1182,7 +1181,7 @@ public class TouchInteractionService extends Service { && !launcherResumedThroughShellTransition && !previousGestureState.isRecentsAnimationRunning(); - if (gestureState.getActivityInterface().isInLiveTileMode()) { + if (gestureState.getContainerInterface().isInLiveTileMode()) { return createOverviewInputConsumer( previousGestureState, gestureState, @@ -1230,7 +1229,7 @@ public class TouchInteractionService extends Service { final AbsSwipeUpHandler.Factory factory = getSwipeUpHandlerFactory(); final boolean shouldDefer = !mOverviewComponentObserver.isHomeAndOverviewSame() - || gestureState.getActivityInterface().deferStartingActivity(mDeviceState, event); + || gestureState.getContainerInterface().deferStartingActivity(mDeviceState, event); final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event); return new OtherActivityInputConsumer(this, mDeviceState, mTaskAnimationManager, gestureState, shouldDefer, this::onConsumerInactive, @@ -1264,18 +1263,19 @@ public class TouchInteractionService extends Service { MotionEvent event, boolean forceOverviewInputConsumer, CompoundString reasonString) { - StatefulActivity activity = gestureState.getActivityInterface().getCreatedActivity(); - if (activity == null) { + RecentsViewContainer container = gestureState.getContainerInterface().getCreatedContainer(); + if (container == null) { return getDefaultInputConsumer( reasonString.append(SUBSTRING_PREFIX) .append("activity == null, trying to use default input consumer")); } - boolean hasWindowFocus = activity.getRootView().hasWindowFocus(); + boolean hasWindowFocus = container.getRootView().hasWindowFocus(); boolean isPreviousGestureAnimatingToLauncher = previousGestureState.isRunningAnimationToLauncher() || mDeviceState.isPredictiveBackToHomeInProgress(); - boolean isInLiveTileMode = gestureState.getActivityInterface().isInLiveTileMode(); + boolean isInLiveTileMode = gestureState.getContainerInterface().isInLiveTileMode(); + reasonString.append(SUBSTRING_PREFIX) .append(hasWindowFocus ? "activity has window focus" @@ -1289,14 +1289,14 @@ public class TouchInteractionService extends Service { || isInLiveTileMode) { reasonString.append(SUBSTRING_PREFIX) .append("overview should have focus, using OverviewInputConsumer"); - return new OverviewInputConsumer(gestureState, activity, mInputMonitorCompat, + return new OverviewInputConsumer(gestureState, container, mInputMonitorCompat, false /* startingInActivityBounds */); } else { reasonString.append(SUBSTRING_PREFIX).append( "overview shouldn't have focus, using OverviewWithoutFocusInputConsumer"); final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event); - return new OverviewWithoutFocusInputConsumer(activity, mDeviceState, gestureState, - mInputMonitorCompat, disableHorizontalSwipe); + return new OverviewWithoutFocusInputConsumer(container.asContext(), mDeviceState, + gestureState, mInputMonitorCompat, disableHorizontalSwipe); } } @@ -1369,7 +1369,7 @@ public class TouchInteractionService extends Service { mOverviewComponentObserver.getActivityInterface(); final Intent overviewIntent = new Intent( mOverviewComponentObserver.getOverviewIntentIgnoreSysUiState()); - if (activityInterface.getCreatedActivity() != null && fromInit) { + if (activityInterface.getCreatedContainer() != null && fromInit) { // The activity has been created before the initialization of overview service. It is // usually happens when booting or launcher is the top activity, so we should already // have the latest state. @@ -1391,7 +1391,7 @@ public class TouchInteractionService extends Service { } final BaseActivityInterface activityInterface = mOverviewComponentObserver.getActivityInterface(); - final BaseDraggingActivity activity = activityInterface.getCreatedActivity(); + final BaseDraggingActivity activity = activityInterface.getCreatedContainer(); if (activity == null || activity.isStarted()) { // We only care about the existing background activity. return; @@ -1441,7 +1441,7 @@ public class TouchInteractionService extends Service { DisplayController.INSTANCE.get(this).dump(pw); pw.println("TouchState:"); BaseDraggingActivity createdOverviewActivity = mOverviewComponentObserver == null ? null - : mOverviewComponentObserver.getActivityInterface().getCreatedActivity(); + : mOverviewComponentObserver.getActivityInterface().getCreatedContainer(); boolean resumed = mOverviewComponentObserver != null && mOverviewComponentObserver.getActivityInterface().isResumed(); pw.println(" createdOverviewActivity=" + createdOverviewActivity); diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java b/quickstep/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java index 69de3b0f98..ec531d8028 100644 --- a/quickstep/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java +++ b/quickstep/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java @@ -24,9 +24,9 @@ import com.android.launcher3.Utilities; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.NavigationMode; import com.android.launcher3.util.TouchController; -import com.android.quickstep.RecentsActivity; import com.android.quickstep.util.NavBarPosition; import com.android.quickstep.util.TriggerSwipeUpTouchTracker; +import com.android.quickstep.views.RecentsViewContainer; /** * In 0-button mode, intercepts swipe up from the nav bar on FallbackRecentsView to go home. @@ -34,17 +34,18 @@ import com.android.quickstep.util.TriggerSwipeUpTouchTracker; public class FallbackNavBarTouchController implements TouchController, TriggerSwipeUpTouchTracker.OnSwipeUpListener { - private final RecentsActivity mActivity; + private final RecentsViewContainer mContainer; @Nullable private final TriggerSwipeUpTouchTracker mTriggerSwipeUpTracker; - public FallbackNavBarTouchController(RecentsActivity activity) { - mActivity = activity; - NavigationMode sysUINavigationMode = DisplayController.getNavigationMode(mActivity); + public FallbackNavBarTouchController(RecentsViewContainer container) { + mContainer = container; + NavigationMode sysUINavigationMode = + DisplayController.getNavigationMode(mContainer.asContext()); if (sysUINavigationMode == NavigationMode.NO_BUTTON) { NavBarPosition navBarPosition = new NavBarPosition(sysUINavigationMode, - DisplayController.INSTANCE.get(mActivity).getInfo()); - mTriggerSwipeUpTracker = new TriggerSwipeUpTouchTracker(mActivity, + DisplayController.INSTANCE.get(mContainer.asContext()).getInfo()); + mTriggerSwipeUpTracker = new TriggerSwipeUpTouchTracker(mContainer.asContext(), true /* disableHorizontalSwipe */, navBarPosition, this); } else { mTriggerSwipeUpTracker = null; @@ -75,6 +76,6 @@ public class FallbackNavBarTouchController implements TouchController, @Override public void onSwipeUp(boolean wasFling, PointF finalVelocity) { - mActivity.getOverviewPanel().startHome(); + mContainer.getOverviewPanel().startHome(); } } diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java index 69eaf6afd8..2e76356b5d 100644 --- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java +++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java @@ -49,7 +49,9 @@ import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.util.MultiPropertyFactory; import com.android.quickstep.RecentsActivity; import com.android.quickstep.views.ClearAllButton; +import com.android.quickstep.views.OverviewActionsView; import com.android.quickstep.views.RecentsView; +import com.android.quickstep.views.RecentsViewContainer; /** * State controller for fallback recents activity diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java index 32d8be988c..d881a1f735 100644 --- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java +++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java @@ -36,6 +36,7 @@ import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.desktop.DesktopRecentsTransitionController; import com.android.launcher3.logging.StatsLogManager; +import com.android.launcher3.statemanager.StateManager; import com.android.launcher3.statemanager.StateManager.StateListener; import com.android.launcher3.util.SplitConfigurationOptions; import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource; @@ -67,7 +68,7 @@ public class FallbackRecentsView extends RecentsView getStateManager() { + return mContainer.getStateManager(); } /** @@ -210,10 +216,10 @@ public class FallbackRecentsView extends RecentsView { /** * For this state, what color scrim should be drawn behind overview. */ - public int getScrimColor(RecentsActivity activity) { - return hasFlag(FLAG_SCRIM) ? Themes.getAttrColor(activity, R.attr.overviewScrimColor) + public int getScrimColor(Context context) { + return hasFlag(FLAG_SCRIM) + ? Themes.getAttrColor(context, R.attr.overviewScrimColor) : Color.TRANSPARENT; } - public float[] getOverviewScaleAndOffset(RecentsActivity activity) { + public float[] getOverviewScaleAndOffset(RecentsViewContainer container) { return new float[] { NO_SCALE, NO_OFFSET }; } @@ -161,8 +163,8 @@ public class RecentsState implements BaseState { } @Override - public float[] getOverviewScaleAndOffset(RecentsActivity activity) { - return getOverviewScaleAndOffsetForModalState(activity); + public float[] getOverviewScaleAndOffset(RecentsViewContainer container) { + return getOverviewScaleAndOffsetForModalState(container.getOverviewPanel()); } } @@ -172,8 +174,8 @@ public class RecentsState implements BaseState { } @Override - public float[] getOverviewScaleAndOffset(RecentsActivity activity) { - return getOverviewScaleAndOffsetForBackgroundState(activity); + public float[] getOverviewScaleAndOffset(RecentsViewContainer container) { + return getOverviewScaleAndOffsetForBackgroundState(container.getOverviewPanel()); } } @@ -183,7 +185,7 @@ public class RecentsState implements BaseState { } @Override - public float[] getOverviewScaleAndOffset(RecentsActivity activity) { + public float[] getOverviewScaleAndOffset(RecentsViewContainer container) { return new float[] { NO_SCALE, 1 }; } } diff --git a/quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java b/quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java index db4927a0d1..2cb398cfff 100644 --- a/quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java +++ b/quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java @@ -26,7 +26,7 @@ public class RecentsTaskController extends TaskViewTouchController { if (!MAIN_EXECUTOR.getHandler().hasCallbacks(mTriggerLongPress)) { break; } - float touchSlopSquared = mTouchSlopSquared; float dx = ev.getX() - mCurrentDownEvent.getX(); float dy = ev.getY() - mCurrentDownEvent.getY(); double distanceSquared = (dx * dx) + (dy * dy); - if (distanceSquared > touchSlopSquared) { + if (DEBUG_NAV_HANDLE) { + Log.d(TAG, "ACTION_MOVE distanceSquared=" + distanceSquared); + } + if (DeviceConfigWrapper.get().getEnableLpnhTwoStages()) { + if (mTouchSlopSquared < distanceSquared + && distanceSquared <= mOuterTouchSlopSquared) { + MAIN_EXECUTOR.getHandler().removeCallbacks(mTriggerLongPress); + int delay = mOuterLongPressTimeout + - (int) (ev.getEventTime() - ev.getDownTime()); + MAIN_EXECUTOR.getHandler().postDelayed(mTriggerLongPress, delay); + mTouchSlopSquared = mOuterTouchSlopSquared; + if (DEBUG_NAV_HANDLE) { + Log.d(TAG, "Touch in middle region!"); + } + } + } + if (distanceSquared > mTouchSlopSquared) { + if (DEBUG_NAV_HANDLE) { + Log.d(TAG, "Touch slop out. mTouchSlopSquared=" + mTouchSlopSquared); + } cancelLongPress("touch slop passed"); } } @@ -153,6 +191,9 @@ public class NavHandleLongPressInputConsumer extends DelegateInputConsumer { } private void triggerLongPress() { + if (DEBUG_NAV_HANDLE) { + Log.d(TAG, "triggerLongPress"); + } String runningPackage = mTopTaskTracker.getCachedTopTask( /* filterOnlyVisibleRecents */ true).getPackageName(); mStatsLogManager.logger().withPackageName(runningPackage).log( @@ -175,6 +216,9 @@ public class NavHandleLongPressInputConsumer extends DelegateInputConsumer { } private void cancelLongPress(String reason) { + if (DEBUG_NAV_HANDLE) { + Log.d(TAG, "cancelLongPress"); + } MAIN_EXECUTOR.getHandler().removeCallbacks(mTriggerLongPress); mNavHandleLongPressHandler.onTouchFinished(mNavHandle, reason); } diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java index fbbfc16881..9f39476c2c 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java @@ -49,7 +49,6 @@ import com.android.launcher3.util.Preconditions; import com.android.launcher3.util.TraceHelper; import com.android.quickstep.AbsSwipeUpHandler; import com.android.quickstep.AbsSwipeUpHandler.Factory; -import com.android.quickstep.BaseActivityInterface; import com.android.quickstep.GestureState; import com.android.quickstep.InputConsumer; import com.android.quickstep.RecentsAnimationCallbacks; @@ -86,8 +85,6 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC private final CachedEventDispatcher mRecentsViewDispatcher = new CachedEventDispatcher(); private final InputMonitorCompat mInputMonitorCompat; private final InputEventReceiver mInputEventReceiver; - private final BaseActivityInterface mActivityInterface; - private final AbsSwipeUpHandler.Factory mHandlerFactory; private final Consumer mOnCompleteCallback; @@ -135,7 +132,6 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC mTaskAnimationManager = taskAnimationManager; mGestureState = gestureState; mHandlerFactory = handlerFactory; - mActivityInterface = mGestureState.getActivityInterface(); mMotionPauseDetector = new MotionPauseDetector(base, false, mNavBarPosition.isLeftEdge() || mNavBarPosition.isRightEdge() diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java index 7d3a860b23..bb8d1d7d33 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java @@ -28,24 +28,24 @@ import androidx.annotation.Nullable; import com.android.launcher3.Utilities; import com.android.launcher3.statemanager.BaseState; -import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.testing.TestLogging; import com.android.launcher3.testing.shared.TestProtocol; import com.android.launcher3.views.BaseDragLayer; -import com.android.quickstep.BaseActivityInterface; +import com.android.quickstep.BaseContainerInterface; import com.android.quickstep.GestureState; import com.android.quickstep.InputConsumer; import com.android.quickstep.TaskUtils; +import com.android.quickstep.views.RecentsViewContainer; import com.android.systemui.shared.system.InputMonitorCompat; /** * Input consumer for handling touch on the recents/Launcher activity. */ -public class OverviewInputConsumer, T extends StatefulActivity> +public class OverviewInputConsumer, T extends RecentsViewContainer> implements InputConsumer { - private final T mActivity; - private final BaseActivityInterface mActivityInterface; + private final T mContainer; + private final BaseContainerInterface mContainerInterface; private final BaseDragLayer mTarget; private final InputMonitorCompat mInputMonitor; @@ -56,14 +56,14 @@ public class OverviewInputConsumer, T extends StatefulAct private boolean mHasSetTouchModeForFirstDPadEvent; private boolean mIsWaitingForAttachToWindow; - public OverviewInputConsumer(GestureState gestureState, T activity, + public OverviewInputConsumer(GestureState gestureState, T container, @Nullable InputMonitorCompat inputMonitor, boolean startingInActivityBounds) { - mActivity = activity; + mContainer = container; mInputMonitor = inputMonitor; mStartingInActivityBounds = startingInActivityBounds; - mActivityInterface = gestureState.getActivityInterface(); + mContainerInterface = gestureState.getContainerInterface(); - mTarget = activity.getDragLayer(); + mTarget = container.getDragLayer(); mTarget.getLocationOnScreen(mLocationOnScreen); } @@ -91,7 +91,7 @@ public class OverviewInputConsumer, T extends StatefulAct if (!mTargetHandledTouch && handled) { mTargetHandledTouch = true; if (!mStartingInActivityBounds) { - mActivityInterface.closeOverlay(); + mContainerInterface.closeOverlay(); TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS); } if (mInputMonitor != null) { @@ -100,13 +100,13 @@ public class OverviewInputConsumer, T extends StatefulAct } } if (mHasSetTouchModeForFirstDPadEvent) { - mActivity.getRootView().clearFocus(); + mContainer.getRootView().clearFocus(); } } @Override public void onHoverEvent(MotionEvent ev) { - mActivity.dispatchGenericMotionEvent(ev); + mContainer.dispatchGenericMotionEvent(ev); } @Override @@ -115,7 +115,8 @@ public class OverviewInputConsumer, T extends StatefulAct case KeyEvent.KEYCODE_VOLUME_DOWN: case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_MUTE: - MediaSessionManager mgr = mActivity.getSystemService(MediaSessionManager.class); + MediaSessionManager mgr = mContainer.asContext() + .getSystemService(MediaSessionManager.class); mgr.dispatchVolumeKeyEventAsSystemService(ev, AudioManager.USE_DEFAULT_STREAM_TYPE); break; @@ -124,7 +125,7 @@ public class OverviewInputConsumer, T extends StatefulAct if (mHasSetTouchModeForFirstDPadEvent) { break; } - View viewRoot = mActivity.getRootView(); + View viewRoot = mContainer.getRootView(); if (viewRoot.isAttachedToWindow()) { setTouchModeChanged(viewRoot); break; @@ -150,7 +151,7 @@ public class OverviewInputConsumer, T extends StatefulAct default: break; } - mActivity.dispatchKeyEvent(ev); + mContainer.dispatchKeyEvent(ev); } private void setTouchModeChanged(@NonNull View viewRoot) { diff --git a/quickstep/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java index a8bf333567..d73c23ff51 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java @@ -19,12 +19,12 @@ import android.content.Context; import android.view.HapticFeedbackConstants; import android.view.MotionEvent; -import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.R; import com.android.quickstep.GestureState; import com.android.quickstep.InputConsumer; import com.android.quickstep.SystemUiProxy; import com.android.quickstep.util.MotionPauseDetector; +import com.android.quickstep.views.RecentsViewContainer; /** * An input consumer that detects swipe up and hold to exit screen pinning mode. @@ -44,10 +44,10 @@ public class ScreenPinnedInputConsumer implements InputConsumer { mMotionPauseDetector = new MotionPauseDetector(context, true /* makePauseHarderToTrigger*/); mMotionPauseDetector.setOnMotionPauseListener(() -> { SystemUiProxy.INSTANCE.get(context).stopScreenPinning(); - BaseDraggingActivity launcherActivity = gestureState.getActivityInterface() - .getCreatedActivity(); - if (launcherActivity != null) { - launcherActivity.getRootView().performHapticFeedback( + RecentsViewContainer container = gestureState.getContainerInterface() + .getCreatedContainer(); + if (container != null) { + container.getRootView().performHapticFeedback( HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); } diff --git a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java index 561e951362..c9647f596e 100644 --- a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java +++ b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java @@ -39,12 +39,12 @@ import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.statemanager.StateManager; -import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.touch.AllAppsSwipeController; import com.android.quickstep.DeviceConfigWrapper; import com.android.quickstep.orientation.RecentsPagedOrientationHandler; import com.android.quickstep.views.RecentsView; +import com.android.quickstep.views.RecentsViewContainer; /** * Controls an animation that can go beyond progress = 1, at which point resistance should be @@ -158,11 +158,12 @@ public class AnimatorControllerWithResistance { PendingAnimation resistAnim = createRecentsResistanceAnim(params); // Apply All Apps animation during the resistance animation. - if (recentsOrientedState.getActivityInterface().allowAllAppsFromOverview()) { - StatefulActivity activity = - recentsOrientedState.getActivityInterface().getCreatedActivity(); - if (activity != null) { - StateManager stateManager = activity.getStateManager(); + if (recentsOrientedState.getContainerInterface().allowAllAppsFromOverview()) { + RecentsViewContainer container = + recentsOrientedState.getContainerInterface().getCreatedContainer(); + if (container != null) { + RecentsView recentsView = container.getOverviewPanel(); + StateManager stateManager = recentsView.getStateManager(); if (stateManager.isInStableState(LauncherState.BACKGROUND_APP) && stateManager.isInTransition()) { @@ -185,7 +186,7 @@ public class AnimatorControllerWithResistance { private static float getAllAppsThreshold(Context context, RecentsOrientedState recentsOrientedState, DeviceProfile dp) { int transitionDragLength = - recentsOrientedState.getActivityInterface().getSwipeUpDestinationAndLength( + recentsOrientedState.getContainerInterface().getSwipeUpDestinationAndLength( dp, context, TEMP_RECT, recentsOrientedState.getOrientationHandler()); float dragLengthFactor = (float) dp.heightPx / transitionDragLength; @@ -203,7 +204,7 @@ public class AnimatorControllerWithResistance { Rect startRect = new Rect(); RecentsPagedOrientationHandler orientationHandler = params.recentsOrientedState .getOrientationHandler(); - params.recentsOrientedState.getActivityInterface() + params.recentsOrientedState.getContainerInterface() .calculateTaskSize(params.context, params.dp, startRect, orientationHandler); long distanceToCover = startRect.bottom; PendingAnimation resistAnim = params.resistAnim != null @@ -303,14 +304,14 @@ public class AnimatorControllerWithResistance { this.translationProperty = translationProperty; if (dp.isTablet) { resistanceParams = - recentsOrientedState.getActivityInterface().allowAllAppsFromOverview() + recentsOrientedState.getContainerInterface().allowAllAppsFromOverview() ? RecentsResistanceParams.FROM_APP_TO_ALL_APPS_TABLET : enableGridOnlyOverview() ? RecentsResistanceParams.FROM_APP_TABLET_GRID_ONLY : RecentsResistanceParams.FROM_APP_TABLET; } else { resistanceParams = - recentsOrientedState.getActivityInterface().allowAllAppsFromOverview() + recentsOrientedState.getContainerInterface().allowAllAppsFromOverview() ? RecentsResistanceParams.FROM_APP_TO_ALL_APPS : RecentsResistanceParams.FROM_APP; } diff --git a/quickstep/src/com/android/quickstep/util/AppPairsController.java b/quickstep/src/com/android/quickstep/util/AppPairsController.java index 3ed3e40ca7..3f0657123f 100644 --- a/quickstep/src/com/android/quickstep/util/AppPairsController.java +++ b/quickstep/src/com/android/quickstep/util/AppPairsController.java @@ -42,7 +42,6 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.internal.jank.Cuj; -import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherSettings; import com.android.launcher3.accessibility.LauncherAccessibilityDelegate; @@ -56,8 +55,10 @@ import com.android.launcher3.model.data.AppPairInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.taskbar.TaskbarActivityContext; +import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.SplitConfigurationOptions.StagePosition; +import com.android.launcher3.views.ActivityContext; import com.android.quickstep.SystemUiProxy; import com.android.quickstep.TopTaskTracker; import com.android.quickstep.views.GroupedTaskView; @@ -159,7 +160,7 @@ public class AppPairsController { }); MAIN_EXECUTOR.execute(() -> { LauncherAccessibilityDelegate delegate = - Launcher.getLauncher(mContext).getAccessibilityDelegate(); + QuickstepLauncher.getLauncher(mContext).getAccessibilityDelegate(); if (delegate != null) { delegate.addToWorkspace(newAppPair, true, (success) -> { if (success) { @@ -238,7 +239,8 @@ public class AppPairsController { return null; } - AllAppsStore appsStore = Launcher.getLauncher(mContext).getAppsView().getAppsStore(); + AllAppsStore appsStore = ActivityContext.lookupContext(mContext) + .getAppsView().getAppsStore(); // Lookup by ComponentKey AppInfo appInfo = appsStore.getApp(key); diff --git a/quickstep/src/com/android/quickstep/util/AssistStateManager.java b/quickstep/src/com/android/quickstep/util/AssistStateManager.java index a1fdbbb127..a3904bc3e6 100644 --- a/quickstep/src/com/android/quickstep/util/AssistStateManager.java +++ b/quickstep/src/com/android/quickstep/util/AssistStateManager.java @@ -52,16 +52,38 @@ public class AssistStateManager implements ResourceBasedOverride { return Optional.empty(); } - /** Get the Launcher overridden long press duration to trigger Assistant. */ + /** Get the Launcher overridden long press nav handle duration to trigger Assistant. */ public Optional getLPNHDurationMillis() { return Optional.empty(); } - /** Get the Launcher overridden long press touch slop multiplier to trigger Assistant. */ - public Optional getLPNHCustomSlopMultiplier() { + /** + * Get the Launcher overridden long press nav handle touch slop multiplier to trigger Assistant. + */ + public Optional getLPNHCustomSlopMultiplier() { return Optional.empty(); } + /** Get the Launcher overridden long press home duration to trigger Assistant. */ + public Optional getLPHDurationMillis() { + return Optional.empty(); + } + + /** Get the Launcher overridden long press home touch slop multiplier to trigger Assistant. */ + public Optional getLPHCustomSlopMultiplier() { + return Optional.empty(); + } + + /** Get the long press duration data source. */ + public int getDurationDataSource() { + return 0; + } + + /** Get the long press touch slop multiplier data source. */ + public int getSlopDataSource() { + return 0; + } + /** Return {@code true} if the Settings toggle is enabled. */ public boolean isSettingsAllEntrypointsEnabled() { return false; diff --git a/quickstep/src/com/android/quickstep/util/InputProxyHandlerFactory.java b/quickstep/src/com/android/quickstep/util/InputProxyHandlerFactory.java index 8209c09304..843619de78 100644 --- a/quickstep/src/com/android/quickstep/util/InputProxyHandlerFactory.java +++ b/quickstep/src/com/android/quickstep/util/InputProxyHandlerFactory.java @@ -17,11 +17,11 @@ package com.android.quickstep.util; import androidx.annotation.UiThread; -import com.android.launcher3.statemanager.StatefulActivity; -import com.android.quickstep.BaseActivityInterface; +import com.android.quickstep.BaseContainerInterface; import com.android.quickstep.GestureState; import com.android.quickstep.InputConsumer; import com.android.quickstep.inputconsumers.OverviewInputConsumer; +import com.android.quickstep.views.RecentsViewContainer; import java.util.function.Supplier; @@ -31,13 +31,13 @@ import java.util.function.Supplier; */ public class InputProxyHandlerFactory implements Supplier { - private final BaseActivityInterface mActivityInterface; + private final BaseContainerInterface mContainerInterface; private final GestureState mGestureState; @UiThread - public InputProxyHandlerFactory(BaseActivityInterface activityInterface, + public InputProxyHandlerFactory(BaseContainerInterface activityInterface, GestureState gestureState) { - mActivityInterface = activityInterface; + mContainerInterface = activityInterface; mGestureState = gestureState; } @@ -46,8 +46,8 @@ public class InputProxyHandlerFactory implements Supplier { */ @Override public InputConsumer get() { - StatefulActivity activity = mActivityInterface.getCreatedActivity(); - return activity == null ? InputConsumer.NO_OP - : new OverviewInputConsumer(mGestureState, activity, null, true); + RecentsViewContainer container = mContainerInterface.getCreatedContainer(); + return container == null ? InputConsumer.NO_OP + : new OverviewInputConsumer(mGestureState, container, null, true); } } diff --git a/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java index 61ba5ace65..4474f3355c 100644 --- a/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java +++ b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java @@ -30,9 +30,9 @@ import androidx.core.view.OneShotPreDrawListener; import com.android.launcher3.DeviceProfile; import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; import com.android.launcher3.Hotseat; -import com.android.launcher3.Launcher; import com.android.launcher3.Workspace; import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.util.HorizontalInsettableView; import com.android.quickstep.SystemUiProxy; import com.android.quickstep.util.unfold.LauncherJankMonitorTransitionProgressListener; @@ -56,7 +56,7 @@ public class LauncherUnfoldAnimationController implements OnDeviceProfileChangeL private static final FloatProperty HOTSEAT_SCALE_PROPERTY = HOTSEAT_SCALE_PROPERTY_FACTORY.get(SCALE_INDEX_UNFOLD_ANIMATION); - private final Launcher mLauncher; + private final QuickstepLauncher mLauncher; private final ScopedUnfoldTransitionProgressProvider mProgressProvider; private final NaturalRotationUnfoldProgressProvider mNaturalOrientationProgressProvider; private final UnfoldMoveFromCenterHotseatAnimator mUnfoldMoveFromCenterHotseatAnimator; @@ -73,7 +73,7 @@ public class LauncherUnfoldAnimationController implements OnDeviceProfileChangeL private HorizontalInsettableView mQsbInsettable; public LauncherUnfoldAnimationController( - Launcher launcher, + QuickstepLauncher launcher, WindowManager windowManager, UnfoldTransitionProgressProvider unfoldTransitionProgressProvider, RotationChangeProvider rotationChangeProvider) { diff --git a/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java b/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java index 1d008da5b3..0b05c2e7c1 100644 --- a/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java +++ b/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java @@ -19,39 +19,40 @@ import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_O import android.animation.Animator; import android.animation.ObjectAnimator; +import android.content.Context; import androidx.dynamicanimation.animation.DynamicAnimation; import com.android.launcher3.anim.SpringAnimationBuilder; import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory; -import com.android.launcher3.statemanager.StatefulActivity; import com.android.quickstep.views.RecentsView; +import com.android.quickstep.views.RecentsViewContainer; -public class RecentsAtomicAnimationFactory - extends AtomicAnimationFactory { +public class RecentsAtomicAnimationFactory extends AtomicAnimationFactory { public static final int INDEX_RECENTS_FADE_ANIM = AtomicAnimationFactory.NEXT_INDEX + 0; public static final int INDEX_RECENTS_TRANSLATE_X_ANIM = AtomicAnimationFactory.NEXT_INDEX + 1; private static final int MY_ANIM_COUNT = 2; - protected final ACTIVITY_TYPE mActivity; + protected final CONTAINER mContainer; - public RecentsAtomicAnimationFactory(ACTIVITY_TYPE activity) { + public RecentsAtomicAnimationFactory(CONTAINER container) { super(MY_ANIM_COUNT); - mActivity = activity; + mContainer = container; } @Override public Animator createStateElementAnimation(int index, float... values) { switch (index) { case INDEX_RECENTS_FADE_ANIM: - ObjectAnimator alpha = ObjectAnimator.ofFloat(mActivity.getOverviewPanel(), + ObjectAnimator alpha = ObjectAnimator.ofFloat(mContainer.getOverviewPanel(), RecentsView.CONTENT_ALPHA, values); return alpha; case INDEX_RECENTS_TRANSLATE_X_ANIM: { - RecentsView rv = mActivity.getOverviewPanel(); - return new SpringAnimationBuilder(mActivity) + RecentsView rv = mContainer.getOverviewPanel(); + return new SpringAnimationBuilder(mContainer) .setMinimumVisibleChange(DynamicAnimation.MIN_VISIBLE_CHANGE_SCALE) .setDampingRatio(0.8f) .setStiffness(250) diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java index cba628b817..9335e7e475 100644 --- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java +++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java @@ -50,7 +50,7 @@ import com.android.launcher3.testing.shared.TestProtocol; import com.android.launcher3.touch.PagedOrientationHandler; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.SettingsCache; -import com.android.quickstep.BaseActivityInterface; +import com.android.quickstep.BaseContainerInterface; import com.android.quickstep.SystemUiProxy; import com.android.quickstep.TaskAnimationManager; import com.android.quickstep.orientation.RecentsPagedOrientationHandler; @@ -118,7 +118,7 @@ public class RecentsOrientedState implements | FLAG_SWIPE_UP_NOT_RUNNING; private final Context mContext; - private final BaseActivityInterface mActivityInterface; + private final BaseContainerInterface mContainerInterface; private final OrientationEventListener mOrientationListener; private final SettingsCache mSettingsCache; private final SettingsCache.OnChangeListener mRotationChangeListener = @@ -138,10 +138,10 @@ public class RecentsOrientedState implements * is enabled * @see #setRotationWatcherEnabled(boolean) */ - public RecentsOrientedState(Context context, BaseActivityInterface activityInterface, + public RecentsOrientedState(Context context, BaseContainerInterface containerInterface, IntConsumer rotationChangeListener) { mContext = context; - mActivityInterface = activityInterface; + mContainerInterface = containerInterface; mOrientationListener = new OrientationEventListener(context) { @Override public void onOrientationChanged(int degrees) { @@ -153,7 +153,7 @@ public class RecentsOrientedState implements } }; - mFlags = mActivityInterface.rotationSupportedByActivity + mFlags = mContainerInterface.rotationSupportedByActivity ? FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_ACTIVITY : 0; mFlags |= FLAG_SWIPE_UP_NOT_RUNNING; @@ -161,8 +161,8 @@ public class RecentsOrientedState implements initFlags(); } - public BaseActivityInterface getActivityInterface() { - return mActivityInterface; + public BaseContainerInterface getContainerInterface() { + return mContainerInterface; } /** diff --git a/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt b/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt index 33736adc82..48c2407e33 100644 --- a/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt +++ b/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt @@ -20,7 +20,6 @@ import android.view.View import com.android.app.animation.Interpolators import com.android.app.animation.Interpolators.EMPHASIZED import com.android.app.animation.Interpolators.LINEAR -import com.android.launcher3.Launcher import com.android.launcher3.LauncherAnimUtils.HOTSEAT_SCALE_PROPERTY_FACTORY import com.android.launcher3.LauncherAnimUtils.SCALE_INDEX_WORKSPACE_STATE import com.android.launcher3.LauncherAnimUtils.WORKSPACE_SCALE_PROPERTY_FACTORY @@ -39,7 +38,7 @@ import com.android.quickstep.views.RecentsView * Creates an animation where the workspace and hotseat fade in while revealing from the center of * the screen outwards radially. This is used in conjunction with the swipe up to home animation. */ -class ScalingWorkspaceRevealAnim(launcher: Launcher) { +class ScalingWorkspaceRevealAnim(launcher: QuickstepLauncher) { companion object { private const val FADE_DURATION_MS = 200L private const val SCALE_DURATION_MS = 1000L diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt index a2d3859135..9e45380d10 100644 --- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt +++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt @@ -41,7 +41,6 @@ import androidx.annotation.VisibleForTesting import com.android.app.animation.Interpolators import com.android.launcher3.DeviceProfile import com.android.launcher3.Flags.enableOverviewIconMenu -import com.android.launcher3.Launcher import com.android.launcher3.QuickstepTransitionManager import com.android.launcher3.Utilities import com.android.launcher3.anim.PendingAnimation @@ -50,8 +49,8 @@ import com.android.launcher3.config.FeatureFlags import com.android.launcher3.logging.StatsLogManager.EventEnum import com.android.launcher3.statehandlers.DepthController import com.android.launcher3.statemanager.StateManager -import com.android.launcher3.statemanager.StatefulActivity import com.android.launcher3.taskbar.TaskbarActivityContext +import com.android.launcher3.uioverrides.QuickstepLauncher import com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource import com.android.launcher3.views.BaseDragLayer @@ -61,6 +60,7 @@ import com.android.quickstep.views.FloatingTaskView import com.android.quickstep.views.GroupedTaskView import com.android.quickstep.views.IconAppChipView import com.android.quickstep.views.RecentsView +import com.android.quickstep.views.RecentsViewContainer import com.android.quickstep.views.SplitInstructionsView import com.android.quickstep.views.TaskThumbnailView import com.android.quickstep.views.TaskView @@ -269,12 +269,12 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC } /** Does not play any animation if user is not currently in split selection state. */ - fun playPlaceholderDismissAnim(launcher: StatefulActivity<*>, splitDismissEvent: EventEnum) { + fun playPlaceholderDismissAnim(container: RecentsViewContainer, splitDismissEvent: EventEnum) { if (!splitSelectStateController.isSplitSelectActive) { return } - val anim = createPlaceholderDismissAnim(launcher, splitDismissEvent, null /*duration*/) + val anim = createPlaceholderDismissAnim(container, splitDismissEvent, null /*duration*/) anim.start() } @@ -283,18 +283,18 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC * for why split is being dismissed */ fun createPlaceholderDismissAnim( - launcher: StatefulActivity<*>, + container: RecentsViewContainer, splitDismissEvent: EventEnum, duration: Long? ): AnimatorSet { val animatorSet = AnimatorSet() duration?.let { animatorSet.duration = it } - val recentsView: RecentsView<*, *> = launcher.getOverviewPanel() + val recentsView: RecentsView<*, *> = container.getOverviewPanel() val floatingTask: FloatingTaskView = splitSelectStateController.firstFloatingTaskView ?: return animatorSet // We are in split selection state currently, transitioning to another state - val dragLayer: BaseDragLayer<*> = launcher.dragLayer + val dragLayer: BaseDragLayer<*> = container.dragLayer val onScreenRectF = RectF() Utilities.getBoundsForViewInDragLayer( dragLayer, @@ -320,7 +320,7 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC floatingTask, onScreenRectF, floatingTask.stagePosition, - launcher.deviceProfile + container.deviceProfile ) ) ) @@ -329,7 +329,7 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC override fun onAnimationEnd(animation: Animator) { splitSelectStateController.resetState() safeRemoveViewFromDragLayer( - launcher, + container, splitSelectStateController.splitInstructionsView ) } @@ -343,11 +343,11 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC * Returns a [PendingAnimation] to animate in the chip to instruct a user to select a second app * for splitscreen */ - fun getShowSplitInstructionsAnim(launcher: StatefulActivity<*>): PendingAnimation { - safeRemoveViewFromDragLayer(launcher, splitSelectStateController.splitInstructionsView) - val splitInstructionsView = SplitInstructionsView.getSplitInstructionsView(launcher) + fun getShowSplitInstructionsAnim(container: RecentsViewContainer): PendingAnimation { + safeRemoveViewFromDragLayer(container, splitSelectStateController.splitInstructionsView) + val splitInstructionsView = SplitInstructionsView.getSplitInstructionsView(container) splitSelectStateController.splitInstructionsView = splitInstructionsView - val timings = AnimUtils.getDeviceOverviewToSplitTimings(launcher.deviceProfile.isTablet) + val timings = AnimUtils.getDeviceOverviewToSplitTimings(container.deviceProfile.isTablet) val anim = PendingAnimation(100 /*duration */) splitInstructionsView.alpha = 0f anim.setViewAlpha( @@ -374,8 +374,8 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC } /** Removes the split instructions view from [launcher] drag layer. */ - fun removeSplitInstructionsView(launcher: StatefulActivity<*>) { - safeRemoveViewFromDragLayer(launcher, splitSelectStateController.splitInstructionsView) + fun removeSplitInstructionsView(container: RecentsViewContainer) { + safeRemoveViewFromDragLayer(container, splitSelectStateController.splitInstructionsView) } /** @@ -384,22 +384,23 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC * TODO(b/276361926): Remove the [resetCallback] option once contextual launches */ fun playAnimPlaceholderToFullscreen( - launcher: StatefulActivity<*>, + container: RecentsViewContainer, view: View, resetCallback: Optional ) { val stagedTaskView = view as FloatingTaskView - val isTablet: Boolean = launcher.deviceProfile.isTablet + val isTablet: Boolean = container.deviceProfile.isTablet val duration = if (isTablet) SplitAnimationTimings.TABLET_CONFIRM_DURATION else SplitAnimationTimings.PHONE_CONFIRM_DURATION + val pendingAnimation = PendingAnimation(duration.toLong()) val firstTaskStartingBounds = Rect() val firstTaskEndingBounds = Rect() stagedTaskView.getBoundsOnScreen(firstTaskStartingBounds) - launcher.dragLayer.getBoundsOnScreen(firstTaskEndingBounds) + container.dragLayer.getBoundsOnScreen(firstTaskEndingBounds) splitSelectStateController.setLaunchingFirstAppFullscreen() stagedTaskView.addConfirmAnimation( @@ -589,7 +590,7 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC } // Else we are in Launcher and can launch with the full icon stretch-and-split animation. - val launcher = Launcher.getLauncher(launchingIconView.context) + val launcher = QuickstepLauncher.getLauncher(launchingIconView.context) val dp = launcher.deviceProfile // Create an AnimatorSet that will run both shell and launcher transitions together @@ -923,9 +924,9 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC animator.start() } - private fun safeRemoveViewFromDragLayer(launcher: StatefulActivity<*>, view: View?) { + private fun safeRemoveViewFromDragLayer(container: RecentsViewContainer, view: View?) { if (view != null) { - launcher.dragLayer.removeView(view) + container.dragLayer.removeView(view) } } } diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java index bff5a259c7..c9aa30d80f 100644 --- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java +++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java @@ -72,7 +72,6 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.internal.logging.InstanceId; -import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.apppairs.AppPairIcon; @@ -82,9 +81,9 @@ import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.statehandlers.DepthController; import com.android.launcher3.statemanager.StateManager; -import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.testing.TestLogging; import com.android.launcher3.testing.shared.TestProtocol; +import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.util.BackPressHandler; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.SplitConfigurationOptions.StagePosition; @@ -100,6 +99,7 @@ import com.android.quickstep.TaskAnimationManager; import com.android.quickstep.views.FloatingTaskView; import com.android.quickstep.views.GroupedTaskView; import com.android.quickstep.views.RecentsView; +import com.android.quickstep.views.RecentsViewContainer; import com.android.quickstep.views.SplitInstructionsView; import com.android.systemui.animation.RemoteAnimationRunnerCompat; import com.android.systemui.shared.recents.model.Task; @@ -121,7 +121,7 @@ import java.util.function.Consumer; public class SplitSelectStateController { private static final String TAG = "SplitSelectStateCtor"; - private StatefulActivity mContext; + private RecentsViewContainer mContainer; private final Handler mHandler; private final RecentsModel mRecentTasksModel; @Nullable @@ -179,7 +179,7 @@ public class SplitSelectStateController { public void onBackInvoked() { // When exiting from split selection, leave current context to go to // homescreen as well - getSplitAnimationController().playPlaceholderDismissAnim(mContext, + getSplitAnimationController().playPlaceholderDismissAnim(mContainer, LAUNCHER_SPLIT_SELECTION_EXIT_HOME); if (mActivityBackCallback != null) { mActivityBackCallback.run(); @@ -187,11 +187,11 @@ public class SplitSelectStateController { } }; - public SplitSelectStateController(StatefulActivity context, Handler handler, + public SplitSelectStateController(RecentsViewContainer container, Handler handler, StateManager stateManager, DepthController depthController, StatsLogManager statsLogManager, SystemUiProxy systemUiProxy, RecentsModel recentsModel, Runnable activityBackCallback) { - mContext = context; + mContainer = container; mHandler = handler; mStatsLogManager = statsLogManager; mSystemUiProxy = systemUiProxy; @@ -200,12 +200,12 @@ public class SplitSelectStateController { mRecentTasksModel = recentsModel; mActivityBackCallback = activityBackCallback; mSplitAnimationController = new SplitAnimationController(this); - mAppPairsController = new AppPairsController(context, this, statsLogManager); - mSplitSelectDataHolder = new SplitSelectDataHolder(mContext); + mAppPairsController = new AppPairsController(mContainer.asContext(), this, statsLogManager); + mSplitSelectDataHolder = new SplitSelectDataHolder(mContainer.asContext()); } public void onDestroy() { - mContext = null; + mContainer = null; mActivityBackCallback = null; mAppPairsController.onDestroy(); mSplitSelectDataHolder.onDestroy(); @@ -646,7 +646,7 @@ public class SplitSelectStateController { } } - public void initSplitFromDesktopController(Launcher launcher) { + public void initSplitFromDesktopController(QuickstepLauncher launcher) { initSplitFromDesktopController(new SplitFromDesktopController(launcher)); } @@ -955,7 +955,7 @@ public class SplitSelectStateController { public class SplitFromDesktopController { private static final String TAG = "SplitFromDesktopController"; - private final Launcher mLauncher; + private final QuickstepLauncher mLauncher; private final OverviewComponentObserver mOverviewComponentObserver; private final int mSplitPlaceholderSize; private final int mSplitPlaceholderInset; @@ -963,7 +963,7 @@ public class SplitSelectStateController { private ISplitSelectListener mSplitSelectListener; private Drawable mAppIcon; - public SplitFromDesktopController(Launcher launcher) { + public SplitFromDesktopController(QuickstepLauncher launcher) { mLauncher = launcher; RecentsAnimationDeviceState deviceState = new RecentsAnimationDeviceState( launcher.getApplicationContext()); diff --git a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java index 16d707bb10..2cd421aac3 100644 --- a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java +++ b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java @@ -35,7 +35,6 @@ import android.view.View; import com.android.internal.jank.Cuj; import com.android.launcher3.DeviceProfile; -import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; import com.android.launcher3.anim.PendingAnimation; @@ -46,6 +45,7 @@ import com.android.launcher3.model.data.AppPairInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.PackageItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; +import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.quickstep.views.FloatingTaskView; import com.android.quickstep.views.RecentsView; import com.android.systemui.shared.system.InteractionJankMonitorWrapper; @@ -53,13 +53,14 @@ import com.android.systemui.shared.system.InteractionJankMonitorWrapper; /** Handles when the stage split lands on the home screen. */ public class SplitToWorkspaceController { - private final Launcher mLauncher; + private final QuickstepLauncher mLauncher; private final SplitSelectStateController mController; private final int mHalfDividerSize; private final IconCache mIconCache; - public SplitToWorkspaceController(Launcher launcher, SplitSelectStateController controller) { + public SplitToWorkspaceController(QuickstepLauncher launcher, + SplitSelectStateController controller) { mLauncher = launcher; mController = controller; mIconCache = LauncherAppState.getInstanceNoCreate().getIconCache(); diff --git a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java index d6d6a119bd..997a842dc2 100644 --- a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java +++ b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java @@ -38,7 +38,6 @@ import androidx.annotation.Nullable; import com.android.launcher3.CellLayout; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Hotseat; -import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.QuickstepTransitionManager; import com.android.launcher3.R; @@ -75,13 +74,13 @@ public class StaggeredWorkspaceAnim { private final AnimatorSet mAnimators = new AnimatorSet(); private final @Nullable View mIgnoredView; - public StaggeredWorkspaceAnim(Launcher launcher, float velocity, boolean animateOverviewScrim, - @Nullable View ignoredView) { + public StaggeredWorkspaceAnim(QuickstepLauncher launcher, float velocity, + boolean animateOverviewScrim, @Nullable View ignoredView) { this(launcher, velocity, animateOverviewScrim, ignoredView, true); } - public StaggeredWorkspaceAnim(Launcher launcher, float velocity, boolean animateOverviewScrim, - @Nullable View ignoredView, boolean staggerWorkspace) { + public StaggeredWorkspaceAnim(QuickstepLauncher launcher, float velocity, + boolean animateOverviewScrim, @Nullable View ignoredView, boolean staggerWorkspace) { prepareToAnimate(launcher, animateOverviewScrim); mIgnoredView = ignoredView; @@ -124,7 +123,8 @@ public class StaggeredWorkspaceAnim { for (int i = hotseatIcons.getChildCount() - 1; i >= 0; i--) { View child = hotseatIcons.getChildAt(i); CellLayoutLayoutParams lp = ((CellLayoutLayoutParams) child.getLayoutParams()); - addStaggeredAnimationForView(child, lp.getCellY() + 1, totalRows, duration); + addStaggeredAnimationForView(child, lp.getCellY() + 1, + totalRows, duration); } } else { final int hotseatRow, qsbRow; @@ -194,7 +194,8 @@ public class StaggeredWorkspaceAnim { for (int i = itemsContainer.getChildCount() - 1; i >= 0; i--) { View child = itemsContainer.getChildAt(i); CellLayoutLayoutParams lp = ((CellLayoutLayoutParams) child.getLayoutParams()); - addStaggeredAnimationForView(child, lp.getCellY() + lp.cellVSpan, totalRows, duration); + addStaggeredAnimationForView(child, lp.getCellY() + lp.cellVSpan, + totalRows, duration); } mAnimators.addListener(new AnimatorListenerAdapter() { @@ -209,7 +210,7 @@ public class StaggeredWorkspaceAnim { /** * Setup workspace with 0 duration to prepare for our staggered animation. */ - private void prepareToAnimate(Launcher launcher, boolean animateOverviewScrim) { + private void prepareToAnimate(QuickstepLauncher launcher, boolean animateOverviewScrim) { StateAnimationConfig config = new StateAnimationConfig(); config.animFlags = SKIP_OVERVIEW | SKIP_DEPTH_CONTROLLER | SKIP_SCRIM; config.duration = 0; @@ -294,12 +295,10 @@ public class StaggeredWorkspaceAnim { mAnimators.play(alpha); } - private void addDepthAnimationForState(Launcher launcher, LauncherState state, long duration) { - if (!(launcher instanceof QuickstepLauncher)) { - return; - } + private void addDepthAnimationForState(QuickstepLauncher launcher, LauncherState state, + long duration) { PendingAnimation builder = new PendingAnimation(duration); - DepthController depthController = ((QuickstepLauncher) launcher).getDepthController(); + DepthController depthController = launcher.getDepthController(); depthController.setStateWithAnimation(state, new StateAnimationConfig(), builder); mAnimators.play(builder.buildAnim()); } diff --git a/quickstep/src/com/android/quickstep/util/TaskRemovedDuringLaunchListener.java b/quickstep/src/com/android/quickstep/util/TaskRemovedDuringLaunchListener.java index cdadd711a8..89d8cc48ce 100644 --- a/quickstep/src/com/android/quickstep/util/TaskRemovedDuringLaunchListener.java +++ b/quickstep/src/com/android/quickstep/util/TaskRemovedDuringLaunchListener.java @@ -24,8 +24,8 @@ import static com.android.launcher3.BaseActivity.EVENT_STOPPED; import androidx.annotation.NonNull; -import com.android.launcher3.BaseActivity; import com.android.quickstep.RecentsModel; +import com.android.quickstep.views.RecentsViewContainer; /** * This class tracks the failure of a task launch through the TaskView.launchTask() call, in an @@ -38,7 +38,7 @@ import com.android.quickstep.RecentsModel; */ public class TaskRemovedDuringLaunchListener { - private BaseActivity mActivity; + private RecentsViewContainer mContainer; private int mLaunchedTaskId = INVALID_TASK_ID; private Runnable mTaskLaunchFailedCallback = null; @@ -49,16 +49,16 @@ public class TaskRemovedDuringLaunchListener { * Registers a failure listener callback if it detects a scenario in which an app launch * failed before the transition finished. */ - public void register(BaseActivity activity, int launchedTaskId, + public void register(RecentsViewContainer container, int launchedTaskId, @NonNull Runnable taskLaunchFailedCallback) { // The normal task launch case, Launcher stops and updates its state correctly - activity.addEventCallback(EVENT_STOPPED, mUnregisterCallback); + container.addEventCallback(EVENT_STOPPED, mUnregisterCallback); // The transition hasn't finished but Launcher was resumed, check if the launch failed - activity.addEventCallback(EVENT_RESUMED, mResumeCallback); + container.addEventCallback(EVENT_RESUMED, mResumeCallback); // If we somehow don't get any of the above signals, then just unregister this listener - activity.addEventCallback(EVENT_DESTROYED, mUnregisterCallback); + container.addEventCallback(EVENT_DESTROYED, mUnregisterCallback); - mActivity = activity; + mContainer = container; mLaunchedTaskId = launchedTaskId; mTaskLaunchFailedCallback = taskLaunchFailedCallback; } @@ -67,11 +67,11 @@ public class TaskRemovedDuringLaunchListener { * Unregisters the failure listener. */ private void unregister() { - mActivity.removeEventCallback(EVENT_STOPPED, mUnregisterCallback); - mActivity.removeEventCallback(EVENT_RESUMED, mResumeCallback); - mActivity.removeEventCallback(EVENT_DESTROYED, mUnregisterCallback); + mContainer.removeEventCallback(EVENT_STOPPED, mUnregisterCallback); + mContainer.removeEventCallback(EVENT_RESUMED, mResumeCallback); + mContainer.removeEventCallback(EVENT_DESTROYED, mUnregisterCallback); - mActivity = null; + mContainer = null; mLaunchedTaskId = INVALID_TASK_ID; mTaskLaunchFailedCallback = null; } diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java index 1152de2750..fcb865f10d 100644 --- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java +++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java @@ -51,6 +51,7 @@ import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds; import com.android.launcher3.util.TraceHelper; import com.android.quickstep.BaseActivityInterface; +import com.android.quickstep.BaseContainerInterface; import com.android.quickstep.TaskAnimationManager; import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties; import com.android.quickstep.views.TaskView.FullscreenDrawParams; @@ -70,7 +71,7 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { private final float[] mTempPoint = new float[2]; private final Context mContext; - private final BaseActivityInterface mSizeStrategy; + private final BaseContainerInterface mSizeStrategy; @NonNull private RecentsOrientedState mOrientationState; @@ -122,7 +123,7 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { private int mTaskRectTranslationX; private int mTaskRectTranslationY; - public TaskViewSimulator(Context context, BaseActivityInterface sizeStrategy) { + public TaskViewSimulator(Context context, BaseContainerInterface sizeStrategy) { mContext = context; mSizeStrategy = sizeStrategy; diff --git a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterHotseatAnimator.java b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterHotseatAnimator.java index c8141b4642..4aea1b8282 100644 --- a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterHotseatAnimator.java +++ b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterHotseatAnimator.java @@ -20,7 +20,7 @@ import android.view.ViewGroup; import android.view.WindowManager; import com.android.launcher3.Hotseat; -import com.android.launcher3.Launcher; +import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.systemui.unfold.updates.RotationChangeProvider; /** @@ -28,10 +28,10 @@ import com.android.systemui.unfold.updates.RotationChangeProvider; */ public class UnfoldMoveFromCenterHotseatAnimator extends BaseUnfoldMoveFromCenterAnimator { - private final Launcher mLauncher; + private final QuickstepLauncher mLauncher; - public UnfoldMoveFromCenterHotseatAnimator(Launcher launcher, WindowManager windowManager, - RotationChangeProvider rotationChangeProvider) { + public UnfoldMoveFromCenterHotseatAnimator(QuickstepLauncher launcher, + WindowManager windowManager, RotationChangeProvider rotationChangeProvider) { super(windowManager, rotationChangeProvider); mLauncher = launcher; } diff --git a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java index c05b38f5f2..0ec3ae05d7 100644 --- a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java +++ b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java @@ -19,9 +19,9 @@ import android.view.View; import android.view.WindowManager; import com.android.launcher3.CellLayout; -import com.android.launcher3.Launcher; import com.android.launcher3.ShortcutAndWidgetContainer; import com.android.launcher3.Workspace; +import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.systemui.unfold.updates.RotationChangeProvider; /** @@ -29,10 +29,10 @@ import com.android.systemui.unfold.updates.RotationChangeProvider; */ public class UnfoldMoveFromCenterWorkspaceAnimator extends BaseUnfoldMoveFromCenterAnimator { - private final Launcher mLauncher; + private final QuickstepLauncher mLauncher; - public UnfoldMoveFromCenterWorkspaceAnimator(Launcher launcher, WindowManager windowManager, - RotationChangeProvider rotationChangeProvider) { + public UnfoldMoveFromCenterWorkspaceAnimator(QuickstepLauncher launcher, + WindowManager windowManager, RotationChangeProvider rotationChangeProvider) { super(windowManager, rotationChangeProvider); mLauncher = launcher; } diff --git a/quickstep/src/com/android/quickstep/util/unfold/LauncherUnfoldTransitionController.kt b/quickstep/src/com/android/quickstep/util/unfold/LauncherUnfoldTransitionController.kt index 54d317d564..09563f5527 100644 --- a/quickstep/src/com/android/quickstep/util/unfold/LauncherUnfoldTransitionController.kt +++ b/quickstep/src/com/android/quickstep/util/unfold/LauncherUnfoldTransitionController.kt @@ -21,15 +21,15 @@ import android.view.Surface import com.android.launcher3.Alarm import com.android.launcher3.DeviceProfile import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener -import com.android.launcher3.Launcher import com.android.launcher3.anim.PendingAnimation import com.android.launcher3.config.FeatureFlags +import com.android.launcher3.uioverrides.QuickstepLauncher import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener /** Controls animations that are happening during unfolding foldable devices */ class LauncherUnfoldTransitionController( - private val launcher: Launcher, + private val launcher: QuickstepLauncher, private val progressProvider: ProxyUnfoldTransitionProvider ) : OnDeviceProfileChangeListener, ActivityLifecycleCallbacksAdapter, TransitionProgressListener { diff --git a/quickstep/src/com/android/quickstep/util/unfold/UnfoldAnimationBuilder.kt b/quickstep/src/com/android/quickstep/util/unfold/UnfoldAnimationBuilder.kt index d2c4728362..2f90ee760e 100644 --- a/quickstep/src/com/android/quickstep/util/unfold/UnfoldAnimationBuilder.kt +++ b/quickstep/src/com/android/quickstep/util/unfold/UnfoldAnimationBuilder.kt @@ -20,7 +20,6 @@ import android.view.ViewGroup import com.android.app.animation.Interpolators.LINEAR import com.android.app.animation.Interpolators.clampToProgress import com.android.launcher3.CellLayout -import com.android.launcher3.Launcher import com.android.launcher3.LauncherAnimUtils.HOTSEAT_SCALE_PROPERTY_FACTORY import com.android.launcher3.LauncherAnimUtils.SCALE_INDEX_UNFOLD_ANIMATION import com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X @@ -28,6 +27,7 @@ import com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y import com.android.launcher3.LauncherAnimUtils.WORKSPACE_SCALE_PROPERTY_FACTORY import com.android.launcher3.Workspace import com.android.launcher3.anim.PendingAnimation +import com.android.launcher3.uioverrides.QuickstepLauncher import com.android.launcher3.util.HorizontalInsettableView private typealias ViewGroupAction = (ViewGroup, Boolean) -> Unit @@ -112,7 +112,7 @@ object UnfoldAnimationBuilder { * Builds an animation for the unfold experience and adds it to the provided PendingAnimation */ fun buildUnfoldAnimation( - launcher: Launcher, + launcher: QuickstepLauncher, isVerticalFold: Boolean, screenSize: Point, anim: PendingAnimation diff --git a/quickstep/src/com/android/quickstep/views/ClearAllButton.java b/quickstep/src/com/android/quickstep/views/ClearAllButton.java index acda2e153d..b8afd9ddd9 100644 --- a/quickstep/src/com/android/quickstep/views/ClearAllButton.java +++ b/quickstep/src/com/android/quickstep/views/ClearAllButton.java @@ -68,7 +68,7 @@ public class ClearAllButton extends Button { } }; - private final StatefulActivity mActivity; + private final RecentsViewContainer mContainer; private float mScrollAlpha = 1; private float mContentAlpha = 1; private float mVisibilityAlpha = 1; @@ -92,7 +92,7 @@ public class ClearAllButton extends Button { public ClearAllButton(Context context, AttributeSet attrs) { super(context, attrs); mIsRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL; - mActivity = StatefulActivity.fromContext(context); + mContainer = RecentsViewContainer.containerFromContext(context); if (Flags.enableFocusOutline()) { TypedArray styledAttrs = context.obtainStyledAttributes(attrs, @@ -326,7 +326,7 @@ public class ClearAllButton extends Button { * Get the Y translation that is set in the original layout position, before scrolling. */ private float getOriginalTranslationY() { - DeviceProfile deviceProfile = mActivity.getDeviceProfile(); + DeviceProfile deviceProfile = mContainer.getDeviceProfile(); if (deviceProfile.isTablet) { if (enableGridOnlyOverview()) { return (getRecentsView().getLastComputedTaskSize().height() diff --git a/quickstep/src/com/android/quickstep/views/DesktopAppSelectView.java b/quickstep/src/com/android/quickstep/views/DesktopAppSelectView.java index a5be142235..6a9a268334 100644 --- a/quickstep/src/com/android/quickstep/views/DesktopAppSelectView.java +++ b/quickstep/src/com/android/quickstep/views/DesktopAppSelectView.java @@ -33,6 +33,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.Utilities; +import com.android.launcher3.uioverrides.QuickstepLauncher; /** * Floating view show on launcher home screen that notifies the user that an app will be launched to @@ -47,7 +48,7 @@ public class DesktopAppSelectView extends LinearLayout { private static final int SHOW_CONTENT_ALPHA_DURATION = 83; private static final int HIDE_DURATION = 83; - private final Launcher mLauncher; + private final RecentsViewContainer mContainer; private View mText; private View mCloseButton; @@ -71,7 +72,7 @@ public class DesktopAppSelectView extends LinearLayout { public DesktopAppSelectView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); - mLauncher = Launcher.getLauncher(context); + mContainer = RecentsViewContainer.containerFromContext(context); } /** @@ -104,7 +105,7 @@ public class DesktopAppSelectView extends LinearLayout { } private void show() { - mLauncher.getDragLayer().addView(this); + mContainer.getDragLayer().addView(this); // Set up initial values getBackground().setAlpha(0); @@ -163,7 +164,7 @@ public class DesktopAppSelectView extends LinearLayout { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); - mLauncher.getDragLayer().removeView(DesktopAppSelectView.this); + mContainer.getDragLayer().removeView(DesktopAppSelectView.this); mHideAnimation = null; } }); diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java index 10b4168601..78b17632a3 100644 --- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java +++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java @@ -118,7 +118,7 @@ public class DesktopTaskView extends TaskView { mBackgroundView = findViewById(R.id.background); int topMarginPx = - mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx; + mContainer.getDeviceProfile().overviewTaskThumbnailTopMarginPx; FrameLayout.LayoutParams params = (LayoutParams) mBackgroundView.getLayoutParams(); params.topMargin = topMarginPx; mBackgroundView.setLayoutParams(params); @@ -303,7 +303,7 @@ public class DesktopTaskView extends TaskView { @Override protected void setThumbnailOrientation(RecentsOrientedState orientationState) { - DeviceProfile deviceProfile = mActivity.getDeviceProfile(); + DeviceProfile deviceProfile = mContainer.getDeviceProfile(); int thumbnailTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx; LayoutParams snapshotParams = (LayoutParams) mSnapshotView.getLayoutParams(); @@ -420,7 +420,7 @@ public class DesktopTaskView extends TaskView { setMeasuredDimension(containerWidth, containerHeight); - int thumbnailTopMarginPx = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx; + int thumbnailTopMarginPx = mContainer.getDeviceProfile().overviewTaskThumbnailTopMarginPx; containerHeight -= thumbnailTopMarginPx; int thumbnails = mSnapshotViewMap.size(); @@ -428,8 +428,8 @@ public class DesktopTaskView extends TaskView { return; } - int windowWidth = mActivity.getDeviceProfile().widthPx; - int windowHeight = mActivity.getDeviceProfile().heightPx; + int windowWidth = mContainer.getDeviceProfile().widthPx; + int windowHeight = mContainer.getDeviceProfile().heightPx; float scaleWidth = containerWidth / (float) windowWidth; float scaleHeight = containerHeight / (float) windowHeight; diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java index 840382d141..8fa5375739 100644 --- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java +++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java @@ -45,8 +45,6 @@ import androidx.annotation.IntDef; import androidx.annotation.Nullable; import androidx.annotation.StringRes; -import com.android.launcher3.BaseActivity; -import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; import com.android.launcher3.Utilities; @@ -83,7 +81,7 @@ public final class DigitalWellBeingToast { private static final String TAG = DigitalWellBeingToast.class.getSimpleName(); - private final BaseDraggingActivity mActivity; + private final RecentsViewContainer mContainer; private final TaskView mTaskView; private final LauncherApps mLauncherApps; @@ -102,10 +100,10 @@ public final class DigitalWellBeingToast { private float mSplitOffsetTranslationY; private float mSplitOffsetTranslationX; - public DigitalWellBeingToast(BaseDraggingActivity activity, TaskView taskView) { - mActivity = activity; + public DigitalWellBeingToast(RecentsViewContainer container, TaskView taskView) { + mContainer = container; mTaskView = taskView; - mLauncherApps = activity.getSystemService(LauncherApps.class); + mLauncherApps = container.asContext().getSystemService(LauncherApps.class); } private void setNoLimit() { @@ -120,9 +118,10 @@ public final class DigitalWellBeingToast { mAppUsageLimitTimeMs = appUsageLimitTimeMs; mAppRemainingTimeMs = appRemainingTimeMs; mHasLimit = true; - TextView toast = mActivity.getViewCache().getView(R.layout.digital_wellbeing_toast, - mActivity, mTaskView); - toast.setText(prefixTextWithIcon(mActivity, R.drawable.ic_hourglass_top, getText())); + TextView toast = mContainer.getViewCache().getView(R.layout.digital_wellbeing_toast, + mContainer.asContext(), mTaskView); + toast.setText(prefixTextWithIcon(mContainer.asContext(), R.drawable.ic_hourglass_top, + getText())); toast.setOnClickListener(this::openAppUsageSettings); replaceBanner(toast); @@ -170,14 +169,14 @@ public final class DigitalWellBeingToast { public void setSplitConfiguration(SplitBounds splitBounds) { mSplitBounds = splitBounds; if (mSplitBounds == null - || !mActivity.getDeviceProfile().isTablet + || !mContainer.getDeviceProfile().isTablet || mTaskView.isFocusedTask()) { mSplitBannerConfig = SPLIT_BANNER_FULLSCREEN; return; } // For portrait grid only height of task changes, not width. So we keep the text the same - if (!mActivity.getDeviceProfile().isLeftRightSplit) { + if (!mContainer.getDeviceProfile().isLeftRightSplit) { mSplitBannerConfig = SPLIT_GRID_BANNER_LARGE; return; } @@ -226,7 +225,7 @@ public final class DigitalWellBeingToast { // Use a specific string for usage less than one minute but non-zero. if (duration.compareTo(Duration.ZERO) > 0) { - return mActivity.getString(durationLessThanOneMinuteStringId); + return mContainer.asContext().getString(durationLessThanOneMinuteStringId); } // Otherwise, return 0-minute string. @@ -250,7 +249,7 @@ public final class DigitalWellBeingToast { R.string.shorter_duration_less_than_one_minute, false /* forceFormatWidth */); if (forContentDesc || mSplitBannerConfig == SPLIT_BANNER_FULLSCREEN) { - return mActivity.getString( + return mContainer.asContext().getString( R.string.time_left_for_app, readableDuration); } @@ -270,11 +269,12 @@ public final class DigitalWellBeingToast { mTask.getTopComponent().getPackageName()).addFlags( Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); try { - final BaseActivity activity = BaseActivity.fromContext(view.getContext()); + final RecentsViewContainer container = + RecentsViewContainer.containerFromContext(view.getContext()); final ActivityOptions options = ActivityOptions.makeScaleUpAnimation( view, 0, 0, view.getWidth(), view.getHeight()); - activity.startActivity(intent, options.toBundle()); + container.asContext().startActivity(intent, options.toBundle()); // TODO: add WW logging on the app usage settings click. } catch (ActivityNotFoundException e) { @@ -286,7 +286,7 @@ public final class DigitalWellBeingToast { private String getContentDescriptionForTask( Task task, long appUsageLimitTimeMs, long appRemainingTimeMs) { return appUsageLimitTimeMs >= 0 && appRemainingTimeMs >= 0 ? - mActivity.getString( + mContainer.asContext().getString( R.string.task_contents_description_with_remaining_time, task.titleDescription, getText(appRemainingTimeMs, true /* forContentDesc */)) : @@ -303,7 +303,7 @@ public final class DigitalWellBeingToast { mBanner.setOutlineProvider(mOldBannerOutlineProvider); mTaskView.removeView(mBanner); mBanner.setOnClickListener(null); - mActivity.getViewCache().recycleView(R.layout.digital_wellbeing_toast, mBanner); + mContainer.getViewCache().recycleView(R.layout.digital_wellbeing_toast, mBanner); } } @@ -318,7 +318,7 @@ public final class DigitalWellBeingToast { private void setupAndAddBanner() { FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) mBanner.getLayoutParams(); - DeviceProfile deviceProfile = mActivity.getDeviceProfile(); + DeviceProfile deviceProfile = mContainer.getDeviceProfile(); layoutParams.bottomMargin = ((ViewGroup.MarginLayoutParams) mTaskView.getThumbnail().getLayoutParams()).bottomMargin; RecentsPagedOrientationHandler orientationHandler = mTaskView.getPagedOrientationHandler(); diff --git a/quickstep/src/com/android/quickstep/views/FloatingAppPairBackground.kt b/quickstep/src/com/android/quickstep/views/FloatingAppPairBackground.kt index 1c1e1674e5..0d49309d1c 100644 --- a/quickstep/src/com/android/quickstep/views/FloatingAppPairBackground.kt +++ b/quickstep/src/com/android/quickstep/views/FloatingAppPairBackground.kt @@ -26,7 +26,6 @@ import android.graphics.drawable.Drawable import android.os.Build import android.view.animation.Interpolator import com.android.app.animation.Interpolators -import com.android.launcher3.Launcher import com.android.launcher3.R import com.android.launcher3.Utilities import com.android.quickstep.util.AnimUtils @@ -55,7 +54,7 @@ class FloatingAppPairBackground( private val ARRAY_OF_ZEROES = FloatArray(8) } - private val launcher: Launcher + private val container: RecentsViewContainer private val backgroundPaint = Paint(Paint.ANTI_ALIAS_FLAG) // Animation interpolators @@ -70,15 +69,15 @@ class FloatingAppPairBackground( private val desiredSplitRatio: Float init { - launcher = Launcher.getLauncher(context) - val dp = launcher.deviceProfile + container = RecentsViewContainer.containerFromContext(context) + val dp = container.deviceProfile // Set up background paint color val ta = context.theme.obtainStyledAttributes(R.styleable.FolderIconPreview) backgroundPaint.style = Paint.Style.FILL backgroundPaint.color = ta.getColor(R.styleable.FolderIconPreview_folderPreviewColor, 0) ta.recycle() // Set up timings and interpolators - val timings = AnimUtils.getDeviceAppPairLaunchTimings(launcher.deviceProfile.isTablet) + val timings = AnimUtils.getDeviceAppPairLaunchTimings(container.deviceProfile.isTablet) expandXInterpolator = Interpolators.clampToProgress( timings.getStagedRectScaleXInterpolator(), @@ -105,9 +104,9 @@ class FloatingAppPairBackground( ) // Find device-specific measurements - deviceCornerRadius = QuickStepContract.getWindowCornerRadius(launcher) + deviceCornerRadius = QuickStepContract.getWindowCornerRadius(container.asContext()) deviceHalfDividerSize = - launcher.resources.getDimensionPixelSize(R.dimen.multi_window_task_divider_size) / 2f + container.asContext().resources.getDimensionPixelSize(R.dimen.multi_window_task_divider_size) / 2f val dividerCenterPos = dividerPos + deviceHalfDividerSize desiredSplitRatio = if (dp.isLeftRightSplit) dividerCenterPos / dp.widthPx @@ -115,7 +114,7 @@ class FloatingAppPairBackground( } override fun draw(canvas: Canvas) { - if (launcher.deviceProfile.isLeftRightSplit) { + if (container.deviceProfile.isLeftRightSplit) { drawLeftRightSplit(canvas) } else { drawTopBottomSplit(canvas) @@ -150,39 +149,37 @@ class FloatingAppPairBackground( val dividerCenterPos = width * desiredSplitRatio // The left half of the background image - val leftSide = RectF( - 0f, - 0f, - dividerCenterPos - changingDividerSize, - height - ) + val leftSide = RectF(0f, 0f, dividerCenterPos - changingDividerSize, height) // The right half of the background image - val rightSide = RectF( - dividerCenterPos + changingDividerSize, - 0f, - width, - height - ) + val rightSide = RectF(dividerCenterPos + changingDividerSize, 0f, width, height) // Draw background drawCustomRoundedRect( canvas, leftSide, floatArrayOf( - cornerRadiusX, cornerRadiusY, - changingInnerRadiusX, changingInnerRadiusY, - changingInnerRadiusX, changingInnerRadiusY, - cornerRadiusX, cornerRadiusY + cornerRadiusX, + cornerRadiusY, + changingInnerRadiusX, + changingInnerRadiusY, + changingInnerRadiusX, + changingInnerRadiusY, + cornerRadiusX, + cornerRadiusY, ) ) drawCustomRoundedRect( canvas, rightSide, floatArrayOf( - changingInnerRadiusX, changingInnerRadiusY, - cornerRadiusX, cornerRadiusY, - cornerRadiusX, cornerRadiusY, - changingInnerRadiusX, changingInnerRadiusY + changingInnerRadiusX, + changingInnerRadiusY, + cornerRadiusX, + cornerRadiusY, + cornerRadiusX, + cornerRadiusY, + changingInnerRadiusX, + changingInnerRadiusY, ) ) @@ -250,39 +247,37 @@ class FloatingAppPairBackground( val dividerCenterPos = height * desiredSplitRatio // The top half of the background image - val topSide = RectF( - 0f, - 0f, - width, - dividerCenterPos - changingDividerSize - ) + val topSide = RectF(0f, 0f, width, dividerCenterPos - changingDividerSize) // The bottom half of the background image - val bottomSide = RectF( - 0f, - dividerCenterPos + changingDividerSize, - width, - height - ) + val bottomSide = RectF(0f, dividerCenterPos + changingDividerSize, width, height) // Draw background drawCustomRoundedRect( canvas, topSide, floatArrayOf( - cornerRadiusX, cornerRadiusY, - cornerRadiusX, cornerRadiusY, - changingInnerRadiusX, changingInnerRadiusY, - changingInnerRadiusX, changingInnerRadiusY + cornerRadiusX, + cornerRadiusY, + cornerRadiusX, + cornerRadiusY, + changingInnerRadiusX, + changingInnerRadiusY, + changingInnerRadiusX, + changingInnerRadiusY ) ) drawCustomRoundedRect( canvas, bottomSide, floatArrayOf( - changingInnerRadiusX, changingInnerRadiusY, - changingInnerRadiusX, changingInnerRadiusY, - cornerRadiusX, cornerRadiusY, - cornerRadiusX, cornerRadiusY + changingInnerRadiusX, + changingInnerRadiusY, + changingInnerRadiusX, + changingInnerRadiusY, + cornerRadiusX, + cornerRadiusY, + cornerRadiusX, + cornerRadiusY ) ) @@ -338,8 +333,10 @@ class FloatingAppPairBackground( // Fallback rectangle with uniform rounded corners val scaleFactorX = floatingView.scaleX val scaleFactorY = floatingView.scaleY - val cornerRadiusX = QuickStepContract.getWindowCornerRadius(launcher) / scaleFactorX - val cornerRadiusY = QuickStepContract.getWindowCornerRadius(launcher) / scaleFactorY + val cornerRadiusX = + QuickStepContract.getWindowCornerRadius(container.asContext()) / scaleFactorX + val cornerRadiusY = + QuickStepContract.getWindowCornerRadius(container.asContext()) / scaleFactorY c.drawRoundRect(rect, cornerRadiusX, cornerRadiusY, backgroundPaint) } } diff --git a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java index 18922a6fb3..e479c16200 100644 --- a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java +++ b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java @@ -36,12 +36,10 @@ import android.widget.FrameLayout; import androidx.annotation.Nullable; import com.android.launcher3.AbstractFloatingView; -import com.android.launcher3.BaseActivity; import com.android.launcher3.InsettableFrameLayout; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.anim.PendingAnimation; -import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.taskbar.TaskbarActivityContext; import com.android.launcher3.util.SplitConfigurationOptions; import com.android.launcher3.views.BaseDragLayer; @@ -54,7 +52,7 @@ import com.android.systemui.shared.system.QuickStepContract; /** * Create an instance via - * {@link #getFloatingTaskView(StatefulActivity, View, Bitmap, Drawable, RectF)} to + * {@link #getFloatingTaskView(RecentsViewContainer, View, Bitmap, Drawable, RectF)} to * which will have the thumbnail from the provided existing TaskView overlaying the taskview itself. * * Can then animate the taskview using @@ -67,32 +65,32 @@ public class FloatingTaskView extends FrameLayout { public static final FloatProperty PRIMARY_TRANSLATE_OFFSCREEN = new FloatProperty("floatingTaskPrimaryTranslateOffscreen") { - @Override - public void setValue(FloatingTaskView view, float translation) { - ((RecentsView) view.mActivity.getOverviewPanel()).getPagedOrientationHandler() - .setFloatingTaskPrimaryTranslation( - view, - translation, - view.mActivity.getDeviceProfile() - ); - } + @Override + public void setValue(FloatingTaskView view, float translation) { + ((RecentsView) view.mContainer.getOverviewPanel()).getPagedOrientationHandler() + .setFloatingTaskPrimaryTranslation( + view, + translation, + view.mContainer.getDeviceProfile() + ); + } - @Override - public Float get(FloatingTaskView view) { - return ((RecentsView) view.mActivity.getOverviewPanel()) - .getPagedOrientationHandler() - .getFloatingTaskPrimaryTranslation( - view, - view.mActivity.getDeviceProfile() - ); - } - }; + @Override + public Float get(FloatingTaskView view) { + return ((RecentsView) view.mContainer.getOverviewPanel()) + .getPagedOrientationHandler() + .getFloatingTaskPrimaryTranslation( + view, + view.mContainer.getDeviceProfile() + ); + } + }; private int mSplitHolderSize; private FloatingTaskThumbnailView mThumbnailView; private SplitPlaceholderView mSplitPlaceholderView; private RectF mStartingPosition; - private final StatefulActivity mActivity; + private final RecentsViewContainer mContainer; private final boolean mIsRtl; private final FullscreenDrawParams mFullscreenParams; private RecentsPagedOrientationHandler mOrientationHandler; @@ -110,7 +108,7 @@ public class FloatingTaskView extends FrameLayout { public FloatingTaskView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); - mActivity = BaseActivity.fromContext(context); + mContainer = RecentsViewContainer.containerFromContext(context); mIsRtl = Utilities.isRtl(getResources()); mFullscreenParams = new FullscreenDrawParams(context); @@ -126,7 +124,7 @@ public class FloatingTaskView extends FrameLayout { mSplitPlaceholderView.setAlpha(0); } - private void init(StatefulActivity launcher, View originalView, @Nullable Bitmap thumbnail, + private void init(RecentsViewContainer launcher, View originalView, @Nullable Bitmap thumbnail, Drawable icon, RectF positionOut) { mStartingPosition = positionOut; updateInitialPositionForView(originalView); @@ -153,7 +151,7 @@ public class FloatingTaskView extends FrameLayout { * Configures and returns a an instance of {@link FloatingTaskView} initially matching the * appearance of {@code originalView}. */ - public static FloatingTaskView getFloatingTaskView(StatefulActivity launcher, + public static FloatingTaskView getFloatingTaskView(RecentsViewContainer launcher, View originalView, @Nullable Bitmap thumbnail, Drawable icon, RectF positionOut) { final ViewGroup dragLayer = launcher.getDragLayer(); final FloatingTaskView floatingView = (FloatingTaskView) launcher.getLayoutInflater() @@ -179,13 +177,13 @@ public class FloatingTaskView extends FrameLayout { originalView.getBoundsOnScreen(mTmpRect); mStartingPosition.set(mTmpRect); int[] dragLayerPositionRelativeToScreen = - mActivity.getDragLayer().getLocationOnScreen(); + mContainer.getDragLayer().getLocationOnScreen(); mStartingPosition.offset( -dragLayerPositionRelativeToScreen[0], -dragLayerPositionRelativeToScreen[1]); } else { Rect viewBounds = new Rect(0, 0, originalView.getWidth(), originalView.getHeight()); - Utilities.getBoundsForViewInDragLayer(mActivity.getDragLayer(), originalView, + Utilities.getBoundsForViewInDragLayer(mContainer.getDragLayer(), originalView, viewBounds, false /* ignoreTransform */, null /* recycle */, mStartingPosition); } @@ -235,7 +233,7 @@ public class FloatingTaskView extends FrameLayout { // Position the floating view exactly on top of the original lp.topMargin = Math.round(pos.top); if (mIsRtl) { - lp.setMarginStart(mActivity.getDeviceProfile().widthPx - Math.round(pos.right)); + lp.setMarginStart(mContainer.getDeviceProfile().widthPx - Math.round(pos.right)); } else { lp.setMarginStart(Math.round(pos.left)); } @@ -252,7 +250,7 @@ public class FloatingTaskView extends FrameLayout { */ public void addStagingAnimation(PendingAnimation animation, RectF startingBounds, Rect endBounds, boolean fadeWithThumbnail, boolean isStagedTask) { - boolean isTablet = mActivity.getDeviceProfile().isTablet; + boolean isTablet = mContainer.getDeviceProfile().isTablet; boolean splittingFromOverview = fadeWithThumbnail; SplitAnimationTimings timings; @@ -276,7 +274,7 @@ public class FloatingTaskView extends FrameLayout { public void addConfirmAnimation(PendingAnimation animation, RectF startingBounds, Rect endBounds, boolean fadeWithThumbnail, boolean isStagedTask) { SplitAnimationTimings timings = - AnimUtils.getDeviceSplitToConfirmTimings(mActivity.getDeviceProfile().isTablet); + AnimUtils.getDeviceSplitToConfirmTimings(mContainer.getDeviceProfile().isTablet); addAnimation(animation, startingBounds, endBounds, fadeWithThumbnail, isStagedTask, timings); @@ -291,7 +289,7 @@ public class FloatingTaskView extends FrameLayout { Rect endBounds, boolean fadeWithThumbnail, boolean isStagedTask, SplitAnimationTimings timings) { mFullscreenParams.setIsStagedTask(isStagedTask); - final BaseDragLayer dragLayer = mActivity.getDragLayer(); + final BaseDragLayer dragLayer = mContainer.getDragLayer(); int[] dragLayerBounds = new int[2]; dragLayer.getLocationOnScreen(dragLayerBounds); SplitOverlayProperties prop = new SplitOverlayProperties(endBounds, @@ -391,7 +389,7 @@ public class FloatingTaskView extends FrameLayout { mOrientationHandler.updateSplitIconParams(iconView, onScreenRectCenterX, onScreenRectCenterY, mFullscreenParams.mScaleX, mFullscreenParams.mScaleY, iconView.getDrawableWidth(), iconView.getDrawableHeight(), - mActivity.getDeviceProfile(), mStagePosition); + mContainer.getDeviceProfile(), mStagePosition); } public int getStagePosition() { diff --git a/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java b/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java index 486fc2cf08..4dde635da7 100644 --- a/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java +++ b/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java @@ -33,10 +33,10 @@ import android.widget.FrameLayout; import androidx.annotation.Nullable; -import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.dragndrop.DragLayer; +import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.util.Themes; import com.android.launcher3.views.FloatingView; import com.android.launcher3.views.ListenerView; @@ -49,7 +49,7 @@ public class FloatingWidgetView extends FrameLayout implements AnimatorListener, OnGlobalLayoutListener, FloatingView { private static final Matrix sTmpMatrix = new Matrix(); - private final Launcher mLauncher; + private final QuickstepLauncher mLauncher; private final ListenerView mListenerView; private final FloatingWidgetBackgroundView mBackgroundView; private final RectF mBackgroundOffset = new RectF(); @@ -80,7 +80,7 @@ public class FloatingWidgetView extends FrameLayout implements AnimatorListener, public FloatingWidgetView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); - mLauncher = Launcher.getLauncher(context); + mLauncher = QuickstepLauncher.getLauncher(context); mListenerView = new ListenerView(context, attrs); mBackgroundView = new FloatingWidgetBackgroundView(context, attrs, defStyleAttr); addView(mBackgroundView); @@ -283,7 +283,7 @@ public class FloatingWidgetView extends FrameLayout implements AnimatorListener, * @param windowSize the size of the window when launched * @param windowCornerRadius the corner radius of the window */ - public static FloatingWidgetView getFloatingWidgetView(Launcher launcher, + public static FloatingWidgetView getFloatingWidgetView(QuickstepLauncher launcher, LauncherAppWidgetHostView originalView, RectF widgetBackgroundPosition, Size windowSize, float windowCornerRadius, boolean appTargetsAreTranslucent, int fallbackBackgroundColor) { diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java index 259927d4e7..9e1c856455 100644 --- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java +++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java @@ -41,11 +41,11 @@ import com.android.systemui.shared.recents.utilities.PreviewPositionHelper; import com.android.systemui.shared.system.InteractionJankMonitorWrapper; import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition; +import kotlin.Unit; + import java.util.HashMap; import java.util.function.Consumer; -import kotlin.Unit; - /** * TaskView that contains and shows thumbnails for not one, BUT TWO(!!) tasks * @@ -81,7 +81,7 @@ public class GroupedTaskView extends TaskView { public GroupedTaskView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); - mDigitalWellBeingToast2 = new DigitalWellBeingToast(mActivity, this); + mDigitalWellBeingToast2 = new DigitalWellBeingToast(mContainer, this); } @Override @@ -356,7 +356,7 @@ public class GroupedTaskView extends TaskView { if (initSplitTaskId == INVALID_TASK_ID) { getPagedOrientationHandler().measureGroupedTaskViewThumbnailBounds(mSnapshotView, mSnapshotView2, widthSize, heightSize, mSplitBoundsConfig, - mActivity.getDeviceProfile(), getLayoutDirection() == LAYOUT_DIRECTION_RTL); + mContainer.getDeviceProfile(), getLayoutDirection() == LAYOUT_DIRECTION_RTL); // Should we be having a separate translation step apart from the measuring above? // The following only applies to large screen for now, but for future reference // we'd want to abstract this out in PagedViewHandlers to get the primary/secondary @@ -373,7 +373,7 @@ public class GroupedTaskView extends TaskView { container.getThumbnailView().measure(widthMeasureSpec, View.MeasureSpec.makeMeasureSpec( heightSize - - mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx, + mContainer.getDeviceProfile().overviewTaskThumbnailTopMarginPx, MeasureSpec.EXACTLY)); } if (!enableOverviewIconMenu()) { @@ -392,7 +392,7 @@ public class GroupedTaskView extends TaskView { @Override public void setOrientationState(RecentsOrientedState orientationState) { - DeviceProfile deviceProfile = mActivity.getDeviceProfile(); + DeviceProfile deviceProfile = mContainer.getDeviceProfile(); if (enableOverviewIconMenu() && mSplitBoundsConfig != null) { ViewGroup.LayoutParams layoutParams = getLayoutParams(); Pair groupedTaskViewSizes = @@ -425,7 +425,7 @@ public class GroupedTaskView extends TaskView { return; } - DeviceProfile deviceProfile = mActivity.getDeviceProfile(); + DeviceProfile deviceProfile = mContainer.getDeviceProfile(); int taskIconHeight = deviceProfile.overviewTaskIconSizePx; boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL; diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java index 0a3d2a0ac1..06c2aa3804 100644 --- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java @@ -72,7 +72,7 @@ public class LauncherRecentsView extends RecentsView getStateManager() { + return mContainer.getStateManager(); } @Override protected void onTaskLaunchAnimationEnd(boolean success) { if (success) { - mActivity.getStateManager().moveToRestState(); + getStateManager().moveToRestState(); } else { - LauncherState state = mActivity.getStateManager().getState(); - mActivity.getAllAppsController().setState(state); + LauncherState state = getStateManager().getState(); + mContainer.getAllAppsController().setState(state); } super.onTaskLaunchAnimationEnd(success); } @@ -115,14 +120,14 @@ public class LauncherRecentsView extends RecentsView : the container that should host recents view + * @param : the type of base state that will be used */ -public abstract class RecentsView, + +public abstract class RecentsView> extends PagedView implements Insettable, TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback, TaskVisualsChangeListener { @@ -443,7 +446,7 @@ public abstract class RecentsView mSizeStrategy; + protected final BaseContainerInterface mSizeStrategy; @Nullable protected RecentsAnimationController mRecentsAnimationController; @Nullable @@ -480,7 +483,7 @@ public abstract class RecentsView { - Animator animatorFade = mActivity.getStateManager().createStateElementAnimation( + Animator animatorFade = getStateManager().createStateElementAnimation( RecentsAtomicAnimationFactory.INDEX_RECENTS_FADE_ANIM, 1f, 0f); - Animator animatorAppear = mActivity.getStateManager().createStateElementAnimation( + Animator animatorAppear = getStateManager().createStateElementAnimation( RecentsAtomicAnimationFactory.INDEX_RECENTS_FADE_ANIM, 0f, 1f); animatorFade.addListener(new AnimatorListenerAdapter() { @Override @@ -1088,13 +1091,13 @@ public abstract class RecentsView remoteTargetHandle.getTransformParams() .setSyncTransactionApplier(mSyncTransactionApplier)); RecentsModel.INSTANCE.get(getContext()).addThumbnailChangeListener(this); - mIPipAnimationListener.setActivityAndRecentsView(mActivity, this); + mIPipAnimationListener.setActivityAndRecentsView(mContainer, this); SystemUiProxy.INSTANCE.get(getContext()).setPipAnimationListener( mIPipAnimationListener); mOrientationState.initListeners(); @@ -1109,7 +1112,7 @@ public abstract class RecentsView remoteTargetHandle.getTransformParams() @@ -1249,7 +1252,7 @@ public abstract class RecentsView= 0; --i) { RemoteAnimationTarget app = apps[i]; - float dx = mActivity.getDeviceProfile().widthPx * (1 - percent) / 2 + float dx = mContainer.getDeviceProfile().widthPx * (1 - percent) / 2 + app.screenSpaceBounds.left * percent; - float dy = mActivity.getDeviceProfile().heightPx * (1 - percent) / 2 + float dy = mContainer.getDeviceProfile().heightPx * (1 - percent) / 2 + app.screenSpaceBounds.top * percent; matrix.setScale(percent, percent); matrix.postTranslate(dx, dy); @@ -1294,7 +1297,7 @@ public abstract class RecentsView 0) { @@ -1495,7 +1498,7 @@ public abstract class RecentsView deviceProfile.availableWidthPx * SIGNIFICANT_MOVE_SCREEN_WIDTH_PERCENTAGE; } + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + boolean intercept = super.onInterceptTouchEvent(ev); + if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) { + Log.d("b/318590728", "onInterceptTouchEvent: " + ev); + } + return intercept; + } + @Override public boolean onTouchEvent(MotionEvent ev) { super.onTouchEvent(ev); @@ -1644,7 +1656,7 @@ public abstract class RecentsView getStateManager(); + public void reset() { setCurrentTask(-1); mCurrentPageScrollDiff = 0; @@ -2570,6 +2584,7 @@ public abstract class RecentsView { setLayoutRotation(newRotation, mOrientationState.getDisplayRotation()); - mActivity.getDragLayer().recreateControllers(); + mContainer.getDragLayer().recreateControllers(); setRecentsChangedOrientation(false).start(); })); pa.start(); @@ -2637,7 +2652,7 @@ public abstract class RecentsView endState = mSizeStrategy.stateFromGestureEndTarget(endTarget); - if (endState.displayOverviewTasksAsGrid(mActivity.getDeviceProfile())) { + if (endState.displayOverviewTasksAsGrid(mContainer.getDeviceProfile())) { TaskView runningTaskView = getRunningTaskView(); float runningTaskPrimaryGridTranslation = 0; float runningTaskSecondaryGridTranslation = 0; @@ -2921,7 +2936,7 @@ public abstract class RecentsView mSplitSelectStateController.getSplitAnimationController(). - playAnimPlaceholderToFullscreen(mActivity, view, + playAnimPlaceholderToFullscreen(mContainer, view, Optional.of(() -> resetFromSplitSelectionState()))); // SplitInstructionsView: animate in safeRemoveDragLayerView(mSplitSelectStateController.getSplitInstructionsView()); SplitInstructionsView splitInstructionsView = - SplitInstructionsView.getSplitInstructionsView(mActivity); + SplitInstructionsView.getSplitInstructionsView(mContainer); splitInstructionsView.setAlpha(0); anim.setViewAlpha(splitInstructionsView, 1, clampToProgress(LINEAR, timings.getInstructionsContainerFadeInStartOffset(), @@ -3436,7 +3451,7 @@ public abstract class RecentsView mContainer.getDisplay().getRotation()); mOrientationState.setRecentsRotation(rotation); } @@ -4408,14 +4424,14 @@ public abstract class RecentsView{ @@ -4816,14 +4832,14 @@ public abstract class RecentsView, FloatProperty> taskViewsFloat = orientationHandler.getSplitSelectTaskOffset( TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION, - mActivity.getDeviceProfile()); + mContainer.getDeviceProfile()); taskViewsFloat.first.set(this, getSplitSelectTranslation()); taskViewsFloat.second.set(this, 0f); @@ -5108,10 +5124,10 @@ public abstract class RecentsView UPDATE_SYSUI_FLAGS_THRESHOLD) { - mActivity.getSystemUiController().updateUiState( + mContainer.getSystemUiController().updateUiState( UI_STATE_FULLSCREEN_TASK, targetSysUiFlags); } else { - mActivity.getSystemUiController().updateUiState(UI_STATE_FULLSCREEN_TASK, 0); + mContainer.getSystemUiController().updateUiState(UI_STATE_FULLSCREEN_TASK, 0); } // Passing the threshold from taskview to fullscreen app will vibrate @@ -5173,7 +5189,7 @@ public abstract class RecentsView extends + private static class PinnedStackAnimationListener extends IPipAnimationListener.Stub { @Nullable private T mActivity; @@ -6190,7 +6208,7 @@ public abstract class RecentsView mActivity.setLocusContext(id, Bundle.EMPTY)); + UI_HELPER_EXECUTOR.post(() -> mContainer.setLocusContext(id, Bundle.EMPTY)); + } + + /** + * Moves the provided task into desktop mode, and invoke {@code successCallback} if succeeded. + */ + public void moveTaskToDesktop(TaskIdAttributeContainer taskContainer, + Runnable successCallback) { + if (!enableDesktopWindowingMode()) { + return; + } + switchToScreenshot(() -> finishRecentsAnimation(/* toRecents= */true, /* shouldPip= */false, + () -> moveTaskToDesktopInternal(taskContainer, successCallback))); + } + + private void moveTaskToDesktopInternal(TaskIdAttributeContainer taskContainer, + Runnable successCallback) { + if (mDesktopRecentsTransitionController == null) { + return; + } + mDesktopRecentsTransitionController.moveToDesktop(taskContainer.getTask().key.id); + successCallback.run(); } public interface TaskLaunchListener { diff --git a/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java b/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java index a3e5a35fbb..a56d51e515 100644 --- a/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java +++ b/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java @@ -43,6 +43,7 @@ import com.android.launcher3.statemanager.BaseState; import com.android.launcher3.statemanager.StateManager; import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.states.StateAnimationConfig; + import com.android.quickstep.util.SplitSelectStateController; /** @@ -57,7 +58,7 @@ public class SplitInstructionsView extends LinearLayout { private static final float BOUNCE_HEIGHT = 20; private static final int DURATION_DEFAULT_SPLIT_DISMISS = 350; - private final StatefulActivity mLauncher; + private final RecentsViewContainer mContainer; public boolean mIsCurrentlyAnimating = false; public static final FloatProperty UNFOLD = @@ -96,13 +97,13 @@ public class SplitInstructionsView extends LinearLayout { public SplitInstructionsView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); - mLauncher = (StatefulActivity) context; + mContainer = RecentsViewContainer.containerFromContext(context); } - public static SplitInstructionsView getSplitInstructionsView(StatefulActivity launcher) { - ViewGroup dragLayer = launcher.getDragLayer(); + public static SplitInstructionsView getSplitInstructionsView(RecentsViewContainer container) { + ViewGroup dragLayer = container.getDragLayer(); final SplitInstructionsView splitInstructionsView = - (SplitInstructionsView) launcher.getLayoutInflater().inflate( + (SplitInstructionsView) container.getLayoutInflater().inflate( R.layout.split_instructions_view, dragLayer, false @@ -139,12 +140,12 @@ public class SplitInstructionsView extends LinearLayout { } private void exitSplitSelection() { - SplitSelectStateController splitSelectController = - ((RecentsView) mLauncher.getOverviewPanel()).getSplitSelectController(); + RecentsView recentsView = mContainer.getOverviewPanel(); + SplitSelectStateController splitSelectController = recentsView.getSplitSelectController(); - StateManager stateManager = mLauncher.getStateManager(); + StateManager stateManager = recentsView.getStateManager(); BaseState startState = stateManager.getState(); - long duration = startState.getTransitionDuration(mLauncher, false); + long duration = startState.getTransitionDuration(mContainer.asContext(), false); if (duration == 0) { // Case where we're in contextual on workspace (NORMAL), which by default has 0 // transition duration @@ -155,7 +156,7 @@ public class SplitInstructionsView extends LinearLayout { AnimatorSet stateAnim = stateManager.createAtomicAnimation( startState, NORMAL, config); AnimatorSet dismissAnim = splitSelectController.getSplitAnimationController() - .createPlaceholderDismissAnim(mLauncher, + .createPlaceholderDismissAnim(mContainer, LAUNCHER_SPLIT_SELECTION_EXIT_CANCEL_BUTTON, duration); stateAnim.play(dismissAnim); stateManager.setCurrentAnimation(stateAnim, NORMAL); @@ -163,10 +164,10 @@ public class SplitInstructionsView extends LinearLayout { } void ensureProperRotation() { - ((RecentsView) mLauncher.getOverviewPanel()).getPagedOrientationHandler() + ((RecentsView) mContainer.getOverviewPanel()).getPagedOrientationHandler() .setSplitInstructionsParams( this, - mLauncher.getDeviceProfile(), + mContainer.getDeviceProfile(), getMeasuredHeight(), getMeasuredWidth() ); diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java index 956dd263a2..fcbb45b9e2 100644 --- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java +++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java @@ -46,7 +46,6 @@ import androidx.annotation.Nullable; import com.android.app.animation.Interpolators; import com.android.launcher3.AbstractFloatingView; -import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; import com.android.launcher3.anim.AnimationSuccessListener; @@ -69,7 +68,7 @@ public class TaskMenuView extends AbstractFloatingView { private static final int REVEAL_OPEN_DURATION = enableOverviewIconMenu() ? 417 : 150; private static final int REVEAL_CLOSE_DURATION = enableOverviewIconMenu() ? 333 : 100; - private BaseDraggingActivity mActivity; + private RecentsViewContainer mContainer; private TextView mTaskName; @Nullable private AnimatorSet mOpenCloseAnimator; @@ -89,7 +88,7 @@ public class TaskMenuView extends AbstractFloatingView { public TaskMenuView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); - mActivity = BaseDraggingActivity.fromContext(context); + mContainer = RecentsViewContainer.containerFromContext(context); setClipToOutline(true); } @@ -103,7 +102,7 @@ public class TaskMenuView extends AbstractFloatingView { @Override public boolean onControllerInterceptTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { - BaseDragLayer dl = mActivity.getDragLayer(); + BaseDragLayer dl = mContainer.getDragLayer(); if (!dl.isEventOverView(this, ev)) { // TODO: log this once we have a new container type for it? close(true); @@ -141,7 +140,7 @@ public class TaskMenuView extends AbstractFloatingView { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (!(enableOverviewIconMenu() - && ((RecentsView) mActivity.getOverviewPanel()).isOnGridBottomRow(mTaskView))) { + && ((RecentsView) mContainer.getOverviewPanel()).isOnGridBottomRow(mTaskView))) { // TODO(b/326952853): Cap menu height for grid bottom row in a way that doesn't break // additionalTranslationY. int maxMenuHeight = calculateMaxHeight(); @@ -166,10 +165,10 @@ public class TaskMenuView extends AbstractFloatingView { public static boolean showForTask(TaskIdAttributeContainer taskContainer, @Nullable Runnable onClosingStartCallback) { - BaseDraggingActivity activity = BaseDraggingActivity.fromContext( + RecentsViewContainer container = RecentsViewContainer.containerFromContext( taskContainer.getTaskView().getContext()); - final TaskMenuView taskMenuView = (TaskMenuView) activity.getLayoutInflater().inflate( - R.layout.task_menu, activity.getDragLayer(), false); + final TaskMenuView taskMenuView = (TaskMenuView) container.getLayoutInflater().inflate( + R.layout.task_menu, container.getDragLayer(), false); taskMenuView.setOnClosingStartCallback(onClosingStartCallback); return taskMenuView.populateAndShowForTask(taskContainer); } @@ -182,7 +181,7 @@ public class TaskMenuView extends AbstractFloatingView { if (isAttachedToWindow()) { return false; } - mActivity.getDragLayer().addView(this); + mContainer.getDragLayer().addView(this); mTaskView = taskContainer.getTaskView(); mTaskContainer = taskContainer; if (!populateAndLayoutMenu()) { @@ -215,7 +214,7 @@ public class TaskMenuView extends AbstractFloatingView { } private void addMenuOption(SystemShortcut menuOption) { - LinearLayout menuOptionView = (LinearLayout) mActivity.getLayoutInflater().inflate( + LinearLayout menuOptionView = (LinearLayout) mContainer.getLayoutInflater().inflate( R.layout.task_view_menu_option, this, false); if (enableOverviewIconMenu()) { ((GradientDrawable) menuOptionView.getBackground()).setCornerRadius(0); @@ -224,7 +223,7 @@ public class TaskMenuView extends AbstractFloatingView { menuOptionView.findViewById(R.id.icon), menuOptionView.findViewById(R.id.text)); LayoutParams lp = (LayoutParams) menuOptionView.getLayoutParams(); mTaskView.getPagedOrientationHandler().setLayoutParamsForTaskMenuOptionItem(lp, - menuOptionView, mActivity.getDeviceProfile()); + menuOptionView, mContainer.getDeviceProfile()); // Set an onClick listener on each menu option. The onClick method is responsible for // ending LiveTile mode on the thumbnail if needed. menuOptionView.setOnClickListener(menuOption::onClick); @@ -232,19 +231,19 @@ public class TaskMenuView extends AbstractFloatingView { } private void orientAroundTaskView(TaskIdAttributeContainer taskContainer) { - RecentsView recentsView = mActivity.getOverviewPanel(); + RecentsView recentsView = mContainer.getOverviewPanel(); RecentsPagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler(); measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); // Get Position - DeviceProfile deviceProfile = mActivity.getDeviceProfile(); - mActivity.getDragLayer().getDescendantRectRelativeToSelf( + DeviceProfile deviceProfile = mContainer.getDeviceProfile(); + mContainer.getDragLayer().getDescendantRectRelativeToSelf( enableOverviewIconMenu() ? getIconView().findViewById(R.id.icon_view_menu_anchor) : taskContainer.getThumbnailView(), sTempRect); - Rect insets = mActivity.getDragLayer().getInsets(); + Rect insets = mContainer.getDragLayer().getInsets(); BaseDragLayer.LayoutParams params = (BaseDragLayer.LayoutParams) getLayoutParams(); params.width = orientationHandler.getTaskMenuWidth(taskContainer.getThumbnailView(), deviceProfile, taskContainer.getStagePosition()); @@ -325,12 +324,12 @@ public class TaskMenuView extends AbstractFloatingView { IconAppChipView iconAppChip = (IconAppChipView) mTaskContainer.getIconView().asView(); float additionalTranslationY = 0; - if (((RecentsView) mActivity.getOverviewPanel()).isOnGridBottomRow(mTaskView)) { + if (((RecentsView) mContainer.getOverviewPanel()).isOnGridBottomRow(mTaskView)) { // Animate menu up for enough room to display full menu when task on bottom row. float menuBottom = getHeight() + mMenuTranslationYBeforeOpen; float taskBottom = mTaskView.getHeight() + mTaskView.getPersistentTranslationY(); - float taskbarTop = mActivity.getDeviceProfile().heightPx - - mActivity.getDeviceProfile().getOverviewActionsClaimedSpaceBelow(); + float taskbarTop = mContainer.getDeviceProfile().heightPx + - mContainer.getDeviceProfile().getOverviewActionsClaimedSpaceBelow(); float midpoint = (taskBottom + taskbarTop) / 2f; additionalTranslationY = -Math.max(menuBottom - midpoint, 0); } @@ -345,11 +344,11 @@ public class TaskMenuView extends AbstractFloatingView { menuTranslationYAnim.setInterpolator(EMPHASIZED); float additionalTranslationX = 0; - if (mActivity.getDeviceProfile().isLandscape + if (mContainer.getDeviceProfile().isLandscape && mTaskContainer.getStagePosition() == STAGE_POSITION_BOTTOM_OR_RIGHT) { // Animate menu and icon when split task would display off the side of the screen. additionalTranslationX = Math.max( - getTranslationX() + getWidth() - (mActivity.getDeviceProfile().widthPx + getTranslationX() + getWidth() - (mContainer.getDeviceProfile().widthPx - getResources().getDimensionPixelSize( R.dimen.task_menu_edge_padding) * 2), 0); } @@ -410,7 +409,7 @@ public class TaskMenuView extends AbstractFloatingView { private void closeComplete() { testLogD(TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE, "TaskMenuView.java.closeComplete"); mIsOpen = false; - mActivity.getDragLayer().removeView(this); + mContainer.getDragLayer().removeView(this); mRevealAnimator = null; } @@ -433,7 +432,7 @@ public class TaskMenuView extends AbstractFloatingView { private int calculateMaxHeight() { float taskInsetMargin = getResources().getDimension(R.dimen.task_card_margin); return mTaskView.getPagedOrientationHandler().getTaskMenuHeight(taskInsetMargin, - mActivity.getDeviceProfile(), getTranslationX(), getTranslationY()); + mContainer.getDeviceProfile(), getTranslationX(), getTranslationY()); } private void setOnClosingStartCallback(Runnable onClosingStartCallback) { diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt index dcf681c345..c124f03228 100644 --- a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt +++ b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt @@ -29,7 +29,6 @@ import android.view.View import android.view.ViewGroup import android.widget.FrameLayout import android.widget.LinearLayout -import com.android.launcher3.BaseDraggingActivity import com.android.launcher3.DeviceProfile import com.android.launcher3.InsettableFrameLayout import com.android.launcher3.R @@ -40,24 +39,22 @@ import com.android.launcher3.util.Themes import com.android.quickstep.TaskOverlayFactory import com.android.quickstep.views.TaskView.TaskIdAttributeContainer -class TaskMenuViewWithArrow : ArrowPopup { +class TaskMenuViewWithArrow : ArrowPopup where T : RecentsViewContainer, T : Context { companion object { const val TAG = "TaskMenuViewWithArrow" - fun showForTask( + fun showForTask( taskContainer: TaskIdAttributeContainer, alignedOptionIndex: Int = 0 - ): Boolean { - val activity = - BaseDraggingActivity.fromContext( - taskContainer.taskView.context - ) + ): Boolean where T : RecentsViewContainer, T : Context { + val container: RecentsViewContainer = + RecentsViewContainer.containerFromContext(taskContainer.taskView.context) val taskMenuViewWithArrow = - activity.layoutInflater.inflate( + container.layoutInflater.inflate( R.layout.task_menu_with_arrow, - activity.dragLayer, + container.dragLayer, false - ) as TaskMenuViewWithArrow<*> + ) as TaskMenuViewWithArrow return taskMenuViewWithArrow.populateAndShowForTask(taskContainer, alignedOptionIndex) } diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java index 077247b09a..7e4673939a 100644 --- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java +++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java @@ -48,7 +48,6 @@ import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import androidx.core.graphics.ColorUtils; -import com.android.launcher3.BaseActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Utilities; import com.android.launcher3.util.MainThreadInitializedObject; @@ -122,7 +121,7 @@ public class TaskThumbnailView extends View { } }; - private final BaseActivity mActivity; + private final RecentsViewContainer mContainer; @Nullable private TaskOverlay mOverlay; private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -171,7 +170,7 @@ public class TaskThumbnailView extends View { mBackgroundPaint.setColor(Color.WHITE); mSplashBackgroundPaint.setColor(Color.WHITE); mClearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); - mActivity = BaseActivity.fromContext(context); + mContainer = RecentsViewContainer.containerFromContext(context); // Initialize with placeholder value. It is overridden later by TaskView mFullscreenParams = TEMP_PARAMS.get(context); @@ -308,7 +307,7 @@ public class TaskThumbnailView extends View { RectF boundsInBitmapSpace = new RectF(); boundsToBitmapSpace.mapRect(boundsInBitmapSpace, viewRect); - DeviceProfile dp = mActivity.getDeviceProfile(); + DeviceProfile dp = mContainer.getDeviceProfile(); int bottomInset = dp.isTablet ? Math.round(bitmapRect.bottom - boundsInBitmapSpace.bottom) : 0; return Insets.of(0, 0, 0, bottomInset); @@ -549,7 +548,7 @@ public class TaskThumbnailView extends View { } private void updateThumbnailMatrix() { - DeviceProfile dp = mActivity.getDeviceProfile(); + DeviceProfile dp = mContainer.getDeviceProfile(); mPreviewPositionHelper.setOrientationChanged(false); if (mBitmapShader != null && mThumbnailData != null) { mPreviewRect.set(0, 0, mThumbnailData.thumbnail.getWidth(), diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java index 6ff2a20125..ec571154a0 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/src/com/android/quickstep/views/TaskView.java @@ -87,7 +87,6 @@ import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.pm.UserCache; import com.android.launcher3.popup.SystemShortcut; -import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.testing.TestLogging; import com.android.launcher3.testing.shared.TestProtocol; import com.android.launcher3.util.ActivityOptionsWrapper; @@ -119,8 +118,6 @@ import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.QuickStepContract; -import kotlin.Unit; - import java.lang.annotation.Retention; import java.util.Arrays; import java.util.Collections; @@ -129,6 +126,8 @@ import java.util.List; import java.util.function.Consumer; import java.util.stream.Stream; +import kotlin.Unit; + /** * A task in the Recents view. */ @@ -335,7 +334,7 @@ public class TaskView extends FrameLayout implements Reusable { private float mNonGridScale = 1; private float mDismissScale = 1; protected final FullscreenDrawParams mCurrentFullscreenParams; - protected final StatefulActivity mActivity; + protected final RecentsViewContainer mContainer; // Various causes of changing primary translation, which we aggregate to setTranslationX/Y(). private float mDismissTranslationX; @@ -417,11 +416,11 @@ public class TaskView extends FrameLayout implements Reusable { int defStyleRes, BorderAnimator focusBorderAnimator, BorderAnimator hoverBorderAnimator) { super(context, attrs, defStyleAttr, defStyleRes); - mActivity = StatefulActivity.fromContext(context); + mContainer = RecentsViewContainer.containerFromContext(context); setOnClickListener(this::onClick); mCurrentFullscreenParams = new FullscreenDrawParams(context); - mDigitalWellBeingToast = new DigitalWellBeingToast(mActivity, this); + mDigitalWellBeingToast = new DigitalWellBeingToast(mContainer, this); boolean keyboardFocusHighlightEnabled = FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH.get() || Flags.enableFocusOutline(); @@ -487,7 +486,11 @@ public class TaskView extends FrameLayout implements Reusable { return getItemInfo(mTask); } - protected WorkspaceItemInfo getItemInfo(@Nullable Task task) { + /** + * Builds proto for logging + */ + @VisibleForTesting + public WorkspaceItemInfo getItemInfo(@Nullable Task task) { WorkspaceItemInfo stubInfo = new WorkspaceItemInfo(); stubInfo.itemType = LauncherSettings.Favorites.ITEM_TYPE_TASK; stubInfo.container = LauncherSettings.Favorites.CONTAINER_TASKSWITCHER; @@ -613,7 +616,7 @@ public class TaskView extends FrameLayout implements Reusable { float viewHalfHeight = view.getHeight() / 2f; tempCenterCoords[0] = viewHalfWidth; tempCenterCoords[1] = viewHalfHeight; - getDescendantCoordRelativeToAncestor(view.asView(), mActivity.getDragLayer(), + getDescendantCoordRelativeToAncestor(view.asView(), mContainer.getDragLayer(), tempCenterCoords, false); transformingTouchDelegate.setBounds( (int) (tempCenterCoords[0] - viewHalfWidth), @@ -813,13 +816,19 @@ public class TaskView extends FrameLayout implements Reusable { private void onClick(View view) { if (getTask() == null) { + Log.d("b/310064698", "onClick - task is null"); return; } if (confirmSecondSplitSelectApp()) { + Log.d("b/310064698", mTask + " - onClick - split select is active"); return; } - launchTasks(); - mActivity.getStatsLogManager().logger().withItemInfo(getItemInfo()) + RunnableList callbackList = launchTasks(); + Log.d("b/310064698", mTask + " - onClick - callbackList: " + callbackList); + if (callbackList != null) { + callbackList.add(() -> Log.d("b/310064698", mTask + " - onClick - launchCompleted")); + } + mContainer.getStatsLogManager().logger().withItemInfo(getItemInfo()) .log(LAUNCHER_TASK_LAUNCH_TAP); } @@ -861,7 +870,7 @@ public class TaskView extends FrameLayout implements Reusable { "TaskView.launchTaskAnimated: startActivityFromRecentsAsync"); TestLogging.recordEvent( TestProtocol.SEQUENCE_MAIN, "startActivityFromRecentsAsync", mTask); - ActivityOptionsWrapper opts = mActivity.getActivityLaunchOptions(this, null); + ActivityOptionsWrapper opts = mContainer.getActivityLaunchOptions(this, null); opts.options.setLaunchDisplayId( getDisplay() == null ? DEFAULT_DISPLAY : getDisplay().getDisplayId()); if (ActivityManagerWrapper.getInstance() @@ -919,7 +928,7 @@ public class TaskView extends FrameLayout implements Reusable { // We only listen for failures to launch in quickswitch because the during this // gesture launcher is in the background state, vs other launches which are in // the actual overview state - failureListener.register(mActivity, mTask.key.id, () -> { + failureListener.register(mContainer, mTask.key.id, () -> { notifyTaskLaunchFailed(TAG); RecentsView rv = getRecentsView(); if (rv != null) { @@ -1022,7 +1031,7 @@ public class TaskView extends FrameLayout implements Reusable { TaskViewUtils.composeRecentsLaunchAnimator( anim, this, targets.apps, targets.wallpapers, targets.nonApps, true /* launcherClosing */, - mActivity.getStateManager(), recentsView, + recentsView.getStateManager(), recentsView, recentsView.getDepthController()); anim.addListener(new AnimatorListenerAdapter() { @Override @@ -1133,12 +1142,12 @@ public class TaskView extends FrameLayout implements Reusable { return true; } - if (!mActivity.getDeviceProfile().isTablet + if (!mContainer.getDeviceProfile().isTablet && !getRecentsView().isClearAllHidden()) { getRecentsView().snapToPage(getRecentsView().indexOfChild(this)); return false; } else { - mActivity.getStatsLogManager().logger().withItemInfo(getItemInfo()) + mContainer.getStatsLogManager().logger().withItemInfo(getItemInfo()) .log(LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS); return showTaskMenuWithContainer(iconView); } @@ -1147,7 +1156,7 @@ public class TaskView extends FrameLayout implements Reusable { protected boolean showTaskMenuWithContainer(TaskViewIcon iconView) { TaskIdAttributeContainer menuContainer = mTaskIdAttributeContainer[iconView == mIconView ? 0 : 1]; - DeviceProfile dp = mActivity.getDeviceProfile(); + DeviceProfile dp = mContainer.getDeviceProfile(); if (enableOverviewIconMenu() && iconView instanceof IconAppChipView) { ((IconAppChipView) iconView).revealAnim(/* isRevealing= */ true); return TaskMenuView.showForTask(menuContainer, @@ -1201,7 +1210,7 @@ public class TaskView extends FrameLayout implements Reusable { } protected void setThumbnailOrientation(RecentsOrientedState orientationState) { - DeviceProfile deviceProfile = mActivity.getDeviceProfile(); + DeviceProfile deviceProfile = mContainer.getDeviceProfile(); int thumbnailTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx; // TODO(b/271468547), we should default to setting trasnlations only on the snapshot instead @@ -1218,7 +1227,7 @@ public class TaskView extends FrameLayout implements Reusable { * Returns whether the task is part of overview grid and not being focused. */ public boolean isGridTask() { - DeviceProfile deviceProfile = mActivity.getDeviceProfile(); + DeviceProfile deviceProfile = mContainer.getDeviceProfile(); return deviceProfile.isTablet && !isFocusedTask(); } @@ -1325,7 +1334,7 @@ public class TaskView extends FrameLayout implements Reusable { @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); - if (mActivity.getDeviceProfile().isTablet) { + if (mContainer.getDeviceProfile().isTablet) { setPivotX(getLayoutDirection() == LAYOUT_DIRECTION_RTL ? 0 : right - left); setPivotY(mSnapshotView.getTop()); } else { @@ -1682,10 +1691,10 @@ public class TaskView extends FrameLayout implements Reusable { mFullscreenProgress = progress; mIconView.setVisibility(progress < 1 ? VISIBLE : INVISIBLE); mSnapshotView.getTaskOverlay().setFullscreenProgress(progress); - + RecentsView recentsView = mContainer.getOverviewPanel(); // Animate icons and DWB banners in/out, except in QuickSwitch state, when tiles are // oversized and banner would look disproportionately large. - if (mActivity.getStateManager().getState() != BACKGROUND_APP) { + if (recentsView.getStateManager().getState() != BACKGROUND_APP) { setIconsAndBannersTransitionProgress(progress, true); } @@ -1719,7 +1728,7 @@ public class TaskView extends FrameLayout implements Reusable { float boxTranslationY; int expectedWidth; int expectedHeight; - DeviceProfile deviceProfile = mActivity.getDeviceProfile(); + DeviceProfile deviceProfile = mContainer.getDeviceProfile(); final int thumbnailPadding = deviceProfile.overviewTaskThumbnailTopMarginPx; final Rect lastComputedTaskSize = getRecentsView().getLastComputedTaskSize(); final int taskWidth = lastComputedTaskSize.width(); diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt index a7ed8a73b2..0de5f197ea 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt @@ -37,6 +37,7 @@ import com.android.launcher3.util.SplitConfigurationOptions import com.android.quickstep.RecentsModel import com.android.quickstep.SystemUiProxy import com.android.quickstep.util.SplitSelectStateController.SplitFromDesktopController +import com.android.quickstep.views.RecentsViewContainer import com.android.systemui.shared.recents.model.Task import com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50 import java.util.function.Consumer @@ -63,7 +64,7 @@ class SplitSelectStateControllerTest { private val statsLogger: StatsLogger = mock() private val stateManager: StateManager = mock() private val handler: Handler = mock() - private val context: StatefulActivity<*> = mock() + private val context: RecentsViewContainer = mock() private val recentsModel: RecentsModel = mock() private val pendingIntent: PendingIntent = mock() private val splitFromDesktopController: SplitFromDesktopController = mock() diff --git a/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java b/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java index 6a48b772a4..44c23ba9a2 100644 --- a/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java +++ b/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java @@ -23,9 +23,9 @@ import android.os.SystemProperties; import androidx.test.uiautomator.By; import androidx.test.uiautomator.Until; -import com.android.launcher3.Launcher; import com.android.launcher3.tapl.LaunchedAppState; import com.android.launcher3.ui.AbstractLauncherUiTest; +import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.quickstep.views.RecentsView; import org.junit.rules.RuleChain; @@ -34,7 +34,7 @@ import org.junit.rules.TestRule; /** * Base class for all instrumentation tests that deal with Quickstep. */ -public abstract class AbstractQuickStepTest extends AbstractLauncherUiTest { +public abstract class AbstractQuickStepTest extends AbstractLauncherUiTest { public static final boolean ENABLE_SHELL_TRANSITIONS = SystemProperties.getBoolean("persist.wm.debug.shell_transit", true); @Override @@ -46,7 +46,7 @@ public abstract class AbstractQuickStepTest extends AbstractLauncherUiTest { } @Override - protected void onLauncherActivityClose(Launcher launcher) { + protected void onLauncherActivityClose(QuickstepLauncher launcher) { RecentsView recentsView = launcher.getOverviewPanel(); if (recentsView != null) { recentsView.finishRecentsAnimation(false /* toRecents */, null); diff --git a/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt new file mode 100644 index 0000000000..7dabbca417 --- /dev/null +++ b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2024 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.quickstep + +import android.content.ComponentName +import android.content.Intent +import android.platform.test.flag.junit.SetFlagsRule +import com.android.launcher3.AbstractFloatingView +import com.android.launcher3.AbstractFloatingViewHelper +import com.android.launcher3.Launcher +import com.android.launcher3.logging.StatsLogManager +import com.android.launcher3.logging.StatsLogManager.LauncherEvent +import com.android.launcher3.model.data.WorkspaceItemInfo +import com.android.launcher3.uioverrides.QuickstepLauncher +import com.android.launcher3.util.SplitConfigurationOptions +import com.android.quickstep.views.LauncherRecentsView +import com.android.quickstep.views.TaskView +import com.android.systemui.shared.recents.model.Task +import com.android.systemui.shared.recents.model.Task.TaskKey +import com.android.window.flags.Flags +import com.google.common.truth.Truth.assertThat +import org.junit.Rule +import org.junit.Test +import org.mockito.kotlin.any +import org.mockito.kotlin.eq +import org.mockito.kotlin.mock +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + +/** Test for DesktopSystemShortcut */ +class DesktopSystemShortcutTest { + + @get:Rule val setFlagsRule = SetFlagsRule(SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT) + + private val launcher: QuickstepLauncher = mock() + private val statsLogManager: StatsLogManager = mock() + private val statsLogger: StatsLogManager.StatsLogger = mock() + private val recentsView: LauncherRecentsView = mock() + private val taskView: TaskView = mock() + private val workspaceItemInfo: WorkspaceItemInfo = mock() + private val abstractFloatingViewHelper: AbstractFloatingViewHelper = mock() + private val factory: TaskShortcutFactory = + DesktopSystemShortcut.createFactory(abstractFloatingViewHelper) + + @Test + fun createDesktopTaskShortcutFactory_featureOff() { + setFlagsRule.disableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + + val task = + Task(TaskKey(1, 0, Intent(), ComponentName("", ""), 0, 2000)).apply { + isDockable = true + } + val taskContainer = + taskView.TaskIdAttributeContainer( + task, + null, + null, + SplitConfigurationOptions.STAGE_POSITION_UNDEFINED + ) + + val shortcuts = factory.getShortcuts(launcher, taskContainer) + assertThat(shortcuts).isNull() + } + + @Test + fun createDesktopTaskShortcutFactory_undockable() { + setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + + val task = + Task(TaskKey(1, 0, Intent(), ComponentName("", ""), 0, 2000)).apply { + isDockable = false + } + val taskContainer = + taskView.TaskIdAttributeContainer( + task, + null, + null, + SplitConfigurationOptions.STAGE_POSITION_UNDEFINED + ) + + val shortcuts = factory.getShortcuts(launcher, taskContainer) + assertThat(shortcuts).isNull() + } + + @Test + fun desktopSystemShortcutClicked() { + setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + + val task = + Task(TaskKey(1, 0, Intent(), ComponentName("", ""), 0, 2000)).apply { + isDockable = true + } + val taskContainer = + taskView.TaskIdAttributeContainer( + task, + null, + null, + SplitConfigurationOptions.STAGE_POSITION_UNDEFINED + ) + + whenever(launcher.getOverviewPanel()).thenReturn(recentsView) + whenever(launcher.statsLogManager).thenReturn(statsLogManager) + whenever(statsLogManager.logger()).thenReturn(statsLogger) + whenever(statsLogger.withItemInfo(any())).thenReturn(statsLogger) + whenever(taskView.getItemInfo(task)).thenReturn(workspaceItemInfo) + whenever(recentsView.moveTaskToDesktop(any(), any())).thenAnswer { + val successCallback = it.getArgument(1) + successCallback.run() + } + + val shortcuts = factory.getShortcuts(launcher, taskContainer) + assertThat(shortcuts).hasSize(1) + assertThat(shortcuts!!.first()).isInstanceOf(DesktopSystemShortcut::class.java) + + val desktopShortcut = shortcuts.first() as DesktopSystemShortcut + + desktopShortcut.onClick(taskView) + + val allTypesExceptRebindSafe = + AbstractFloatingView.TYPE_ALL and AbstractFloatingView.TYPE_REBIND_SAFE.inv() + verify(abstractFloatingViewHelper).closeOpenViews(launcher, true, allTypesExceptRebindSafe) + verify(recentsView).moveTaskToDesktop(eq(taskContainer), any()) + verify(statsLogger).withItemInfo(workspaceItemInfo) + verify(statsLogger).log(LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_DESKTOP_TAP) + } +} diff --git a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java index 3f3b9eda1f..fa10b61ad4 100644 --- a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java +++ b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java @@ -27,6 +27,7 @@ import android.platform.test.annotations.PlatinumTest; import com.android.launcher3.tapl.OverviewTask.OverviewSplitTask; import com.android.launcher3.tapl.OverviewTaskMenu; import com.android.launcher3.ui.AbstractLauncherUiTest; +import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.util.rule.TestStabilityRule; import org.junit.Test; @@ -35,7 +36,7 @@ import org.junit.Test; * This test run in both Out of process (Oop) and in-process (Ipc). * Tests the app Icon in overview. */ -public class TaplOverviewIconTest extends AbstractLauncherUiTest { +public class TaplOverviewIconTest extends AbstractLauncherUiTest { private static final String CALCULATOR_APP_PACKAGE = resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR); diff --git a/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java b/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java new file mode 100644 index 0000000000..0c143b4b70 --- /dev/null +++ b/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2024 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.quickstep; + +import static com.android.launcher3.LauncherState.ALL_APPS; +import static com.android.launcher3.LauncherState.NORMAL; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; + +import android.util.Log; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.LargeTest; + +import com.android.launcher3.tapl.LauncherInstrumentation; + +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.IOException; +import java.util.Objects; + +@LargeTest +@RunWith(AndroidJUnit4.class) +public class TaplPrivateSpaceTest extends AbstractQuickStepTest { + + private int mProfileUserId; + private boolean mPrivateProfileSetupSuccessful; + private static final String TAG = "TaplPrivateSpaceTest"; + + @Override + public void setUp() throws Exception { + super.setUp(); + initialize(this); + + createAndStartPrivateProfileUser(); + assumeTrue("Private Profile Setup not successful, aborting", + mPrivateProfileSetupSuccessful); + + mDevice.pressHome(); + waitForLauncherCondition("Launcher didn't start", Objects::nonNull); + waitForStateTransitionToEnd("Launcher internal state didn't switch to Normal", + () -> NORMAL); + waitForResumed("Launcher internal state is still Background"); + mLauncher.getWorkspace().switchToAllApps(); + waitForStateTransitionToEnd("Launcher internal state didn't switch to All Apps", + () -> ALL_APPS); + + // Wait for Private Space being available in Launcher. + waitForPrivateSpaceSetup(); + // Wait for Launcher UI to be updated with Private Space Items. + waitForLauncherUIUpdate(); + } + + private void createAndStartPrivateProfileUser() { + String createUserOutput = executeShellCommand("pm create-user --profileOf 0 --user-type " + + "android.os.usertype.profile.PRIVATE LauncherPrivateProfile"); + updatePrivateProfileSetupSuccessful("pm create-user", createUserOutput); + String[] tokens = createUserOutput.split("\\s+"); + mProfileUserId = Integer.parseInt(tokens[tokens.length - 1]); + StringBuilder logStr = new StringBuilder().append("profileId: ").append(mProfileUserId); + for (String str : tokens) { + logStr.append(str).append("\n"); + } + String startUserOutput = executeShellCommand("am start-user " + mProfileUserId); + updatePrivateProfileSetupSuccessful("am start-user", startUserOutput); + } + + @After + public void removePrivateProfile() { + String output = executeShellCommand("pm remove-user " + mProfileUserId); + updateProfileRemovalSuccessful("pm remove-user", output); + waitForPrivateSpaceRemoval(); + } + + @Test + public void testPrivateSpaceContainerIsPresent() { + assumeTrue(mPrivateProfileSetupSuccessful); + // Scroll to the bottom of All Apps + executeOnLauncher(launcher -> launcher.getAppsView().resetAndScrollToPrivateSpaceHeader()); + waitForResumed("Launcher internal state is still Background"); + + // Verify Unlocked View elements are present. + assertNotNull("Private Space Unlocked View not found, or is not correct", + mLauncher.getAllApps().getPrivateSpaceUnlockedView()); + } + + private void waitForPrivateSpaceSetup() { + waitForLauncherCondition("Private Profile not setup", + launcher -> launcher.getAppsView().hasPrivateProfile(), + LauncherInstrumentation.WAIT_TIME_MS); + } + + private void waitForPrivateSpaceRemoval() { + waitForLauncherCondition("Private Profile not setup", + launcher -> !launcher.getAppsView().hasPrivateProfile(), + LauncherInstrumentation.WAIT_TIME_MS); + } + + private void waitForLauncherUIUpdate() { + // Wait for model thread completion as it may be processing + // the install event from the SystemService + mLauncher.waitForModelQueueCleared(); + // Wait for Launcher UI thread completion, as it may be processing updating the UI in + // response to the model update. Not that `waitForLauncherInitialized` is just a proxy + // method, we can use any method which touches Launcher UI thread, + mLauncher.waitForLauncherInitialized(); + } + + private void updatePrivateProfileSetupSuccessful(String cli, String output) { + Log.d(TAG, "updatePrivateProfileSetupSuccessful, cli=" + cli + " " + "output=" + + output); + mPrivateProfileSetupSuccessful = output.startsWith("Success"); + } + + private void updateProfileRemovalSuccessful(String cli, String output) { + Log.d(TAG, "updateProfileRemovalSuccessful, cli=" + cli + " " + "output=" + output); + assertTrue(output, output.startsWith("Success")); + } + + private String executeShellCommand(String command) { + try { + return mDevice.executeShellCommand(command); + } catch (IOException e) { + Log.e(TAG, "error running shell command", e); + throw new RuntimeException(e); + } + } +} diff --git a/quickstep/tests/src/com/android/quickstep/TaskViewTest.java b/quickstep/tests/src/com/android/quickstep/TaskViewTest.java index d744194d42..8eec9034ca 100644 --- a/quickstep/tests/src/com/android/quickstep/TaskViewTest.java +++ b/quickstep/tests/src/com/android/quickstep/TaskViewTest.java @@ -35,6 +35,7 @@ import android.view.MotionEvent; import androidx.test.filters.SmallTest; import com.android.launcher3.statemanager.StatefulActivity; +import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.quickstep.util.BorderAnimator; import com.android.quickstep.views.TaskView; @@ -47,7 +48,7 @@ import org.mockito.MockitoAnnotations; public class TaskViewTest { @Mock - private StatefulActivity mContext; + private QuickstepLauncher mContext; @Mock private Resources mResource; @Mock diff --git a/res/values/config.xml b/res/values/config.xml index 599584b64b..f820e763fb 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -78,6 +78,7 @@ + diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java index e7b88dc9b9..4ccf3dbdfb 100644 --- a/src/com/android/launcher3/AbstractFloatingView.java +++ b/src/com/android/launcher3/AbstractFloatingView.java @@ -278,18 +278,7 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch public static void closeOpenViews(ActivityContext activity, boolean animate, @FloatingViewType int type) { - BaseDragLayer dragLayer = activity.getDragLayer(); - // Iterate in reverse order. AbstractFloatingView is added later to the dragLayer, - // and will be one of the last views. - for (int i = dragLayer.getChildCount() - 1; i >= 0; i--) { - View child = dragLayer.getChildAt(i); - if (child instanceof AbstractFloatingView) { - AbstractFloatingView abs = (AbstractFloatingView) child; - if (abs.isOfType(type)) { - abs.close(animate); - } - } - } + new AbstractFloatingViewHelper().closeOpenViews(activity, animate, type); } public static void closeAllOpenViews(ActivityContext activity, boolean animate) { diff --git a/src/com/android/launcher3/AbstractFloatingViewHelper.kt b/src/com/android/launcher3/AbstractFloatingViewHelper.kt new file mode 100644 index 0000000000..0bfbc6e9fe --- /dev/null +++ b/src/com/android/launcher3/AbstractFloatingViewHelper.kt @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2024 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 + +import com.android.launcher3.AbstractFloatingView.FloatingViewType +import com.android.launcher3.views.ActivityContext + +/** + * Helper class for manaing AbstractFloatingViews which shows a floating UI on top of the launcher + * UI. + */ +class AbstractFloatingViewHelper { + fun closeOpenViews(activity: ActivityContext, animate: Boolean, @FloatingViewType type: Int) { + val dragLayer = activity.getDragLayer() + // Iterate in reverse order. AbstractFloatingView is added later to the dragLayer, + // and will be one of the last views. + for (i in dragLayer.getChildCount() - 1 downTo 0) { + val child = dragLayer.getChildAt(i) + if (child is AbstractFloatingView && child.isOfType(type)) { + child.close(animate) + } + } + } +} diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java index c7cdfa8c69..cf865288c4 100644 --- a/src/com/android/launcher3/AutoInstallsLayout.java +++ b/src/com/android/launcher3/AutoInstallsLayout.java @@ -52,7 +52,7 @@ import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.pm.UserCache; import com.android.launcher3.qsb.QsbContainerView; import com.android.launcher3.shortcuts.ShortcutKey; -import com.android.launcher3.uioverrides.ApiWrapper; +import com.android.launcher3.util.ApiWrapper; import com.android.launcher3.util.IntArray; import com.android.launcher3.util.Partner; import com.android.launcher3.util.Thunk; @@ -203,7 +203,7 @@ public class AutoInstallsLayout { mIdp = LauncherAppState.getIDP(context); mRowCount = mIdp.numRows; mColumnCount = mIdp.numColumns; - mActivityOverride = ApiWrapper.getActivityOverrides(context); + mActivityOverride = ApiWrapper.INSTANCE.get(context).getActivityOverrides(); } /** diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java index 1c2ed4343d..cf93a79c54 100644 --- a/src/com/android/launcher3/BaseDraggingActivity.java +++ b/src/com/android/launcher3/BaseDraggingActivity.java @@ -111,8 +111,6 @@ public abstract class BaseDraggingActivity extends BaseActivity return false; } - public abstract T getOverviewPanel(); - public abstract View getRootView(); public void returnToHomescreen() { diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index 3ddc7aa5e7..6cb33a8c29 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -63,13 +63,13 @@ import com.android.launcher3.responsive.ResponsiveCellSpecsProvider; import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType; import com.android.launcher3.responsive.ResponsiveSpec.DimensionType; import com.android.launcher3.responsive.ResponsiveSpecsProvider; -import com.android.launcher3.uioverrides.ApiWrapper; import com.android.launcher3.util.CellContentDimensions; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.DisplayController.Info; import com.android.launcher3.util.IconSizeSteps; import com.android.launcher3.util.ResourceHelper; import com.android.launcher3.util.WindowBounds; +import com.android.launcher3.util.window.WindowManagerProxy; import java.io.PrintWriter; import java.util.Locale; @@ -350,7 +350,8 @@ public class DeviceProfile { isTablet = info.isTablet(windowBounds); isPhone = !isTablet; isTwoPanels = isTablet && isMultiDisplay; - isTaskbarPresent = isTablet && ApiWrapper.TASKBAR_DRAWN_IN_PROCESS; + isTaskbarPresent = isTablet + && WindowManagerProxy.INSTANCE.get(context).isTaskbarDrawnInProcess(); // Some more constants. context = getContext(context, info, isVerticalBarLayout() || (isTablet && isLandscape) diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 3273f27731..d2d5ba995e 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -1551,7 +1551,13 @@ public class Launcher extends StatefulActivity LauncherAppWidgetInfo launcherInfo, CellPos presenterPos) { CellLayout cellLayout = getCellLayout(launcherInfo.container, presenterPos.screenId); - if (mStateManager.getState() == NORMAL) { + // We should wait until launcher is not animating to show resize frame so that + // {@link View#hasIdentityMatrix()} returns true (no scale effect) from CellLayout and + // Workspace (they are widget's parent view). Otherwise widget's + // {@link View#getLocationInWindow(int[])} will set skewed location, causing resize + // frame not showing at skewed location in + // {@link AppWidgetResizeFrame#snapToWidget(boolean)}. + if (mStateManager.getState() == NORMAL && !mStateManager.isInTransition()) { AppWidgetResizeFrame.showForWidget(launcherHostView, cellLayout); } else { mStateManager.addStateListener(new StateManager.StateListener() { @@ -1647,7 +1653,7 @@ public class Launcher extends StatefulActivity } else if (Intent.ACTION_ALL_APPS.equals(intent.getAction())) { showAllAppsFromIntent(alreadyOnHome); } else if (INTENT_ACTION_ALL_APPS_TOGGLE.equals(intent.getAction())) { - toggleAllAppsFromIntent(alreadyOnHome); + toggleAllAppsSearch(alreadyOnHome); } else if (Intent.ACTION_SHOW_WORK_APPS.equals(intent.getAction())) { showAllAppsWithSelectedTabFromIntent(alreadyOnHome, ActivityAllAppsContainerView.AdapterHolder.WORK); @@ -1661,7 +1667,12 @@ public class Launcher extends StatefulActivity // Overridden } - protected void toggleAllAppsFromIntent(boolean alreadyOnHome) { + /** Toggles Launcher All Apps with keyboard ready for search. */ + public void toggleAllAppsSearch() { + toggleAllAppsSearch(/* alreadyOnHome= */ true); + } + + protected void toggleAllAppsSearch(boolean alreadyOnHome) { if (getStateManager().isInStableState(ALL_APPS)) { getStateManager().goToState(NORMAL, alreadyOnHome); } else { @@ -2882,8 +2893,8 @@ public class Launcher extends StatefulActivity * Returns {@code true} if there are visible tasks with windowing mode set to * {@link android.app.WindowConfiguration#WINDOWING_MODE_FREEFORM} */ - public boolean areFreeformTasksVisible() { - return false; // Base launcher does not track freeform tasks + public boolean areDesktopTasksVisible() { + return false; // Base launcher does not track desktop tasks } // Getters and Setters diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index 60a6be6c9e..50a597d407 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -110,7 +110,7 @@ public class LauncherAppState implements SafeCloseable { mOnTerminateCallback.add(() -> mContext.getSystemService(LauncherApps.class).unregisterCallback(callbacks)); - if (Utilities.enableSupportForArchiving()) { + if (Flags.enableSupportForArchiving()) { ArchiveCompatibilityParams params = new ArchiveCompatibilityParams(); params.setEnableUnarchivalConfirmation(false); launcherApps.setArchiveCompatibility(params); diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index d44438f5bc..2b886e4570 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -830,10 +830,4 @@ public final class Utilities { // No-Op } } - - /** Encapsulates two flag checks into a single one. */ - public static boolean enableSupportForArchiving() { - return Flags.enableSupportForArchiving() - || getSystemProperty("pm.archiving.enabled", "false").equals("true"); - } } diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java index be120cce75..1def8a33ac 100644 --- a/src/com/android/launcher3/allapps/PrivateProfileManager.java +++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java @@ -72,7 +72,7 @@ import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.PrivateSpaceInstallAppButtonInfo; import com.android.launcher3.pm.UserCache; -import com.android.launcher3.uioverrides.ApiWrapper; +import com.android.launcher3.util.ApiWrapper; import com.android.launcher3.util.Preconditions; import com.android.launcher3.util.SettingsCache; import com.android.launcher3.views.ActivityContext; @@ -122,7 +122,9 @@ public class PrivateProfileManager extends UserProfileManager { super(userManager, statsLogManager, userCache); mAllApps = allApps; mPrivateProfileMatcher = (user) -> userCache.getUserInfo(user).isPrivate(); - UI_HELPER_EXECUTOR.post(this::initializeInBackgroundThread); + + Context appContext = allApps.getContext().getApplicationContext(); + UI_HELPER_EXECUTOR.post(() -> initializeInBackgroundThread(appContext)); mPsHeaderHeight = mAllApps.getContext().getResources().getDimensionPixelSize( R.dimen.ps_header_height); } @@ -187,7 +189,7 @@ public class PrivateProfileManager extends UserProfileManager { /** Whether private profile should be hidden on Launcher. */ public boolean isPrivateSpaceHidden() { return getCurrentState() == STATE_DISABLED && SettingsCache.INSTANCE - .get(mAllApps.mActivityContext).getValue(PRIVATE_SPACE_HIDE_WHEN_LOCKED_URI, 0); + .get(mAllApps.getContext()).getValue(PRIVATE_SPACE_HIDE_WHEN_LOCKED_URI, 0); } /** @@ -215,8 +217,8 @@ public class PrivateProfileManager extends UserProfileManager { /** Opens the Private Space Settings Page. */ public void openPrivateSpaceSettings() { if (mPrivateSpaceSettingsAvailable) { - mAllApps.getContext() - .startActivity(ApiWrapper.getPrivateSpaceSettingsIntent(mAllApps.getContext())); + mAllApps.getContext().startActivity( + ApiWrapper.INSTANCE.get(mAllApps.getContext()).getPrivateSpaceSettingsIntent()); } } @@ -239,33 +241,17 @@ public class PrivateProfileManager extends UserProfileManager { * This case should still be ok, as locking the Private Space container and unlocking it, * reloads the values, fixing the incorrect UI. */ - private void initializeInBackgroundThread() { + private void initializeInBackgroundThread(Context appContext) { Preconditions.assertNonUiThread(); - setPreInstalledSystemPackages(); - setAppInstallerIntent(); - initializePrivateSpaceSettingsState(); - } - - private void initializePrivateSpaceSettingsState() { - Preconditions.assertNonUiThread(); - Intent psSettingsIntent = ApiWrapper.getPrivateSpaceSettingsIntent(mAllApps.getContext()); - setPrivateSpaceSettingsAvailable(psSettingsIntent != null); - } - - private void setPreInstalledSystemPackages() { - Preconditions.assertNonUiThread(); - if (getProfileUser() != null) { - mPreInstalledSystemPackages = new HashSet<>(ApiWrapper - .getPreInstalledSystemPackages(mAllApps.getContext(), getProfileUser())); - } - } - - private void setAppInstallerIntent() { - Preconditions.assertNonUiThread(); - if (getProfileUser() != null) { - mAppInstallerIntent = ApiWrapper.getAppMarketActivityIntent(mAllApps.getContext(), - BuildConfig.APPLICATION_ID, getProfileUser()); + ApiWrapper apiWrapper = ApiWrapper.INSTANCE.get(appContext); + UserHandle profileUser = getProfileUser(); + if (profileUser != null) { + mPreInstalledSystemPackages = new HashSet<>( + apiWrapper.getPreInstalledSystemPackages(profileUser)); + mAppInstallerIntent = apiWrapper + .getAppMarketActivityIntent(BuildConfig.APPLICATION_ID, profileUser); } + setPrivateSpaceSettingsAvailable(apiWrapper.getPrivateSpaceSettingsIntent() != null); } @VisibleForTesting diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java index 29aa216a3b..05fdcef461 100644 --- a/src/com/android/launcher3/dragndrop/AddItemActivity.java +++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java @@ -67,7 +67,7 @@ import com.android.launcher3.model.WidgetsModel; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.PackageItemInfo; import com.android.launcher3.pm.PinRequestHelper; -import com.android.launcher3.uioverrides.ApiWrapper; +import com.android.launcher3.util.ApiWrapper; import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.SystemUiController; import com.android.launcher3.views.AbstractSlideInView; @@ -259,7 +259,8 @@ public class AddItemActivity extends BaseActivity .setPackage(getPackageName()) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); Launcher.ACTIVITY_TRACKER.registerCallback(listener, "AddItemActivity.onLongClick"); - startActivity(homeIntent, ApiWrapper.createFadeOutAnimOptions(this).toBundle()); + startActivity(homeIntent, + ApiWrapper.INSTANCE.get(this).createFadeOutAnimOptions().toBundle()); logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_DRAGGED); mFinishOnPause = true; return false; diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java index 1633eba5e1..af704a88f0 100644 --- a/src/com/android/launcher3/icons/IconCache.java +++ b/src/com/android/launcher3/icons/IconCache.java @@ -51,6 +51,7 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.core.util.Pair; +import com.android.launcher3.Flags; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.Utilities; import com.android.launcher3.icons.ComponentWithLabel.ComponentCachingLogic; @@ -248,7 +249,7 @@ public class IconCache extends BaseIconCache { @SuppressWarnings("NewApi") public synchronized void getTitleAndIcon(ItemInfoWithIcon info, LauncherActivityInfo activityInfo, boolean useLowResIcon) { - boolean isAppArchived = Utilities.enableSupportForArchiving() && activityInfo != null + boolean isAppArchived = Flags.enableSupportForArchiving() && activityInfo != null && activityInfo.getActivityInfo().isArchived; // If we already have activity info, no need to use package icon getTitleAndIcon(info, () -> activityInfo, isAppArchived, useLowResIcon, diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java index e8f8ae25ea..441bbb579d 100644 --- a/src/com/android/launcher3/logging/StatsLogManager.java +++ b/src/com/android/launcher3/logging/StatsLogManager.java @@ -218,6 +218,9 @@ public class StatsLogManager implements ResourceBasedOverride { @UiEvent(doc = "User tapped on free form icon on a task menu.") LAUNCHER_SYSTEM_SHORTCUT_FREE_FORM_TAP(519), + @UiEvent(doc = "User tapped on desktop icon on a task menu.") + LAUNCHER_SYSTEM_SHORTCUT_DESKTOP_TAP(1706), + @UiEvent(doc = "User tapped on pause app system shortcut.") LAUNCHER_SYSTEM_SHORTCUT_PAUSE_TAP(521), diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java index 8659471d27..8c5ea79034 100644 --- a/src/com/android/launcher3/model/AllAppsList.java +++ b/src/com/android/launcher3/model/AllAppsList.java @@ -33,6 +33,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.launcher3.AppFilter; +import com.android.launcher3.Flags; import com.android.launcher3.Utilities; import com.android.launcher3.compat.AlphabeticIndexCompat; import com.android.launcher3.icons.IconCache; @@ -330,7 +331,7 @@ public class AllAppsList { PackageManagerHelper.getLoadingProgress(info), PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING); applicationInfo.intent = launchIntent; - if (Utilities.enableSupportForArchiving()) { + if (Flags.enableSupportForArchiving()) { // In case an app is archived, the respective item flag corresponding to // archiving should also be applied during package updates if (info.getActivityInfo().isArchived) { diff --git a/src/com/android/launcher3/model/ItemInstallQueue.java b/src/com/android/launcher3/model/ItemInstallQueue.java index d35087980a..90aba2a2de 100644 --- a/src/com/android/launcher3/model/ItemInstallQueue.java +++ b/src/com/android/launcher3/model/ItemInstallQueue.java @@ -40,6 +40,7 @@ import android.util.Pair; import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; +import com.android.launcher3.Flags; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; @@ -300,7 +301,7 @@ public class ItemInstallQueue { } else { lai = laiList.get(0); si.intent = makeLaunchIntent(lai); - if (Utilities.enableSupportForArchiving() + if (Flags.enableSupportForArchiving() && lai.getActivityInfo().isArchived) { si.runtimeStatusFlags |= FLAG_ARCHIVED; } diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index e0ced83855..ac4c087e02 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -421,7 +421,7 @@ public class LoaderTask implements Runnable { final HashMap installingPkgs = mSessionHelper.getActiveSessions(); - if (Utilities.enableSupportForArchiving()) { + if (Flags.enableSupportForArchiving()) { mInstallingPkgsCached = installingPkgs; } installingPkgs.forEach(mApp.getIconCache()::updateSessionCache); @@ -695,7 +695,7 @@ public class LoaderTask implements Runnable { for (int i = 0; i < apps.size(); i++) { LauncherActivityInfo app = apps.get(i); AppInfo appInfo = new AppInfo(app, mUserCache.getUserInfo(user), quietMode); - if (Utilities.enableSupportForArchiving() && app.getApplicationInfo().isArchived) { + if (Flags.enableSupportForArchiving() && app.getApplicationInfo().isArchived) { // For archived apps, include progress info in case there is a pending // install session post restart of device. String appPackageName = app.getApplicationInfo().packageName; diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java index ea1ae2ed24..19230654c6 100644 --- a/src/com/android/launcher3/model/PackageUpdatedTask.java +++ b/src/com/android/launcher3/model/PackageUpdatedTask.java @@ -48,7 +48,7 @@ import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.pm.PackageInstallInfo; import com.android.launcher3.pm.UserCache; import com.android.launcher3.shortcuts.ShortcutRequest; -import com.android.launcher3.uioverrides.ApiWrapper; +import com.android.launcher3.util.ApiWrapper; import com.android.launcher3.util.FlagOp; import com.android.launcher3.util.IntSet; import com.android.launcher3.util.ItemInfoMatcher; @@ -276,7 +276,7 @@ public class PackageUpdatedTask extends BaseModelUpdateTask { PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING); // In case an app is archived, we need to make sure that archived state // in WorkspaceItemInfo is refreshed. - if (Utilities.enableSupportForArchiving() && !activities.isEmpty()) { + if (Flags.enableSupportForArchiving() && !activities.isEmpty()) { boolean newArchivalState = activities.get( 0).getActivityInfo().isArchived; if (newArchivalState != si.isArchived()) { @@ -286,7 +286,7 @@ public class PackageUpdatedTask extends BaseModelUpdateTask { } if (si.itemType == Favorites.ITEM_TYPE_APPLICATION) { if (activities != null && !activities.isEmpty()) { - si.status = ApiWrapper + si.status = ApiWrapper.INSTANCE.get(context) .isNonResizeableActivity(activities.get(0)) ? si.status | WorkspaceItemInfo.FLAG_NON_RESIZEABLE : si.status & ~WorkspaceItemInfo.FLAG_NON_RESIZEABLE; diff --git a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt index a900d1fa55..ee45c0f8e2 100644 --- a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt +++ b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt @@ -26,6 +26,7 @@ import android.graphics.Point import android.text.TextUtils import android.util.Log import android.util.LongSparseArray +import com.android.launcher3.Flags import com.android.launcher3.InvariantDeviceProfile import com.android.launcher3.LauncherAppState import com.android.launcher3.LauncherSettings.Favorites @@ -41,7 +42,7 @@ import com.android.launcher3.model.data.LauncherAppWidgetInfo import com.android.launcher3.model.data.WorkspaceItemInfo import com.android.launcher3.pm.PackageInstallInfo import com.android.launcher3.shortcuts.ShortcutKey -import com.android.launcher3.uioverrides.ApiWrapper +import com.android.launcher3.util.ApiWrapper import com.android.launcher3.util.ComponentKey import com.android.launcher3.util.PackageManagerHelper import com.android.launcher3.util.PackageUserKey @@ -325,7 +326,7 @@ class WorkspaceItemProcessor( } val activityInfo = c.launcherActivityInfo if (activityInfo != null) { - if (ApiWrapper.isNonResizeableActivity(activityInfo)) { + if (ApiWrapper.INSTANCE.get(app.context).isNonResizeableActivity(activityInfo)) { info.status = info.status or WorkspaceItemInfo.FLAG_NON_RESIZEABLE } info.setProgressLevel( @@ -335,7 +336,7 @@ class WorkspaceItemProcessor( } if ( (c.restoreFlag != 0 || - Utilities.enableSupportForArchiving() && + Flags.enableSupportForArchiving() && activityInfo != null && activityInfo.applicationInfo.isArchived) && !TextUtils.isEmpty(targetPkg) ) { @@ -347,7 +348,7 @@ class WorkspaceItemProcessor( ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE.inv() } else if ( activityInfo == null || - (Utilities.enableSupportForArchiving() && + (Flags.enableSupportForArchiving() && activityInfo.applicationInfo.isArchived) ) { // For archived apps, include progress info in case there is @@ -479,7 +480,7 @@ class WorkspaceItemProcessor( !isSafeMode && (si == null) && (lapi == null) && - !(Utilities.enableSupportForArchiving() && + !(Flags.enableSupportForArchiving() && pmHelper.isAppArchived(component.packageName)) ) { // Restore never started diff --git a/src/com/android/launcher3/model/data/AppInfo.java b/src/com/android/launcher3/model/data/AppInfo.java index 210d720bca..93ba619099 100644 --- a/src/com/android/launcher3/model/data/AppInfo.java +++ b/src/com/android/launcher3/model/data/AppInfo.java @@ -181,7 +181,7 @@ public class AppInfo extends ItemInfoWithIcon implements WorkspaceItemFactory { if (PackageManagerHelper.isAppSuspended(appInfo)) { info.runtimeStatusFlags |= FLAG_DISABLED_SUSPENDED; } - if (Utilities.enableSupportForArchiving() && lai.getActivityInfo().isArchived) { + if (Flags.enableSupportForArchiving() && lai.getActivityInfo().isArchived) { info.runtimeStatusFlags |= FLAG_ARCHIVED; } info.runtimeStatusFlags |= (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0 diff --git a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java index be3aa101ac..3a74ff236d 100644 --- a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java +++ b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java @@ -22,13 +22,14 @@ import android.os.Process; import androidx.annotation.Nullable; +import com.android.launcher3.Flags; import com.android.launcher3.Utilities; import com.android.launcher3.icons.BitmapInfo; import com.android.launcher3.icons.BitmapInfo.DrawableCreationFlags; import com.android.launcher3.icons.FastBitmapDrawable; import com.android.launcher3.logging.FileLog; import com.android.launcher3.pm.PackageInstallInfo; -import com.android.launcher3.uioverrides.ApiWrapper; +import com.android.launcher3.util.ApiWrapper; /** * Represents an ItemInfo which also holds an icon. @@ -162,7 +163,7 @@ public abstract class ItemInfoWithIcon extends ItemInfo { * Returns true if the app corresponding to the item is archived. */ public boolean isArchived() { - if (!Utilities.enableSupportForArchiving()) { + if (!Flags.enableSupportForArchiving()) { return false; } return (runtimeStatusFlags & FLAG_ARCHIVED) != 0; @@ -251,8 +252,8 @@ public abstract class ItemInfoWithIcon extends ItemInfo { String targetPackage = getTargetPackage(); return targetPackage != null - ? ApiWrapper.getAppMarketActivityIntent( - context, targetPackage, Process.myUserHandle()) + ? ApiWrapper.INSTANCE.get(context).getAppMarketActivityIntent( + targetPackage, Process.myUserHandle()) : null; } diff --git a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java index 9917ad7a64..5ae70039ab 100644 --- a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java +++ b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java @@ -32,7 +32,7 @@ import com.android.launcher3.Utilities; import com.android.launcher3.icons.IconCache; import com.android.launcher3.pm.UserCache; import com.android.launcher3.shortcuts.ShortcutKey; -import com.android.launcher3.uioverrides.ApiWrapper; +import com.android.launcher3.util.ApiWrapper; import com.android.launcher3.util.ContentWriter; import java.util.Arrays; @@ -201,7 +201,7 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { runtimeStatusFlags &= ~FLAG_DISABLED_VERSION_LOWER; } - Person[] persons = ApiWrapper.getPersons(shortcutInfo); + Person[] persons = ApiWrapper.INSTANCE.get(context).getPersons(shortcutInfo); personKeys = persons.length == 0 ? Utilities.EMPTY_STRING_ARRAY : Arrays.stream(persons).map(Person::getKey).sorted().toArray(String[]::new); } diff --git a/src/com/android/launcher3/pm/InstallSessionHelper.java b/src/com/android/launcher3/pm/InstallSessionHelper.java index f3769d535f..4a3318e834 100644 --- a/src/com/android/launcher3/pm/InstallSessionHelper.java +++ b/src/com/android/launcher3/pm/InstallSessionHelper.java @@ -29,6 +29,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; +import com.android.launcher3.Flags; import com.android.launcher3.LauncherPrefs; import com.android.launcher3.SessionCommitReceiver; import com.android.launcher3.Utilities; @@ -217,7 +218,7 @@ public class InstallSessionHelper { && !promiseIconAddedForId(sessionInfo.getSessionId())) { // In case of unarchival, we do not want to add a workspace promise icon if one is // not already present. For general app installations however, we do support it. - if (!Utilities.enableSupportForArchiving() || !sessionInfo.isUnarchival()) { + if (!Flags.enableSupportForArchiving() || !sessionInfo.isUnarchival()) { FileLog.d(LOG, "Adding package name to install queue: " + sessionInfo.getAppPackageName()); @@ -232,7 +233,7 @@ public class InstallSessionHelper { public boolean verifySessionInfo(@Nullable final PackageInstaller.SessionInfo sessionInfo) { // For archived apps we always want to show promise icons and the checks below don't apply. - if (Utilities.enableSupportForArchiving() && sessionInfo != null + if (Flags.enableSupportForArchiving() && sessionInfo != null && sessionInfo.isUnarchival()) { return true; } diff --git a/src/com/android/launcher3/pm/InstallSessionTracker.java b/src/com/android/launcher3/pm/InstallSessionTracker.java index eacbc11821..24d58f3e98 100644 --- a/src/com/android/launcher3/pm/InstallSessionTracker.java +++ b/src/com/android/launcher3/pm/InstallSessionTracker.java @@ -31,6 +31,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; +import com.android.launcher3.Flags; import com.android.launcher3.Utilities; import com.android.launcher3.util.PackageUserKey; @@ -80,7 +81,7 @@ public class InstallSessionTracker extends PackageInstaller.SessionCallback { helper.tryQueuePromiseAppIcon(sessionInfo); - if (Utilities.enableSupportForArchiving() && sessionInfo != null + if (Flags.enableSupportForArchiving() && sessionInfo != null && sessionInfo.isUnarchival()) { // For archived apps, icon could already be present on the workspace. To make sure // the icon state is updated, we send a change event. diff --git a/src/com/android/launcher3/pm/UserCache.java b/src/com/android/launcher3/pm/UserCache.java index 032de31ed7..185e0b55bd 100644 --- a/src/com/android/launcher3/pm/UserCache.java +++ b/src/com/android/launcher3/pm/UserCache.java @@ -17,7 +17,6 @@ package com.android.launcher3.pm; import static com.android.launcher3.Utilities.ATLEAST_U; -import static com.android.launcher3.uioverrides.ApiWrapper.queryAllUsers; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; import android.content.Context; @@ -34,6 +33,7 @@ import androidx.annotation.WorkerThread; import com.android.launcher3.icons.BitmapInfo; import com.android.launcher3.icons.UserBadgeDrawable; +import com.android.launcher3.util.ApiWrapper; import com.android.launcher3.util.FlagOp; import com.android.launcher3.util.MainThreadInitializedObject; import com.android.launcher3.util.SafeCloseable; @@ -119,7 +119,7 @@ public class UserCache implements SafeCloseable { @WorkerThread private void updateCache() { - mUserToSerialMap = queryAllUsers(mContext); + mUserToSerialMap = ApiWrapper.INSTANCE.get(mContext).queryAllUsers(); } /** diff --git a/src/com/android/launcher3/popup/RemoteActionShortcut.java b/src/com/android/launcher3/popup/RemoteActionShortcut.java index 688da4934f..0860ae5743 100644 --- a/src/com/android/launcher3/popup/RemoteActionShortcut.java +++ b/src/com/android/launcher3/popup/RemoteActionShortcut.java @@ -33,22 +33,22 @@ import android.widget.TextView; import android.widget.Toast; import com.android.launcher3.AbstractFloatingView; -import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.views.ActivityContext; import java.lang.ref.WeakReference; -public class RemoteActionShortcut extends SystemShortcut { +public class RemoteActionShortcut extends SystemShortcut { private static final String TAG = "RemoteActionShortcut"; private static final boolean DEBUG = Utilities.IS_DEBUG_DEVICE; private final RemoteAction mAction; public RemoteActionShortcut(RemoteAction action, - BaseDraggingActivity activity, ItemInfo itemInfo, View originalView) { - super(0, R.id.action_remote_action_shortcut, activity, itemInfo, originalView); + T context, ItemInfo itemInfo, View originalView) { + super(0, R.id.action_remote_action_shortcut, context, itemInfo, originalView); mAction = action; } @@ -80,7 +80,7 @@ public class RemoteActionShortcut extends SystemShortcut { mTarget.getStatsLogManager().logger().withItemInfo(mItemInfo) .log(LAUNCHER_SYSTEM_SHORTCUT_PAUSE_TAP); - final WeakReference weakTarget = new WeakReference<>(mTarget); + final WeakReference weakTarget = new WeakReference<>(mTarget); final String actionIdentity = mAction.getTitle() + ", " + mItemInfo.getTargetComponent().getPackageName(); @@ -95,7 +95,7 @@ public class RemoteActionShortcut extends SystemShortcut { mItemInfo.getTargetComponent().getPackageName()), (pendingIntent, intent, resultCode, resultData, resultExtras) -> { if (DEBUG) Log.d(TAG, "Action is complete: " + actionIdentity); - final BaseDraggingActivity target = weakTarget.get(); + final T target = weakTarget.get(); if (resultData != null && !resultData.isEmpty()) { Log.e(TAG, "Remote action returned result: " + actionIdentity + " : " + resultData); diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java index 0af7e677ed..f56d732aa6 100644 --- a/src/com/android/launcher3/popup/SystemShortcut.java +++ b/src/com/android/launcher3/popup/SystemShortcut.java @@ -22,6 +22,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.launcher3.AbstractFloatingView; +import com.android.launcher3.AbstractFloatingViewHelper; import com.android.launcher3.Flags; import com.android.launcher3.R; import com.android.launcher3.SecondaryDropTarget; @@ -31,7 +32,7 @@ import com.android.launcher3.model.WidgetItem; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.pm.UserCache; -import com.android.launcher3.uioverrides.ApiWrapper; +import com.android.launcher3.util.ApiWrapper; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.InstantAppResolver; import com.android.launcher3.util.PackageManagerHelper; @@ -61,23 +62,23 @@ public abstract class SystemShortcut extends ItemInfo protected final ItemInfo mItemInfo; protected final View mOriginalView; + private final AbstractFloatingViewHelper mAbstractFloatingViewHelper; + public SystemShortcut(int iconResId, int labelResId, T target, ItemInfo itemInfo, View originalView) { + this(iconResId, labelResId, target, itemInfo, originalView, + new AbstractFloatingViewHelper()); + } + + public SystemShortcut(int iconResId, int labelResId, T target, ItemInfo itemInfo, + View originalView, AbstractFloatingViewHelper abstractFloatingViewHelper) { mIconResId = iconResId; mLabelResId = labelResId; mAccessibilityActionId = labelResId; mTarget = target; mItemInfo = itemInfo; mOriginalView = originalView; - } - - public SystemShortcut(SystemShortcut other) { - mIconResId = other.mIconResId; - mLabelResId = other.mLabelResId; - mAccessibilityActionId = other.mAccessibilityActionId; - mTarget = other.mTarget; - mItemInfo = other.mItemInfo; - mOriginalView = other.mOriginalView; + mAbstractFloatingViewHelper = abstractFloatingViewHelper; } public void setIconAndLabelFor(View iconView, TextView labelView) { @@ -178,7 +179,7 @@ public abstract class SystemShortcut extends ItemInfo @Override public void onClick(View view) { - dismissTaskMenuView(mTarget); + dismissTaskMenuView(); Rect sourceBounds = Utilities.getViewBounds(view); new PackageManagerHelper(view.getContext()).startDetailsActivityForInfo( mItemInfo, sourceBounds, ActivityOptions.makeBasic().toBundle()); @@ -259,10 +260,8 @@ public abstract class SystemShortcut extends ItemInfo @Override public void onClick(View view) { Intent intent = - ApiWrapper.getAppMarketActivityIntent( - view.getContext(), - mItemInfo.getTargetComponent().getPackageName(), - mSpaceUser); + ApiWrapper.INSTANCE.get(view.getContext()).getAppMarketActivityIntent( + mItemInfo.getTargetComponent().getPackageName(), mSpaceUser); mTarget.startActivitySafely(view, intent, mItemInfo); AbstractFloatingView.closeAllOpenViews(mTarget); mTarget.getStatsLogManager() @@ -303,9 +302,8 @@ public abstract class SystemShortcut extends ItemInfo @Override public void onClick(View view) { - Intent intent = ApiWrapper.getAppMarketActivityIntent(view.getContext(), - mItemInfo.getTargetComponent().getPackageName(), - Process.myUserHandle()); + Intent intent = ApiWrapper.INSTANCE.get(view.getContext()).getAppMarketActivityIntent( + mItemInfo.getTargetComponent().getPackageName(), Process.myUserHandle()); mTarget.startActivitySafely(view, intent, mItemInfo); AbstractFloatingView.closeAllOpenViews(mTarget); } @@ -327,7 +325,7 @@ public abstract class SystemShortcut extends ItemInfo @Override public void onClick(View view) { - dismissTaskMenuView(mTarget); + dismissTaskMenuView(); mTarget.getStatsLogManager().logger() .withItemInfo(mItemInfo) .log(LAUNCHER_SYSTEM_SHORTCUT_DONT_SUGGEST_APP_TAP); @@ -370,7 +368,7 @@ public abstract class SystemShortcut extends ItemInfo @Override public void onClick(View view) { - dismissTaskMenuView(mTarget); + dismissTaskMenuView(); SecondaryDropTarget.performUninstall(view.getContext(), mComponentName, mItemInfo); mTarget.getStatsLogManager() .logger() @@ -379,8 +377,8 @@ public abstract class SystemShortcut extends ItemInfo } } - public static void dismissTaskMenuView(T activity) { - AbstractFloatingView.closeOpenViews(activity, true, + protected void dismissTaskMenuView() { + mAbstractFloatingViewHelper.closeOpenViews(mTarget, true, AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE); } } diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java index b4e6365d66..d702e51881 100644 --- a/src/com/android/launcher3/provider/RestoreDbTask.java +++ b/src/com/android/launcher3/provider/RestoreDbTask.java @@ -70,7 +70,7 @@ import com.android.launcher3.model.data.LauncherAppWidgetInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.pm.UserCache; import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction; -import com.android.launcher3.uioverrides.ApiWrapper; +import com.android.launcher3.util.ApiWrapper; import com.android.launcher3.util.ContentWriter; import com.android.launcher3.util.IntArray; import com.android.launcher3.util.LogConfig; @@ -560,9 +560,8 @@ public class RestoreDbTask { protected static void maybeOverrideShortcuts(Context context, ModelDbController controller, SQLiteDatabase db, long currentUser) { - Map activityOverrides = ApiWrapper.getActivityOverrides( - context); - + Map activityOverrides = + ApiWrapper.INSTANCE.get(context).getActivityOverrides(); if (activityOverrides == null || activityOverrides.isEmpty()) { return; } diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java index 910b0293ec..0299a23382 100644 --- a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java +++ b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java @@ -199,11 +199,6 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity return mAppsView; } - @Override - public T getOverviewPanel() { - return null; - } - @Override public View getRootView() { return mDragLayer; diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java index 50df7757ec..2a9ebbd962 100644 --- a/src/com/android/launcher3/touch/ItemClickHandler.java +++ b/src/com/android/launcher3/touch/ItemClickHandler.java @@ -41,6 +41,7 @@ import android.widget.Toast; import com.android.launcher3.BubbleTextView; import com.android.launcher3.BuildConfig; +import com.android.launcher3.Flags; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherSettings; @@ -63,7 +64,7 @@ import com.android.launcher3.pm.InstallSessionHelper; import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.testing.TestLogging; import com.android.launcher3.testing.shared.TestProtocol; -import com.android.launcher3.uioverrides.ApiWrapper; +import com.android.launcher3.util.ApiWrapper; import com.android.launcher3.util.ItemInfoMatcher; import com.android.launcher3.views.FloatingIconView; import com.android.launcher3.views.Snackbar; @@ -234,7 +235,7 @@ public class ItemClickHandler { } } // Fallback to using custom market intent. - Intent intent = ApiWrapper.getAppMarketActivityIntent(launcher, + Intent intent = ApiWrapper.INSTANCE.get(launcher).getAppMarketActivityIntent( packageName, Process.myUserHandle()); launcher.startActivitySafely(v, intent, item); }; @@ -346,7 +347,7 @@ public class ItemClickHandler { // Check for abandoned promise if ((v instanceof BubbleTextView) && shortcut.hasPromiseIconUi() - && (!Utilities.enableSupportForArchiving() || !shortcut.isArchived())) { + && (!Flags.enableSupportForArchiving() || !shortcut.isArchived())) { String packageName = shortcut.getIntent().getComponent() != null ? shortcut.getIntent().getComponent().getPackageName() : shortcut.getIntent().getPackage(); @@ -372,12 +373,12 @@ public class ItemClickHandler { if (item instanceof ItemInfoWithIcon itemInfoWithIcon) { if ((itemInfoWithIcon.runtimeStatusFlags & ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) { - intent = ApiWrapper.getAppMarketActivityIntent(launcher, + intent = ApiWrapper.INSTANCE.get(launcher).getAppMarketActivityIntent( itemInfoWithIcon.getTargetComponent().getPackageName(), Process.myUserHandle()); } else if (itemInfoWithIcon.itemType == LauncherSettings.Favorites.ITEM_TYPE_PRIVATE_SPACE_INSTALL_APP_BUTTON) { - intent = ApiWrapper.getAppMarketActivityIntent(launcher, + intent = ApiWrapper.INSTANCE.get(launcher).getAppMarketActivityIntent( BuildConfig.APPLICATION_ID, launcher.getAppsView().getPrivateProfileManager().getProfileUser()); launcher.getStatsLogManager().logger().log( diff --git a/src_no_quickstep/com/android/launcher3/uioverrides/ApiWrapper.java b/src/com/android/launcher3/util/ApiWrapper.java similarity index 68% rename from src_no_quickstep/com/android/launcher3/uioverrides/ApiWrapper.java rename to src/com/android/launcher3/util/ApiWrapper.java index 90271c1cae..6429a437bf 100644 --- a/src_no_quickstep/com/android/launcher3/uioverrides/ApiWrapper.java +++ b/src/com/android/launcher3/util/ApiWrapper.java @@ -14,7 +14,9 @@ * limitations under the License. */ -package com.android.launcher3.uioverrides; +package com.android.launcher3.util; + +import static com.android.launcher3.util.MainThreadInitializedObject.forOverride; import android.app.ActivityOptions; import android.app.Person; @@ -28,10 +30,12 @@ import android.os.UserHandle; import android.os.UserManager; import android.util.ArrayMap; -import com.android.launcher3.Utilities; -import com.android.launcher3.util.UserIconInfo; +import androidx.annotation.Nullable; + +import com.android.launcher3.BuildConfig; +import com.android.launcher3.R; +import com.android.launcher3.Utilities; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; @@ -39,30 +43,40 @@ import java.util.Map; /** * A wrapper for the hidden API calls */ -public class ApiWrapper { +public class ApiWrapper implements ResourceBasedOverride, SafeCloseable { - public static final boolean TASKBAR_DRAWN_IN_PROCESS = false; + public static final MainThreadInitializedObject INSTANCE = + forOverride(ApiWrapper.class, R.string.api_wrapper_class); - public static Person[] getPersons(ShortcutInfo si) { + protected final Context mContext; + + public ApiWrapper(Context context) { + mContext = context; + } + + /** + * Returns the list of persons associated with the provided shortcut info + */ + public Person[] getPersons(ShortcutInfo si) { return Utilities.EMPTY_PERSON_ARRAY; } - public static Map getActivityOverrides(Context context) { + public Map getActivityOverrides() { return Collections.emptyMap(); } /** * Creates an ActivityOptions to play fade-out animation on closing targets */ - public static ActivityOptions createFadeOutAnimOptions(Context context) { - return ActivityOptions.makeCustomAnimation(context, 0, android.R.anim.fade_out); + public ActivityOptions createFadeOutAnimOptions() { + return ActivityOptions.makeCustomAnimation(mContext, 0, android.R.anim.fade_out); } /** * Returns a map of all users on the device to their corresponding UI properties */ - public static Map queryAllUsers(Context context) { - UserManager um = context.getSystemService(UserManager.class); + public Map queryAllUsers() { + UserManager um = mContext.getSystemService(UserManager.class); Map users = new ArrayMap<>(); List usersActual = um.getUserProfiles(); if (usersActual != null) { @@ -72,7 +86,7 @@ public class ApiWrapper { // Simple check to check if the provided user is work profile // TODO: Migrate to a better platform API NoopDrawable d = new NoopDrawable(); - boolean isWork = (d != context.getPackageManager().getUserBadgedIcon(d, user)); + boolean isWork = (d != mContext.getPackageManager().getUserBadgedIcon(d, user)); UserIconInfo info = new UserIconInfo( user, isWork ? UserIconInfo.TYPE_WORK : UserIconInfo.TYPE_MAIN, @@ -87,16 +101,15 @@ public class ApiWrapper { * Returns the list of the system packages that are installed at user creation. * An empty list denotes that all system packages are installed for that user at creation. */ - public static List getPreInstalledSystemPackages(Context context, UserHandle user) { - return new ArrayList<>(); + public List getPreInstalledSystemPackages(UserHandle user) { + return Collections.emptyList(); } /** * Returns an intent which can be used to start the App Market activity (Installer * Activity). */ - public static Intent getAppMarketActivityIntent(Context context, String packageName, - UserHandle user) { + public Intent getAppMarketActivityIntent(String packageName, UserHandle user) { return new Intent(Intent.ACTION_VIEW) .setData(new Uri.Builder() .scheme("market") @@ -104,24 +117,27 @@ public class ApiWrapper { .appendQueryParameter("id", packageName) .build()) .putExtra(Intent.EXTRA_REFERRER, new Uri.Builder().scheme("android-app") - .authority(context.getPackageName()).build()); + .authority(BuildConfig.APPLICATION_ID).build()); } /** * Returns an intent which can be used to open Private Space Settings. */ - public static Intent getPrivateSpaceSettingsIntent(Context context) { + @Nullable + public Intent getPrivateSpaceSettingsIntent() { return null; } /** * Checks if an activity is flagged as non-resizeable. */ - public static boolean isNonResizeableActivity(LauncherActivityInfo lai) { + public boolean isNonResizeableActivity(LauncherActivityInfo lai) { // Overridden in quickstep return false; } + @Override + public void close() { } private static class NoopDrawable extends ColorDrawable { @Override diff --git a/src/com/android/launcher3/util/LogConfig.java b/src/com/android/launcher3/util/LogConfig.java index e5bbcb1923..d59c3394c4 100644 --- a/src/com/android/launcher3/util/LogConfig.java +++ b/src/com/android/launcher3/util/LogConfig.java @@ -65,4 +65,9 @@ public class LogConfig { * When turned on, we enable AGA related session summary logging. */ public static final String AGA_SESSION_SUMMARY_LOG = "AGASessionSummaryLog"; + + /** + * When turned on, we enable long press nav handle related logging. + */ + public static final String NAV_HANDLE_LONG_PRESS = "NavHandleLongPress"; } diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java index 316506ab4a..608bed7090 100644 --- a/src/com/android/launcher3/util/PackageManagerHelper.java +++ b/src/com/android/launcher3/util/PackageManagerHelper.java @@ -16,6 +16,8 @@ package com.android.launcher3.util; +import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE; + import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.Context; @@ -38,6 +40,7 @@ import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.android.launcher3.Flags; import com.android.launcher3.PendingAddItemInfo; import com.android.launcher3.R; import com.android.launcher3.Utilities; @@ -46,7 +49,6 @@ import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.ItemInfoWithIcon; import com.android.launcher3.model.data.LauncherAppWidgetInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; -import com.android.launcher3.uioverrides.ApiWrapper; import java.util.List; import java.util.Objects; @@ -109,7 +111,7 @@ public class PackageManagerHelper { @SuppressWarnings("NewApi") public boolean isAppArchivedForUser(@NonNull final String packageName, @NonNull final UserHandle user) { - if (!Utilities.enableSupportForArchiving()) { + if (!Flags.enableSupportForArchiving()) { return false; } final ApplicationInfo info = getApplicationInfo( @@ -169,11 +171,9 @@ public class PackageManagerHelper { * Starts the details activity for {@code info} */ public void startDetailsActivityForInfo(ItemInfo info, Rect sourceBounds, Bundle opts) { - if (info instanceof ItemInfoWithIcon - && (((ItemInfoWithIcon) info).runtimeStatusFlags - & ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) { - ItemInfoWithIcon appInfo = (ItemInfoWithIcon) info; - mContext.startActivity(ApiWrapper.getAppMarketActivityIntent(mContext, + if (info instanceof ItemInfoWithIcon appInfo + && (appInfo.runtimeStatusFlags & FLAG_INSTALL_SESSION_ACTIVE) != 0) { + mContext.startActivity(ApiWrapper.INSTANCE.get(mContext).getAppMarketActivityIntent( appInfo.getTargetComponent().getPackageName(), Process.myUserHandle())); return; } @@ -274,6 +274,6 @@ public class PackageManagerHelper { @SuppressWarnings("NewApi") private boolean isPackageInstalledOrArchived(ApplicationInfo info) { return (info.flags & ApplicationInfo.FLAG_INSTALLED) != 0 || ( - Utilities.enableSupportForArchiving() && info.isArchived); + Flags.enableSupportForArchiving() && info.isArchived); } } diff --git a/src/com/android/launcher3/util/window/WindowManagerProxy.java b/src/com/android/launcher3/util/window/WindowManagerProxy.java index 4a906d33e1..998191e7fc 100644 --- a/src/com/android/launcher3/util/window/WindowManagerProxy.java +++ b/src/com/android/launcher3/util/window/WindowManagerProxy.java @@ -93,6 +93,13 @@ public class WindowManagerProxy implements ResourceBasedOverride { mTaskbarDrawnInProcess = taskbarDrawnInProcess; } + /** + * Returns true if taskbar is drawn in process + */ + public boolean isTaskbarDrawnInProcess() { + return mTaskbarDrawnInProcess; + } + /** * Returns a map of normalized info of internal displays to estimated window bounds * for that display diff --git a/src/com/android/quickstep/views/RecentsViewContainer.java b/src/com/android/quickstep/views/RecentsViewContainer.java new file mode 100644 index 0000000000..0c3f4f1ee5 --- /dev/null +++ b/src/com/android/quickstep/views/RecentsViewContainer.java @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2024 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.quickstep.views; + +import android.app.Activity; +import android.content.Context; +import android.content.ContextWrapper; +import android.content.LocusId; +import android.os.Bundle; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.View; +import android.view.Window; + +import com.android.launcher3.BaseActivity; +import com.android.launcher3.util.SystemUiController; +import com.android.launcher3.views.ActivityContext; +import com.android.launcher3.views.ScrimView; + +/** + * Interface to be implemented by the parent view of RecentsView + */ +public interface RecentsViewContainer extends ActivityContext { + + /** + * Returns an instance of an implementation of RecentsViewContainer + * @param context will find instance of recentsViewContainer from given context. + */ + static T containerFromContext(Context context) { + if (context instanceof RecentsViewContainer) { + return (T) context; + } else if (context instanceof ContextWrapper) { + return containerFromContext(((ContextWrapper) context).getBaseContext()); + } else { + throw new IllegalArgumentException("Cannot find RecentsViewContainer in parent tree"); + } + } + + /** + * Returns {@link SystemUiController} to manage various window flags to control system UI. + */ + SystemUiController getSystemUiController(); + + /** + * Returns {@link ScrimView} + */ + ScrimView getScrimView(); + + /** + * Returns the Overview Panel as a View + */ + T getOverviewPanel(); + + /** + * Returns the RootView + */ + View getRootView(); + + /** + * Dispatches a generic motion event to the view hierarchy. + * Returns the current RecentsViewContainer as context + */ + default Context asContext() { + return (Context) this; + } + + /** + * @see Window.Callback#dispatchGenericMotionEvent(MotionEvent) + */ + boolean dispatchGenericMotionEvent(MotionEvent ev); + + /** + * @see Window.Callback#dispatchKeyEvent(KeyEvent) + */ + boolean dispatchKeyEvent(KeyEvent ev); + + /** + * Returns overview actions view as a view + */ + View getActionsView(); + + /** + * @see BaseActivity#addForceInvisibleFlag(int) + * @param flag {@link BaseActivity.InvisibilityFlags} + */ + void addForceInvisibleFlag(@BaseActivity.InvisibilityFlags int flag); + + /** + * @see BaseActivity#clearForceInvisibleFlag(int) + * @param flag {@link BaseActivity.InvisibilityFlags} + */ + void clearForceInvisibleFlag(@BaseActivity.InvisibilityFlags int flag); + + /** + * @see android.app.Activity#setLocusContext(LocusId, Bundle) + * @param id {@link LocusId} + * @param bundle {@link Bundle} + */ + void setLocusContext(LocusId id, Bundle bundle); + + /** + * @see BaseActivity#isStarted() + * @return boolean + */ + boolean isStarted(); + + /** + * @see BaseActivity#addEventCallback(int, Runnable) + * @param event {@link BaseActivity.ActivityEvent} + * @param callback runnable to be executed upon event + */ + void addEventCallback(@BaseActivity.ActivityEvent int event, Runnable callback); + + /** + * @see BaseActivity#removeEventCallback(int, Runnable) + * @param event {@link BaseActivity.ActivityEvent} + * @param callback runnable to be executed upon event + */ + void removeEventCallback(@BaseActivity.ActivityEvent int event, Runnable callback); + + /** + * @see com.android.quickstep.util.TISBindHelper#runOnBindToTouchInteractionService(Runnable) + * @param r runnable to be executed upon event + */ + void runOnBindToTouchInteractionService(Runnable r); + + /** + * @see Activity#getWindow() + * @return Window + */ + Window getWindow(); + + /** + * @see + * BaseActivity#addMultiWindowModeChangedListener(BaseActivity.MultiWindowModeChangedListener) + * @param listener {@link BaseActivity.MultiWindowModeChangedListener} + */ + void addMultiWindowModeChangedListener( + BaseActivity.MultiWindowModeChangedListener listener); + + /** + * @see + * BaseActivity#removeMultiWindowModeChangedListener( + * BaseActivity.MultiWindowModeChangedListener) + * @param listener {@link BaseActivity.MultiWindowModeChangedListener} + */ + void removeMultiWindowModeChangedListener( + BaseActivity.MultiWindowModeChangedListener listener); + + /** + * Begins transition from overview back to homescreen + */ + void returnToHomescreen(); +} diff --git a/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt b/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt index ffcf83f303..577334bec3 100644 --- a/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt +++ b/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt @@ -38,17 +38,18 @@ import com.android.launcher3.util.rule.setFlags import com.android.launcher3.util.window.CachedDisplayInfo import com.android.launcher3.util.window.WindowManagerProxy import com.google.common.truth.Truth -import org.junit.Rule -import org.mockito.kotlin.any -import org.mockito.kotlin.mock -import org.mockito.kotlin.spy -import org.mockito.kotlin.whenever import java.io.BufferedReader import java.io.File import java.io.PrintWriter import java.io.StringWriter import kotlin.math.max import kotlin.math.min +import org.junit.Rule +import org.mockito.kotlin.any +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.spy +import org.mockito.kotlin.whenever /** * This is an abstract class for DeviceProfile tests that create an InvariantDeviceProfile based on @@ -286,6 +287,9 @@ abstract class AbstractDeviceProfileTest { .thenReturn( if (isGestureMode) NavigationMode.NO_BUTTON else NavigationMode.THREE_BUTTONS ) + doReturn(WindowManagerProxy.INSTANCE[runningContext].isTaskbarDrawnInProcess) + .whenever(windowManagerProxy) + .isTaskbarDrawnInProcess() val density = densityDpi / DisplayMetrics.DENSITY_DEFAULT.toFloat() val config = diff --git a/tests/src/com/android/launcher3/AbstractFloatingViewHelperTest.kt b/tests/src/com/android/launcher3/AbstractFloatingViewHelperTest.kt new file mode 100644 index 0000000000..7ff544d9f7 --- /dev/null +++ b/tests/src/com/android/launcher3/AbstractFloatingViewHelperTest.kt @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2024 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 + +import android.view.View +import com.android.launcher3.dragndrop.DragLayer +import com.android.launcher3.views.ActivityContext +import org.junit.Before +import org.junit.Test +import org.mockito.kotlin.any +import org.mockito.kotlin.mock +import org.mockito.kotlin.never +import org.mockito.kotlin.verify +import org.mockito.kotlin.verifyZeroInteractions +import org.mockito.kotlin.whenever + +/** Test for AbstractFloatingViewHelper */ +class AbstractFloatingViewHelperTest { + private val activityContext: ActivityContext = mock() + private val dragLayer: DragLayer = mock() + private val view: View = mock() + private val folderView: AbstractFloatingView = mock() + private val taskMenuView: AbstractFloatingView = mock() + private val abstractFloatingViewHelper = AbstractFloatingViewHelper() + + @Before + fun setup() { + whenever(activityContext.dragLayer).thenReturn(dragLayer) + whenever(dragLayer.childCount).thenReturn(3) + whenever(dragLayer.getChildAt(0)).thenReturn(view) + whenever(dragLayer.getChildAt(1)).thenReturn(folderView) + whenever(dragLayer.getChildAt(2)).thenReturn(taskMenuView) + whenever(folderView.isOfType(any())).thenAnswer { + (it.getArgument(0) and AbstractFloatingView.TYPE_FOLDER) != 0 + } + whenever(taskMenuView.isOfType(any())).thenAnswer { + (it.getArgument(0) and AbstractFloatingView.TYPE_TASK_MENU) != 0 + } + } + + @Test + fun closeOpenViews_all() { + abstractFloatingViewHelper.closeOpenViews( + activityContext, + true, + AbstractFloatingView.TYPE_ALL + ) + + verifyZeroInteractions(view) + verify(folderView).close(true) + verify(taskMenuView).close(true) + } + + @Test + fun closeOpenViews_taskMenu() { + abstractFloatingViewHelper.closeOpenViews( + activityContext, + true, + AbstractFloatingView.TYPE_TASK_MENU + ) + + verifyZeroInteractions(view) + verify(folderView, never()).close(any()) + verify(taskMenuView).close(true) + } + + @Test + fun closeOpenViews_other() { + abstractFloatingViewHelper.closeOpenViews( + activityContext, + true, + AbstractFloatingView.TYPE_PIN_IME_POPUP + ) + + verifyZeroInteractions(view) + verify(folderView, never()).close(any()) + verify(taskMenuView, never()).close(any()) + } + + @Test + fun closeOpenViews_both_animationOff() { + abstractFloatingViewHelper.closeOpenViews( + activityContext, + false, + AbstractFloatingView.TYPE_FOLDER or AbstractFloatingView.TYPE_TASK_MENU + ) + + verifyZeroInteractions(view) + verify(folderView).close(false) + verify(taskMenuView).close(false) + } +} diff --git a/tests/src/com/android/launcher3/LauncherIntentTest.java b/tests/src/com/android/launcher3/LauncherIntentTest.java index d1110c3c7a..aeeb42a363 100644 --- a/tests/src/com/android/launcher3/LauncherIntentTest.java +++ b/tests/src/com/android/launcher3/LauncherIntentTest.java @@ -34,7 +34,7 @@ import org.junit.runner.RunWith; @LargeTest @RunWith(AndroidJUnit4.class) -public class LauncherIntentTest extends AbstractLauncherUiTest { +public class LauncherIntentTest extends AbstractLauncherUiTest { public final Intent allAppsIntent = new Intent(Intent.ACTION_ALL_APPS); diff --git a/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java b/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java index e9d2f6e61a..2dcbda4ab6 100644 --- a/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java +++ b/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java @@ -47,8 +47,8 @@ import androidx.test.runner.AndroidJUnit4; import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.pm.UserCache; -import com.android.launcher3.uioverrides.ApiWrapper; import com.android.launcher3.util.ActivityContextWrapper; +import com.android.launcher3.util.ApiWrapper; import com.android.launcher3.util.UserIconInfo; import com.android.launcher3.util.rule.TestStabilityRule; @@ -108,7 +108,8 @@ public class PrivateProfileManagerTest { when(mUserCache.getUserInfo(Process.myUserHandle())).thenReturn(MAIN_ICON_INFO); when(mUserCache.getUserInfo(PRIVATE_HANDLE)).thenReturn(PRIVATE_ICON_INFO); when(mAllApps.getContext()).thenReturn(mContext); - when(mAllApps.getContext().getResources()).thenReturn(mResources); + when(mContext.getResources()).thenReturn(mResources); + when(mContext.getApplicationContext()).thenReturn(getApplicationContext()); when(mAllApps.getAppsStore()).thenReturn(mAllAppsStore); when(mAllApps.getActiveRecyclerView()).thenReturn(mAllAppsRecyclerView); when(mContext.getPackageManager()).thenReturn(mPackageManager); @@ -200,14 +201,16 @@ public class PrivateProfileManagerTest { @Test public void openPrivateSpaceSettings_triggersCorrectIntent() { - Intent expectedIntent = ApiWrapper.getPrivateSpaceSettingsIntent(mContext); + Intent expectedIntent = ApiWrapper.INSTANCE.get(mContext).getPrivateSpaceSettingsIntent(); ArgumentCaptor acIntent = ArgumentCaptor.forClass(Intent.class); mPrivateProfileManager.setPrivateSpaceSettingsAvailable(true); mPrivateProfileManager.openPrivateSpaceSettings(); Mockito.verify(mContext).startActivity(acIntent.capture()); - assertEquals("Intent Action is different", expectedIntent, acIntent.getValue()); + assertEquals("Intent Action is different", + expectedIntent == null ? null : expectedIntent.toUri(0), + acIntent.getValue() == null ? null : acIntent.getValue().toUri(0)); } private static void awaitTasksCompleted() throws Exception { diff --git a/tests/src/com/android/launcher3/allapps/TaplAllAppsIconsWorkingTest.java b/tests/src/com/android/launcher3/allapps/TaplAllAppsIconsWorkingTest.java index 10e9f8abb1..0b233e5492 100644 --- a/tests/src/com/android/launcher3/allapps/TaplAllAppsIconsWorkingTest.java +++ b/tests/src/com/android/launcher3/allapps/TaplAllAppsIconsWorkingTest.java @@ -18,6 +18,7 @@ package com.android.launcher3.allapps; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.tapl.AppIcon; import com.android.launcher3.tapl.HomeAllApps; @@ -30,7 +31,7 @@ import org.junit.Test; * The test runs in Out of process (Oop) and in process. * Makes sure the basic behaviors of Icons on AllApps are working. */ -public class TaplAllAppsIconsWorkingTest extends AbstractLauncherUiTest { +public class TaplAllAppsIconsWorkingTest extends AbstractLauncherUiTest { /** * Makes sure we can launch an icon from All apps diff --git a/tests/src/com/android/launcher3/allapps/TaplKeyboardFocusTest.java b/tests/src/com/android/launcher3/allapps/TaplKeyboardFocusTest.java index 0360470215..20684eb5ef 100644 --- a/tests/src/com/android/launcher3/allapps/TaplKeyboardFocusTest.java +++ b/tests/src/com/android/launcher3/allapps/TaplKeyboardFocusTest.java @@ -26,6 +26,7 @@ import android.view.KeyEvent; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; +import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.tapl.HomeAllApps; import com.android.launcher3.ui.AbstractLauncherUiTest; @@ -37,7 +38,7 @@ import org.junit.runner.RunWith; @SmallTest @RunWith(AndroidJUnit4.class) -public class TaplKeyboardFocusTest extends AbstractLauncherUiTest { +public class TaplKeyboardFocusTest extends AbstractLauncherUiTest { @Test public void testAllAppsFocusApp() { diff --git a/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java b/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java index e462c4f9b1..f3f6fa5614 100644 --- a/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java +++ b/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java @@ -28,6 +28,7 @@ import android.platform.test.annotations.PlatinumTest; import androidx.test.filters.FlakyTest; import androidx.test.platform.app.InstrumentationRegistry; +import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.tapl.AllApps; import com.android.launcher3.ui.AbstractLauncherUiTest; @@ -40,7 +41,7 @@ import org.junit.Test; * Test that we can open and close the all apps in multiple situations. * The test runs in Out of process (Oop) and in process. */ -public class TaplOpenCloseAllAppsTest extends AbstractLauncherUiTest { +public class TaplOpenCloseAllAppsTest extends AbstractLauncherUiTest { public static final String READ_DEVICE_CONFIG_PERMISSION = "android.permission.READ_DEVICE_CONFIG"; diff --git a/tests/src/com/android/launcher3/appiconmenu/TaplAppIconMenuTest.java b/tests/src/com/android/launcher3/appiconmenu/TaplAppIconMenuTest.java index c69d1b9988..55d3252843 100644 --- a/tests/src/com/android/launcher3/appiconmenu/TaplAppIconMenuTest.java +++ b/tests/src/com/android/launcher3/appiconmenu/TaplAppIconMenuTest.java @@ -38,7 +38,7 @@ import org.junit.Test; * Tests the AppIconMenu (the menu that appears when you long press an app icon) and also make sure * we can launch a shortcut from it. */ -public class TaplAppIconMenuTest extends AbstractLauncherUiTest { +public class TaplAppIconMenuTest extends AbstractLauncherUiTest { private boolean isOptionsPopupVisible(Launcher launcher) { final ArrowPopup popup = launcher.getOptionsPopup(); diff --git a/tests/src/com/android/launcher3/celllayout/TaplReorderWidgetsTest.java b/tests/src/com/android/launcher3/celllayout/TaplReorderWidgetsTest.java index 1b036453ce..389d027dc1 100644 --- a/tests/src/com/android/launcher3/celllayout/TaplReorderWidgetsTest.java +++ b/tests/src/com/android/launcher3/celllayout/TaplReorderWidgetsTest.java @@ -30,6 +30,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.launcher3.InvariantDeviceProfile; +import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; import com.android.launcher3.MultipageCellLayout; import com.android.launcher3.celllayout.board.CellLayoutBoard; @@ -59,7 +60,7 @@ import java.util.Map; @SmallTest @RunWith(AndroidJUnit4.class) -public class TaplReorderWidgetsTest extends AbstractLauncherUiTest { +public class TaplReorderWidgetsTest extends AbstractLauncherUiTest { @Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind(); diff --git a/tests/src/com/android/launcher3/compat/TaplPromiseIconUiTest.java b/tests/src/com/android/launcher3/compat/TaplPromiseIconUiTest.java index 7ed0fa5b8f..1500538633 100644 --- a/tests/src/com/android/launcher3/compat/TaplPromiseIconUiTest.java +++ b/tests/src/com/android/launcher3/compat/TaplPromiseIconUiTest.java @@ -52,7 +52,7 @@ import java.util.UUID; */ @LargeTest @RunWith(AndroidJUnit4.class) -public class TaplPromiseIconUiTest extends AbstractLauncherUiTest { +public class TaplPromiseIconUiTest extends AbstractLauncherUiTest { @Rule public final CheckFlagsRule mCheckFlagsRule = diff --git a/tests/src/com/android/launcher3/dragging/TaplDragTest.java b/tests/src/com/android/launcher3/dragging/TaplDragTest.java index bf1ba39fef..d64d096c72 100644 --- a/tests/src/com/android/launcher3/dragging/TaplDragTest.java +++ b/tests/src/com/android/launcher3/dragging/TaplDragTest.java @@ -33,6 +33,7 @@ import android.os.SystemClock; import android.platform.test.annotations.PlatinumTest; import android.util.Log; +import com.android.launcher3.Launcher; import com.android.launcher3.tapl.Folder; import com.android.launcher3.tapl.FolderIcon; import com.android.launcher3.tapl.HomeAllApps; @@ -57,7 +58,7 @@ import org.junit.Test; * * Can drag an icon from AllApps into the workspace * * Can drag an icon on the Workspace to other positions of the Workspace. */ -public class TaplDragTest extends AbstractLauncherUiTest { +public class TaplDragTest extends AbstractLauncherUiTest { /** * Adds two icons to the Workspace and combines them into a folder, then makes sure the icons diff --git a/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java b/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java index e21309f0e5..df71ec09d4 100644 --- a/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java +++ b/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java @@ -17,7 +17,6 @@ package com.android.launcher3.dragging; import static com.android.launcher3.testing.shared.TestProtocol.ICON_MISSING; import static com.android.launcher3.testing.shared.TestProtocol.UIOBJECT_STALE_ELEMENT; -import static com.android.launcher3.ui.AbstractLauncherUiTest.initialize; import static com.android.launcher3.util.TestConstants.AppNames.DUMMY_APP_NAME; import static com.android.launcher3.util.TestConstants.AppNames.GMAIL_APP_NAME; import static com.android.launcher3.util.TestConstants.AppNames.MAPS_APP_NAME; @@ -32,6 +31,7 @@ import android.graphics.Point; import android.platform.test.annotations.PlatinumTest; import android.util.Log; +import com.android.launcher3.Launcher; import com.android.launcher3.tapl.HomeAllApps; import com.android.launcher3.tapl.HomeAppIcon; import com.android.launcher3.tapl.Workspace; @@ -51,7 +51,7 @@ import java.util.Map; * Test runs in Out of process (Oop) and In process (Ipc) * Test the behaviour of uninstalling and removing apps both from AllApps, Workspace and Hotseat. */ -public class TaplUninstallRemoveTest extends AbstractLauncherUiTest { +public class TaplUninstallRemoveTest extends AbstractLauncherUiTest { /** * Deletes app both built-in and user-installed from the Workspace and makes sure it's no longer diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java index d8635f9071..71090836bb 100644 --- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java +++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java @@ -95,7 +95,7 @@ import java.util.function.Supplier; /** * Base class for all instrumentation tests providing various utility methods. */ -public abstract class AbstractLauncherUiTest { +public abstract class AbstractLauncherUiTest { public static final long DEFAULT_ACTIVITY_TIMEOUT = TimeUnit.SECONDS.toMillis(10); public static final long DEFAULT_BROADCAST_TIMEOUT_SECS = 5; @@ -251,7 +251,7 @@ public abstract class AbstractLauncherUiTest { final ViewCaptureRule viewCaptureRule = new ViewCaptureRule( Launcher.ACTIVITY_TRACKER::getCreatedActivity); final RuleChain inner = RuleChain - .outerRule(new PortraitLandscapeRunner(this)) + .outerRule(new PortraitLandscapeRunner(this)) .around(new FailureWatcher(mLauncher, viewCaptureRule::getViewCaptureData)) // .around(viewCaptureRule) // b/315482167 .around(new TestIsolationRule(mLauncher, true)); @@ -426,12 +426,12 @@ public abstract class AbstractLauncherUiTest { } } - protected T getFromLauncher(Function f) { + protected T getFromLauncher(Function f) { if (!TestHelpers.isInLauncherProcess()) return null; return getOnUiThread(() -> f.apply(Launcher.ACTIVITY_TRACKER.getCreatedActivity())); } - protected void executeOnLauncher(Consumer f) { + protected void executeOnLauncher(Consumer f) { getFromLauncher(launcher -> { f.accept(launcher); return null; @@ -441,7 +441,7 @@ public abstract class AbstractLauncherUiTest { // Execute an action on Launcher, but forgive it when launcher is null. // Launcher can be null if teardown is happening after a failed setup step where launcher // activity failed to be created. - protected void executeOnLauncherInTearDown(Consumer f) { + protected void executeOnLauncherInTearDown(Consumer f) { executeOnLauncher(launcher -> { if (launcher != null) f.accept(launcher); }); @@ -469,20 +469,20 @@ public abstract class AbstractLauncherUiTest { // Cannot be used in TaplTests after injecting any gesture using Tapl because this can hide // flakiness. protected void waitForLauncherCondition(String - message, Function condition) { + message, Function condition) { waitForLauncherCondition(message, condition, DEFAULT_ACTIVITY_TIMEOUT); } // Cannot be used in TaplTests after injecting any gesture using Tapl because this can hide // flakiness. - protected T getOnceNotNull(String message, Function f) { + protected O getOnceNotNull(String message, Function f) { return getOnceNotNull(message, f, DEFAULT_ACTIVITY_TIMEOUT); } // Cannot be used in TaplTests after injecting any gesture using Tapl because this can hide // flakiness. protected void waitForLauncherCondition( - String message, Function condition, long timeout) { + String message, Function condition, long timeout) { verifyKeyguardInvisible(); if (!TestHelpers.isInLauncherProcess()) return; Wait.atMost(message, () -> getFromLauncher(condition), timeout, mLauncher); @@ -490,7 +490,7 @@ public abstract class AbstractLauncherUiTest { // Cannot be used in TaplTests after injecting any gesture using Tapl because this can hide // flakiness. - protected T getOnceNotNull(String message, Function f, long timeout) { + protected T getOnceNotNull(String message, Function f, long timeout) { if (!TestHelpers.isInLauncherProcess()) return null; final Object[] output = new Object[1]; @@ -506,7 +506,7 @@ public abstract class AbstractLauncherUiTest { // flakiness. protected void waitForLauncherCondition( String message, - Runnable testThreadAction, Function condition, + Runnable testThreadAction, Function condition, long timeout) { if (!TestHelpers.isInLauncherProcess()) return; Wait.atMost(message, () -> { @@ -648,7 +648,7 @@ public abstract class AbstractLauncherUiTest { "Launcher still active", launcher -> launcher == null, DEFAULT_UI_TIMEOUT); } - protected boolean isInLaunchedApp(Launcher launcher) { + protected boolean isInLaunchedApp(LAUNCHER_TYPE launcher) { return launcher == null || !launcher.hasBeenResumed(); } @@ -658,11 +658,11 @@ public abstract class AbstractLauncherUiTest { launcher -> launcher.getStateManager().getState() == state.get()); } - protected int getAllAppsScroll(Launcher launcher) { + protected int getAllAppsScroll(LAUNCHER_TYPE launcher) { return launcher.getAppsView().getActiveRecyclerView().computeVerticalScrollOffset(); } - protected void onLauncherActivityClose(Launcher launcher) { + protected void onLauncherActivityClose(LAUNCHER_TYPE launcher) { } protected HomeAppIcon createShortcutInCenterIfNotExist(String name) { diff --git a/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java b/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java index fabe3f71e7..c4e74f20fa 100644 --- a/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java +++ b/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java @@ -3,6 +3,7 @@ package com.android.launcher3.ui; import android.util.Log; import android.view.Surface; +import com.android.launcher3.Launcher; import com.android.launcher3.tapl.TestHelpers; import com.android.launcher3.util.rule.FailureWatcher; @@ -14,11 +15,12 @@ import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.util.Objects; import java.util.concurrent.TimeUnit; -public class PortraitLandscapeRunner implements TestRule { +public class PortraitLandscapeRunner implements TestRule { private static final String TAG = "PortraitLandscapeRunner"; - private AbstractLauncherUiTest mTest; + private AbstractLauncherUiTest mTest; // Annotation for tests that need to be run in portrait and landscape modes. @Retention(RetentionPolicy.RUNTIME) @@ -26,7 +28,7 @@ public class PortraitLandscapeRunner implements TestRule { public @interface PortraitLandscape { } - public PortraitLandscapeRunner(AbstractLauncherUiTest test) { + public PortraitLandscapeRunner(AbstractLauncherUiTest test) { mTest = test; } @@ -47,7 +49,7 @@ public class PortraitLandscapeRunner implements TestRule { mTest.mDevice.pressHome(); mTest.waitForLauncherCondition("Launcher activity wasn't created", - launcher -> launcher != null, + Objects::nonNull, TimeUnit.SECONDS.toMillis(20)); mTest.executeOnLauncher(launcher -> diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3Test.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3Test.java index 6780ed57b7..342eedf2be 100644 --- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3Test.java +++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3Test.java @@ -22,13 +22,14 @@ import androidx.test.filters.LargeTest; import androidx.test.runner.AndroidJUnit4; import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord; +import com.android.launcher3.Launcher; import org.junit.Test; import org.junit.runner.RunWith; @LargeTest @RunWith(AndroidJUnit4.class) -public class TaplTestsLauncher3Test extends AbstractLauncherUiTest { +public class TaplTestsLauncher3Test extends AbstractLauncherUiTest { @ScreenRecord // b/322823478 @Test diff --git a/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java b/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java index eb1f49ff11..cccda88bbe 100644 --- a/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java +++ b/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java @@ -35,6 +35,7 @@ import androidx.recyclerview.widget.RecyclerView.ViewHolder; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.LargeTest; +import com.android.launcher3.Launcher; import com.android.launcher3.LauncherPrefs; import com.android.launcher3.R; import com.android.launcher3.allapps.ActivityAllAppsContainerView; @@ -58,7 +59,7 @@ import java.util.function.Predicate; @LargeTest @RunWith(AndroidJUnit4.class) -public class TaplWorkProfileTest extends AbstractLauncherUiTest { +public class TaplWorkProfileTest extends AbstractLauncherUiTest { private static final int WORK_PAGE = ActivityAllAppsContainerView.AdapterHolder.WORK; diff --git a/tests/src/com/android/launcher3/ui/widget/TaplAddConfigWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/TaplAddConfigWidgetTest.java index 1db60144dc..e6e02b49ac 100644 --- a/tests/src/com/android/launcher3/ui/widget/TaplAddConfigWidgetTest.java +++ b/tests/src/com/android/launcher3/ui/widget/TaplAddConfigWidgetTest.java @@ -52,7 +52,7 @@ import org.junit.runner.RunWith; */ @LargeTest @RunWith(AndroidJUnit4.class) -public class TaplAddConfigWidgetTest extends AbstractLauncherUiTest { +public class TaplAddConfigWidgetTest extends AbstractLauncherUiTest { @Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind(); diff --git a/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java index 6c243294c3..7845dec4a3 100644 --- a/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java +++ b/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java @@ -25,6 +25,7 @@ import android.platform.test.annotations.PlatinumTest; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.LargeTest; +import com.android.launcher3.Launcher; import com.android.launcher3.celllayout.FavoriteItemsTransaction; import com.android.launcher3.tapl.Widget; import com.android.launcher3.tapl.WidgetResizeFrame; @@ -46,7 +47,7 @@ import org.junit.runner.RunWith; */ @LargeTest @RunWith(AndroidJUnit4.class) -public class TaplAddWidgetTest extends AbstractLauncherUiTest { +public class TaplAddWidgetTest extends AbstractLauncherUiTest { @Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind(); diff --git a/tests/src/com/android/launcher3/ui/widget/TaplBindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/TaplBindWidgetTest.java index e69cb4ce62..28d1faa5e7 100644 --- a/tests/src/com/android/launcher3/ui/widget/TaplBindWidgetTest.java +++ b/tests/src/com/android/launcher3/ui/widget/TaplBindWidgetTest.java @@ -43,6 +43,7 @@ import android.widget.RemoteViews; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.LargeTest; +import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherModel; import com.android.launcher3.LauncherSettings; @@ -76,7 +77,7 @@ import java.util.function.Consumer; */ @LargeTest @RunWith(AndroidJUnit4.class) -public class TaplBindWidgetTest extends AbstractLauncherUiTest { +public class TaplBindWidgetTest extends AbstractLauncherUiTest { @Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind(); diff --git a/tests/src/com/android/launcher3/ui/widget/TaplRequestPinItemTest.java b/tests/src/com/android/launcher3/ui/widget/TaplRequestPinItemTest.java index 90a6d22f38..74047f0d01 100644 --- a/tests/src/com/android/launcher3/ui/widget/TaplRequestPinItemTest.java +++ b/tests/src/com/android/launcher3/ui/widget/TaplRequestPinItemTest.java @@ -59,7 +59,7 @@ import java.util.UUID; */ @LargeTest @RunWith(AndroidJUnit4.class) -public class TaplRequestPinItemTest extends AbstractLauncherUiTest { +public class TaplRequestPinItemTest extends AbstractLauncherUiTest { @Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind(); diff --git a/tests/src/com/android/launcher3/ui/widget/TaplWidgetPickerTest.java b/tests/src/com/android/launcher3/ui/widget/TaplWidgetPickerTest.java index 4acdddc7e2..79724e1189 100644 --- a/tests/src/com/android/launcher3/ui/widget/TaplWidgetPickerTest.java +++ b/tests/src/com/android/launcher3/ui/widget/TaplWidgetPickerTest.java @@ -43,7 +43,7 @@ import org.junit.runner.RunWith; */ @MediumTest @RunWith(AndroidJUnit4.class) -public class TaplWidgetPickerTest extends AbstractLauncherUiTest { +public class TaplWidgetPickerTest extends AbstractLauncherUiTest { // b/325377690 : To get the log printed where DOWN key event is getting lost from TAPL. @Rule public final TestRule mEnableInputTransportPublisherRule = createEnableInputTransportPublisherRule(); diff --git a/tests/src/com/android/launcher3/ui/workspace/TaplThemeIconsTest.java b/tests/src/com/android/launcher3/ui/workspace/TaplThemeIconsTest.java index c60ee8c5ed..d6533171d3 100644 --- a/tests/src/com/android/launcher3/ui/workspace/TaplThemeIconsTest.java +++ b/tests/src/com/android/launcher3/ui/workspace/TaplThemeIconsTest.java @@ -31,6 +31,7 @@ import android.view.ViewGroup; import androidx.test.filters.LargeTest; import com.android.launcher3.BubbleTextView; +import com.android.launcher3.Launcher; import com.android.launcher3.icons.ThemedIconDrawable; import com.android.launcher3.tapl.HomeAllApps; import com.android.launcher3.tapl.HomeAppIcon; @@ -49,7 +50,7 @@ import java.util.Queue; * Note running these tests will clear the workspace on the device. */ @LargeTest -public class TaplThemeIconsTest extends AbstractLauncherUiTest { +public class TaplThemeIconsTest extends AbstractLauncherUiTest { private static final String APP_NAME = "IconThemedActivity"; private static final String SHORTCUT_NAME = "Shortcut 1"; diff --git a/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java b/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java index 913dfa2285..2ce8eef2d8 100644 --- a/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java +++ b/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java @@ -55,7 +55,7 @@ import java.util.stream.Collectors; */ @LargeTest @RunWith(AndroidJUnit4.class) -public class TaplTwoPanelWorkspaceTest extends AbstractLauncherUiTest { +public class TaplTwoPanelWorkspaceTest extends AbstractLauncherUiTest { private AutoCloseable mLauncherLayout; diff --git a/tests/src/com/android/launcher3/ui/workspace/TaplWorkspaceTest.java b/tests/src/com/android/launcher3/ui/workspace/TaplWorkspaceTest.java index 4edeb42fc1..9afde0db28 100644 --- a/tests/src/com/android/launcher3/ui/workspace/TaplWorkspaceTest.java +++ b/tests/src/com/android/launcher3/ui/workspace/TaplWorkspaceTest.java @@ -37,7 +37,7 @@ import org.junit.Test; /** * Test the basic interactions of the Workspace, adding pages, moving the pages and removing pages. */ -public class TaplWorkspaceTest extends AbstractLauncherUiTest { +public class TaplWorkspaceTest extends AbstractLauncherUiTest { private AutoCloseable mLauncherLayout; diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java index 847dc4b627..245ec0911c 100644 --- a/tests/tapl/com/android/launcher3/tapl/AllApps.java +++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java @@ -416,6 +416,14 @@ public abstract class AllApps extends LauncherInstrumentation.VisibleContainer } } + /** Returns PrivateSpaceContainer if present in view. */ + @NonNull + public PrivateSpaceContainer getPrivateSpaceUnlockedView() { + final UiObject2 allAppsContainer = verifyActiveContainer(); + final UiObject2 appListRecycler = getAppListRecycler(allAppsContainer); + return new PrivateSpaceContainer(mLauncher, appListRecycler); + } + protected abstract void verifyVisibleContainerOnDismiss(); /** diff --git a/tests/tapl/com/android/launcher3/tapl/PrivateSpaceContainer.java b/tests/tapl/com/android/launcher3/tapl/PrivateSpaceContainer.java new file mode 100644 index 0000000000..2c16e015c2 --- /dev/null +++ b/tests/tapl/com/android/launcher3/tapl/PrivateSpaceContainer.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2024 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.tapl; + +import androidx.test.uiautomator.UiObject2; + +/** + * View containing Private Space elements. + */ +public class PrivateSpaceContainer { + private static final String PS_HEADER_RES_ID = "ps_header_layout"; + private static final String INSTALL_APP_TITLE = "Install apps"; + private static final String DIVIDER_RES_ID = "private_space_divider"; + + private final LauncherInstrumentation mLauncher; + private final UiObject2 mAppListRecycler; + + PrivateSpaceContainer(LauncherInstrumentation launcherInstrumentation, + UiObject2 appListRecycler) { + mLauncher = launcherInstrumentation; + mAppListRecycler = appListRecycler; + + verifyHeaderIsPresent(); + verifyInstallAppButtonIsPresent(); + verifyDividerIsPresent(); + } + + // Assert PS Header is in view. + // Assert PS header has the correct elements. + private void verifyHeaderIsPresent() { + final UiObject2 psHeader = mLauncher.waitForObjectInContainer(mAppListRecycler, + PS_HEADER_RES_ID); + new PrivateSpaceHeader(mLauncher, psHeader, true); + } + + + // Assert Install App Item is present in view. + private void verifyInstallAppButtonIsPresent() { + mLauncher.getAllApps().getAppIcon(INSTALL_APP_TITLE); + } + + // Assert Sys App Divider is present in view. + private void verifyDividerIsPresent() { + mLauncher.waitForObjectInContainer(mAppListRecycler, DIVIDER_RES_ID); + } +} diff --git a/tests/tapl/com/android/launcher3/tapl/PrivateSpaceHeader.java b/tests/tapl/com/android/launcher3/tapl/PrivateSpaceHeader.java new file mode 100644 index 0000000000..3a7f0380a7 --- /dev/null +++ b/tests/tapl/com/android/launcher3/tapl/PrivateSpaceHeader.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2024 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.tapl; + +import androidx.test.uiautomator.UiObject2; + +/** + * View containing Private Space Header. + */ +public class PrivateSpaceHeader { + private static final String PS_HEADER_TEXT_RES_ID = "ps_container_header"; + private static final String SETTINGS_BUTTON_RES_ID = "ps_settings_button"; + private static final String UNLOCK_BUTTON_VIEW_RES_ID = "ps_lock_unlock_button"; + private static final String LOCK_ICON_RES_ID = "lock_icon"; + private static final String LOCK_TEXT_RES_ID = "lock_text"; + + private final UiObject2 mPrivateSpaceHeader; + private final boolean mPrivateSpaceEnabled; + private final LauncherInstrumentation mLauncher; + + PrivateSpaceHeader(LauncherInstrumentation launcherInstrumentation, + UiObject2 privateSpaceHeader, boolean privateSpaceEnabled) { + mLauncher = launcherInstrumentation; + mPrivateSpaceHeader = privateSpaceHeader; + mPrivateSpaceEnabled = privateSpaceEnabled; + verifyPrivateSpaceHeaderState(); + } + + /** Verify elements in Private Space Header as per state */ + private void verifyPrivateSpaceHeaderState() { + if (mPrivateSpaceEnabled) { + verifyUnlockedState(); + } else { + mLauncher.fail("Private Space found in non enabled state"); + } + } + + /** Verify Unlocked State elements in Private Space Header */ + private void verifyUnlockedState() { + UiObject2 headerText = mLauncher.waitForObjectInContainer(mPrivateSpaceHeader, + PS_HEADER_TEXT_RES_ID); + mLauncher.assertEquals("PS Header Text is incorrect ", + "Private", headerText.getText()); + + UiObject2 settingsButton = mLauncher.waitForObjectInContainer(mPrivateSpaceHeader, + SETTINGS_BUTTON_RES_ID); + mLauncher.waitForObjectEnabled(settingsButton, "Private Space Settings Button"); + mLauncher.assertTrue("PS Settings button is non-clickable", settingsButton.isClickable()); + + UiObject2 unLockButtonView = mLauncher.waitForObjectInContainer(mPrivateSpaceHeader, + UNLOCK_BUTTON_VIEW_RES_ID); + mLauncher.waitForObjectEnabled(unLockButtonView, "Private Space Unlock Button"); + mLauncher.assertTrue("PS Unlock Button is non-clickable", unLockButtonView.isClickable()); + + mLauncher.waitForObjectInContainer(mPrivateSpaceHeader, + LOCK_ICON_RES_ID); + + UiObject2 lockText = mLauncher.waitForObjectInContainer(mPrivateSpaceHeader, + LOCK_TEXT_RES_ID); + mLauncher.assertEquals("PS lock text is incorrect", "Lock", lockText.getText()); + + } +}