diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml index ff5bf0d1e5..19a16e341a 100644 --- a/AndroidManifest-common.xml +++ b/AndroidManifest-common.xml @@ -45,9 +45,6 @@ - - - + android:name="com.android.launcher3.SessionCommitReceiver" + android:exported="true"> - + @@ -117,6 +117,7 @@ android:name="com.android.launcher3.notification.NotificationListener" android:label="@string/notification_dots_service_title" android:enabled="@bool/notification_dots_enabled" + android:exported="true" android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"> @@ -130,6 +131,7 @@ android:theme="@style/AppItemActivityTheme" android:excludeFromRecents="true" android:autoRemoveFromRecents="true" + android:exported="true" android:label="@string/action_add_to_workspace" > @@ -165,6 +167,7 @@ android:name="com.android.launcher3.settings.SettingsActivity" android:label="@string/settings_button_text" android:theme="@style/HomeSettingsTheme" + android:exported="true" android:autoRemoveFromRecents="true"> @@ -187,6 +190,7 @@ android:name="com.android.launcher3.secondarydisplay.SecondaryDisplayLauncher" android:theme="@style/AppTheme" android:launchMode="singleTop" + android:exported="true" android:enabled="true"> diff --git a/AndroidManifest.xml b/AndroidManifest.xml index b031ffbee4..8e01f82018 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -53,6 +53,7 @@ android:resizeableActivity="true" android:resumeWhilePausing="true" android:taskAffinity="" + android:exported="true" android:enabled="true"> diff --git a/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java b/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java index e649ce1de4..aa3710b6d9 100644 --- a/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java +++ b/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java @@ -164,6 +164,12 @@ public class DebugTestInformationHandler extends TestInformationHandler { } case TestProtocol.REQUEST_GET_TEST_EVENTS: { + if (sEvents == null) { + // sEvents can be null if Launcher died and restarted after + // REQUEST_START_EVENT_LOGGING. + return response; + } + synchronized (sEvents) { response.putStringArrayList( TestProtocol.TEST_INFO_RESPONSE_FIELD, new ArrayList<>(sEvents)); diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto index 561196941c..cd229ae015 100644 --- a/protos/launcher_atom.proto +++ b/protos/launcher_atom.proto @@ -131,6 +131,7 @@ message Application { // Legacy shortcuts and shortcuts handled by ShortcutManager message Shortcut { optional string shortcut_name = 1; + optional string shortcut_id = 2; } // AppWidgets handled by AppWidgetManager diff --git a/quickstep/AndroidManifest-launcher.xml b/quickstep/AndroidManifest-launcher.xml index 60afddb0a8..53910e344b 100644 --- a/quickstep/AndroidManifest-launcher.xml +++ b/quickstep/AndroidManifest-launcher.xml @@ -53,6 +53,7 @@ android:resizeableActivity="true" android:resumeWhilePausing="true" android:taskAffinity="" + android:exported="true" android:enabled="true"> diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml index e49f2ecdc0..4e7c3fa75b 100644 --- a/quickstep/AndroidManifest.xml +++ b/quickstep/AndroidManifest.xml @@ -17,97 +17,91 @@ ** limitations under the License. */ --> - - + + - - - + + + - + - + - + + android:excludeFromRecents="true" + android:launchMode="singleTask" + android:clearTaskOnLaunch="true" + android:stateNotNeeded="true" + android:theme="@style/LauncherTheme" + android:screenOrientation="unspecified" + android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize" + android:resizeableActivity="true" + android:resumeWhilePausing="true" + android:taskAffinity=""/> - + - + - - + + - + - + - + - - + + + android:permission="${packageName}.permission.HOTSEAT_EDU" + android:exported="true"> diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java index 4c7943b10b..8cabe3d80b 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java @@ -16,6 +16,12 @@ package com.android.launcher3.appprediction; import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_GRID; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROPPED_ON_DONT_SUGGEST; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_LEFT; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_RIGHT; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_SWIPE_DOWN; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import android.annotation.TargetApi; @@ -31,29 +37,38 @@ import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Message; +import android.os.Process; +import android.os.SystemClock; import android.os.UserHandle; +import android.text.TextUtils; import android.util.Log; +import androidx.annotation.AnyThread; import androidx.annotation.Nullable; import androidx.annotation.UiThread; import androidx.annotation.WorkerThread; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.appprediction.PredictionUiStateManager.Client; +import com.android.launcher3.logger.LauncherAtom; +import com.android.launcher3.logger.LauncherAtom.ContainerInfo; +import com.android.launcher3.logger.LauncherAtom.FolderContainer; +import com.android.launcher3.logger.LauncherAtom.HotseatContainer; +import com.android.launcher3.logger.LauncherAtom.WorkspaceContainer; +import com.android.launcher3.logging.StatsLogManager.EventEnum; import com.android.launcher3.model.AppLaunchTracker; -import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper; -import com.android.systemui.plugins.AppLaunchEventsPlugin; -import com.android.systemui.plugins.PluginListener; +import com.android.launcher3.pm.UserCache; +import com.android.quickstep.logging.StatsLogCompatManager; +import com.android.quickstep.logging.StatsLogCompatManager.StatsLogConsumer; -import java.util.ArrayList; -import java.util.List; +import java.util.Locale; +import java.util.function.Predicate; /** * Subclass of app tracker which publishes the data to the prediction engine and gets back results. */ @TargetApi(Build.VERSION_CODES.Q) -public class PredictionAppTracker extends AppLaunchTracker - implements PluginListener { +public class PredictionAppTracker extends AppLaunchTracker implements StatsLogConsumer { private static final String TAG = "PredictionAppTracker"; private static final boolean DBG = false; @@ -65,11 +80,9 @@ public class PredictionAppTracker extends AppLaunchTracker protected final Context mContext; private final Handler mMessageHandler; - private final List mAppLaunchEventsPluginsList; // Accessed only on worker thread private AppPredictor mHomeAppPredictor; - private AppPredictor mRecentsOverviewPredictor; public PredictionAppTracker(Context context) { mContext = context; @@ -77,10 +90,6 @@ public class PredictionAppTracker extends AppLaunchTracker InvariantDeviceProfile.INSTANCE.get(mContext).addOnChangeListener(this::onIdpChanged); mMessageHandler.sendEmptyMessage(MSG_INIT); - - mAppLaunchEventsPluginsList = new ArrayList<>(); - PluginManagerWrapper.INSTANCE.get(context) - .addPluginListener(this, AppLaunchEventsPlugin.class, true); } @UiThread @@ -97,10 +106,7 @@ public class PredictionAppTracker extends AppLaunchTracker mHomeAppPredictor.destroy(); mHomeAppPredictor = null; } - if (mRecentsOverviewPredictor != null) { - mRecentsOverviewPredictor.destroy(); - mRecentsOverviewPredictor = null; - } + StatsLogCompatManager.LOGS_CONSUMER.remove(this); } @WorkerThread @@ -142,7 +148,7 @@ public class PredictionAppTracker extends AppLaunchTracker // Initialize the clients int count = InvariantDeviceProfile.INSTANCE.get(mContext).numAllAppsColumns; mHomeAppPredictor = createPredictor(Client.HOME, count); - mRecentsOverviewPredictor = createPredictor(Client.OVERVIEW, count); + StatsLogCompatManager.LOGS_CONSUMER.add(this); return true; } case MSG_DESTROY: { @@ -157,12 +163,7 @@ public class PredictionAppTracker extends AppLaunchTracker } case MSG_PREDICT: { if (mHomeAppPredictor != null) { - String client = (String) msg.obj; - if (Client.HOME.id.equals(client)) { - mHomeAppPredictor.requestPredictionUpdate(); - } else { - mRecentsOverviewPredictor.requestPredictionUpdate(); - } + mHomeAppPredictor.requestPredictionUpdate(); } return true; } @@ -179,98 +180,142 @@ public class PredictionAppTracker extends AppLaunchTracker if (DBG) { Log.d(TAG, String.format("Sent immediate message to update %s", client)); } - - // Relay onReturnedToHome to every plugin. - mAppLaunchEventsPluginsList.forEach(AppLaunchEventsPlugin::onReturnedToHome); } - @Override - @UiThread - public void onStartShortcut(String packageName, String shortcutId, UserHandle user, - String container) { - // TODO: Use the full shortcut info - AppTarget target = new AppTarget.Builder( - new AppTargetId("shortcut:" + shortcutId), packageName, user) - .setClassName(shortcutId) - .build(); - - sendLaunch(target, container); - - // Relay onStartShortcut info to every connected plugin. - mAppLaunchEventsPluginsList - .forEach(plugin -> plugin.onStartShortcut( - packageName, - shortcutId, - user, - container != null ? container : CONTAINER_DEFAULT) - ); - - } - - @Override - @UiThread - public void onStartApp(ComponentName cn, UserHandle user, String container) { - if (cn != null) { - AppTarget target = new AppTarget.Builder( - new AppTargetId("app:" + cn), cn.getPackageName(), user) - .setClassName(cn.getClassName()) + @AnyThread + private void sendEvent(LauncherAtom.ItemInfo atomInfo, int eventId) { + AppTarget target = toAppTarget(atomInfo); + if (target != null) { + AppTargetEvent event = new AppTargetEvent.Builder(target, eventId) + .setLaunchLocation(getContainer(atomInfo)) .build(); - sendLaunch(target, container); - - // Relay onStartApp to every connected plugin. - mAppLaunchEventsPluginsList - .forEach(plugin -> plugin.onStartApp( - cn, - user, - container != null ? container : CONTAINER_DEFAULT) - ); + Message.obtain(mMessageHandler, MSG_LAUNCH, event).sendToTarget(); } } @Override - @UiThread - public void onDismissApp(ComponentName cn, UserHandle user, String container) { - if (cn == null) return; - AppTarget target = new AppTarget.Builder( - new AppTargetId("app: " + cn), cn.getPackageName(), user) - .setClassName(cn.getClassName()) - .build(); - sendDismiss(target, container); - - // Relay onDismissApp to every connected plugin. - mAppLaunchEventsPluginsList - .forEach(plugin -> plugin.onDismissApp( - cn, - user, - container != null ? container : CONTAINER_DEFAULT) - ); + public void consume(EventEnum event, LauncherAtom.ItemInfo atomInfo) { + if (event == LAUNCHER_APP_LAUNCH_TAP + || event == LAUNCHER_TASK_LAUNCH_SWIPE_DOWN + || event == LAUNCHER_TASK_LAUNCH_TAP + || event == LAUNCHER_QUICKSWITCH_RIGHT + || event == LAUNCHER_QUICKSWITCH_LEFT) { + sendEvent(atomInfo, AppTargetEvent.ACTION_LAUNCH); + } else if (event == LAUNCHER_ITEM_DROPPED_ON_DONT_SUGGEST) { + sendEvent(atomInfo, AppTargetEvent.ACTION_DISMISS); + } } - @UiThread - private void sendEvent(AppTarget target, String container, int eventId) { - AppTargetEvent event = new AppTargetEvent.Builder(target, eventId) - .setLaunchLocation(container == null ? CONTAINER_DEFAULT : container) - .build(); - Message.obtain(mMessageHandler, MSG_LAUNCH, event).sendToTarget(); + @Nullable + private AppTarget toAppTarget(LauncherAtom.ItemInfo info) { + UserHandle userHandle = Process.myUserHandle(); + if (info.getIsWork()) { + userHandle = UserCache.INSTANCE.get(mContext).getUserProfiles().stream() + .filter(((Predicate) userHandle::equals).negate()) + .findAny() + .orElse(null); + } + if (userHandle == null) { + return null; + } + ComponentName cn = null; + String id = null; + + switch (info.getItemCase()) { + case APPLICATION: { + LauncherAtom.Application app = info.getApplication(); + if ((cn = parseNullable(app.getComponentName())) != null) { + id = "app:" + cn.getPackageName(); + } + break; + } + case SHORTCUT: { + LauncherAtom.Shortcut si = info.getShortcut(); + if (!TextUtils.isEmpty(si.getShortcutId()) + && (cn = parseNullable(si.getShortcutName())) != null) { + id = "shortcut:" + si.getShortcutId(); + } + break; + } + case WIDGET: { + LauncherAtom.Widget widget = info.getWidget(); + if ((cn = parseNullable(widget.getComponentName())) != null) { + id = "widget:" + cn.getPackageName(); + } + break; + } + case TASK: { + LauncherAtom.Task task = info.getTask(); + if ((cn = parseNullable(task.getComponentName())) != null) { + id = "app:" + cn.getPackageName(); + } + break; + } + case FOLDER_ICON: { + id = "folder:" + SystemClock.uptimeMillis(); + cn = new ComponentName(mContext.getPackageName(), "#folder"); + } + } + if (id != null && cn != null) { + return new AppTarget.Builder(new AppTargetId(id), cn.getPackageName(), userHandle) + .setClassName(cn.getClassName()) + .build(); + } + return null; } - @UiThread - private void sendLaunch(AppTarget target, String container) { - sendEvent(target, container, AppTargetEvent.ACTION_LAUNCH); + private String getContainer(LauncherAtom.ItemInfo info) { + ContainerInfo ci = info.getContainerInfo(); + switch (ci.getContainerCase()) { + case WORKSPACE: { + // In case the item type is not widgets, the spaceX and spanY default to 1. + int spanX = info.getWidget().getSpanX(); + int spanY = info.getWidget().getSpanY(); + return getWorkspaceContainerString(ci.getWorkspace(), spanX, spanY); + } + case HOTSEAT: { + return getHotseatContainerString(ci.getHotseat()); + } + case TASK_SWITCHER_CONTAINER: { + return "task-switcher"; + } + case ALL_APPS_CONTAINER: { + return "all-apps"; + } + case SEARCH_RESULT_CONTAINER: { + return "search-results"; + } + case PREDICTED_HOTSEAT_CONTAINER: { + return "predictions/hotseat"; + } + case PREDICTION_CONTAINER: { + return "predictions"; + } + case FOLDER: { + FolderContainer fc = ci.getFolder(); + switch (fc.getParentContainerCase()) { + case WORKSPACE: + return "folder/" + getWorkspaceContainerString(fc.getWorkspace(), 1, 1); + case HOTSEAT: + return "folder/" + getHotseatContainerString(fc.getHotseat()); + } + return "folder"; + } + } + return ""; } - @UiThread - private void sendDismiss(AppTarget target, String container) { - sendEvent(target, container, AppTargetEvent.ACTION_DISMISS); + private static String getWorkspaceContainerString(WorkspaceContainer wc, int spanX, int spanY) { + return String.format(Locale.ENGLISH, "workspace/%d/[%d,%d]/[%d,%d]", + wc.getPageIndex(), wc.getGridX(), wc.getGridY(), spanX, spanY); } - @Override - public void onPluginConnected(AppLaunchEventsPlugin appLaunchEventsPlugin, Context context) { - mAppLaunchEventsPluginsList.add(appLaunchEventsPlugin); + private static String getHotseatContainerString(HotseatContainer hc) { + return String.format(Locale.ENGLISH, "hotseat/%d", hc.getIndex()); } - @Override - public void onPluginDisconnected(AppLaunchEventsPlugin appLaunchEventsPlugin) { - mAppLaunchEventsPluginsList.remove(appLaunchEventsPlugin); + private static ComponentName parseNullable(String componentNameString) { + return TextUtils.isEmpty(componentNameString) + ? null : ComponentName.unflattenFromString(componentNameString); } } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java index 44691d3bb0..e11c701640 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java @@ -56,7 +56,6 @@ import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.keyboard.FocusIndicatorHelper; import com.android.launcher3.keyboard.FocusIndicatorHelper.SimpleFocusIndicatorHelper; import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider; -import com.android.launcher3.model.AppLaunchTracker; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.ItemInfoWithIcon; @@ -93,9 +92,6 @@ public class PredictionRowView extends LinearLayout implements private static final Interpolator ALPHA_FACTOR_INTERPOLATOR = (t) -> (t < 0.8f) ? 0 : (t - 0.8f) / 0.2f; - private static final OnClickListener PREDICTION_CLICK_LISTENER = - ItemClickHandler.getInstance(AppLaunchTracker.CONTAINER_PREDICTIONS); - private final Launcher mLauncher; private final PredictionUiStateManager mPredictionUiStateManager; private int mNumPredictedAppsPerRow; @@ -246,7 +242,7 @@ public class PredictionRowView extends LinearLayout implements while (getChildCount() < mNumPredictedAppsPerRow) { BubbleTextView icon = (BubbleTextView) inflater.inflate( R.layout.all_apps_icon, this, false); - icon.setOnClickListener(PREDICTION_CLICK_LISTENER); + icon.setOnClickListener(ItemClickHandler.INSTANCE); icon.setOnLongClickListener(ItemLongClickListener.INSTANCE_ALL_APPS); icon.setLongPressTimeoutFactor(1f); icon.setOnFocusChangeListener(mFocusHelper); diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java index a0f6b044ba..830c1032ba 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java @@ -75,8 +75,7 @@ public class PredictionUiStateManager implements StateListener, // TODO (b/129421797): Update the client constants public enum Client { - HOME("home"), - OVERVIEW("overview"); + HOME("home"); public final String id; @@ -91,10 +90,9 @@ public class PredictionUiStateManager implements StateListener, private final Context mContext; private final DynamicItemCache mDynamicItemCache; - private final List[] mPredictionServicePredictions; + private List mPredictionServicePredictions = Collections.emptyList(); private int mMaxIconsPerRow; - private Client mActiveClient; private AllAppsContainerView mAppsView; @@ -108,16 +106,10 @@ public class PredictionUiStateManager implements StateListener, mDynamicItemCache = new DynamicItemCache(context, this::onAppsUpdated); - mActiveClient = Client.HOME; - InvariantDeviceProfile idp = LauncherAppState.getIDP(context); mMaxIconsPerRow = idp.numColumns; idp.addOnChangeListener(this); - mPredictionServicePredictions = new List[Client.values().length]; - for (int i = 0; i < mPredictionServicePredictions.length; i++) { - mPredictionServicePredictions[i] = Collections.emptyList(); - } mGettingValidPredictionResults = Utilities.getDevicePrefs(context) .getBoolean(LAST_PREDICTION_ENABLED_STATE, true); @@ -130,18 +122,6 @@ public class PredictionUiStateManager implements StateListener, mMaxIconsPerRow = profile.numColumns; } - public Client getClient() { - return mActiveClient; - } - - public void switchClient(Client client) { - if (client == mActiveClient) { - return; - } - mActiveClient = client; - dispatchOnChange(true); - } - public void setTargetAppsView(AllAppsContainerView appsView) { if (mAppsView != null) { mAppsView.getAppsStore().removeUpdateListener(this); @@ -195,10 +175,8 @@ public class PredictionUiStateManager implements StateListener, } private void updatePredictionStateAfterCallback() { - boolean validResults = false; - for (List l : mPredictionServicePredictions) { - validResults |= l != null && !l.isEmpty(); - } + boolean validResults = mPredictionServicePredictions != null + && !mPredictionServicePredictions.isEmpty(); if (validResults != mGettingValidPredictionResults) { mGettingValidPredictionResults = validResults; Utilities.getDevicePrefs(mContext).edit() @@ -210,7 +188,7 @@ public class PredictionUiStateManager implements StateListener, public AppPredictor.Callback appPredictorCallback(Client client) { return targets -> { - mPredictionServicePredictions[client.ordinal()] = targets; + mPredictionServicePredictions = targets; updatePredictionStateAfterCallback(); }; } @@ -238,7 +216,7 @@ public class PredictionUiStateManager implements StateListener, state.apps = new ArrayList<>(); - List appTargets = mPredictionServicePredictions[mActiveClient.ordinal()]; + List appTargets = mPredictionServicePredictions; if (!appTargets.isEmpty()) { for (AppTarget appTarget : appTargets) { ComponentKey key; diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index 9a03d92e48..bdbd1e955d 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -34,8 +34,6 @@ import android.os.Bundle; import android.util.Log; import android.view.View; -import androidx.annotation.Nullable; - import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; @@ -129,12 +127,11 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { } @Override - public boolean startActivitySafely(View v, Intent intent, ItemInfo item, - @Nullable String sourceContainer) { + public boolean startActivitySafely(View v, Intent intent, ItemInfo item) { if (mHotseatPredictionController != null) { mHotseatPredictionController.setPauseUIUpdate(true); } - return super.startActivitySafely(v, intent, item, sourceContainer); + return super.startActivitySafely(v, intent, item); } @Override diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java index de83caf162..9310685e30 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java @@ -24,6 +24,7 @@ import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MOD import android.animation.Animator; import android.animation.AnimatorSet; +import android.app.ActivityManager.RunningTaskInfo; import android.util.Log; import android.view.animation.Interpolator; @@ -52,17 +53,17 @@ final class AppToOverviewAnimationProvider> extend private final BaseActivityInterface mActivityInterface; // The id of the currently running task that is transitioning to overview. - private final int mTargetTaskId; + private final RunningTaskInfo mTargetTask; private final RecentsAnimationDeviceState mDeviceState; private T mActivity; private RecentsView mRecentsView; AppToOverviewAnimationProvider( - BaseActivityInterface activityInterface, int targetTaskId, + BaseActivityInterface activityInterface, RunningTaskInfo targetTask, RecentsAnimationDeviceState deviceState) { mActivityInterface = activityInterface; - mTargetTaskId = targetTaskId; + mTargetTask = targetTask; mDeviceState = deviceState; } @@ -73,7 +74,7 @@ final class AppToOverviewAnimationProvider> extend * @param wasVisible true if it was visible before */ boolean onActivityReady(T activity, Boolean wasVisible) { - activity.getOverviewPanel().showCurrentTask(mTargetTaskId); + activity.getOverviewPanel().showCurrentTask(mTargetTask); AbstractFloatingView.closeAllOpenViews(activity, wasVisible); BaseActivityInterface.AnimationFactory factory = mActivityInterface.prepareRecentsUI( mDeviceState, @@ -122,7 +123,8 @@ final class AppToOverviewAnimationProvider> extend wallpaperTargets, MODE_CLOSING); // Use the top closing app to determine the insets for the animation - RemoteAnimationTargetCompat runningTaskTarget = targets.findTask(mTargetTaskId); + RemoteAnimationTargetCompat runningTaskTarget = mTargetTask == null ? null + : targets.findTask(mTargetTask.taskId); if (runningTaskTarget == null) { Log.e(TAG, "No closing app"); return pa.buildAnim(); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java index a63f3a802f..b49299d2fe 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java @@ -15,6 +15,8 @@ */ package com.android.quickstep; +import static android.widget.Toast.LENGTH_SHORT; + import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC; @@ -27,11 +29,13 @@ import android.graphics.Rect; import android.os.Build; import android.util.Log; import android.view.MotionEvent; +import android.widget.Toast; import androidx.annotation.CallSuper; import androidx.annotation.UiThread; import com.android.launcher3.DeviceProfile; +import com.android.launcher3.R; import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.util.VibratorWrapper; @@ -138,10 +142,10 @@ public abstract class BaseSwipeUpHandler, Q extend mRecentsView.getNextPageTaskView().launchTask(false /* animate */, true /* freezeTaskList */); } else { - int taskId = mRecentsView.getNextPageTaskView().getTask().key.id; if (!mCanceled) { - TaskView nextTask = mRecentsView.getTaskView(taskId); + TaskView nextTask = mRecentsView.getNextPageTaskView(); if (nextTask != null) { + int taskId = nextTask.getTask().key.id; mGestureState.updateLastStartedTaskId(taskId); boolean hasTaskPreviouslyAppeared = mGestureState.getPreviouslyAppearedTaskIds() .contains(taskId); @@ -158,6 +162,10 @@ public abstract class BaseSwipeUpHandler, Q extend mRecentsAnimationController.finish(true /* toRecents */, null); } }, MAIN_EXECUTOR.getHandler()); + } else { + mActivityInterface.onLaunchTaskFailed(); + Toast.makeText(mContext, R.string.activity_not_available, LENGTH_SHORT).show(); + mRecentsAnimationController.finish(true /* toRecents */, null); } } mCanceled = false; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java index 6c4c5d3f4d..5905695b4a 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java @@ -38,7 +38,6 @@ import static com.android.quickstep.GestureState.STATE_END_TARGET_ANIMATION_FINI import static com.android.quickstep.GestureState.STATE_END_TARGET_SET; import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHED; import static com.android.quickstep.MultiStateCallback.DEBUG_STATES; -import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS; import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.HIDE; import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.PEEK; import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD; @@ -60,6 +59,7 @@ import android.view.ViewTreeObserver.OnDrawListener; import android.view.WindowInsets; import android.view.animation.Interpolator; +import androidx.annotation.Nullable; import androidx.annotation.UiThread; import com.android.launcher3.AbstractFloatingView; @@ -70,6 +70,7 @@ import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.logging.StatsLogManager; +import com.android.launcher3.logging.StatsLogManager.StatsLogger; import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; @@ -266,10 +267,6 @@ public abstract class BaseSwipeUpHandlerV2, Q exte mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED | STATE_RESUME_LAST_TASK, this::notifyTransitionCancelled); - mGestureState.runOnceAtState(STATE_END_TARGET_SET, - () -> mDeviceState.onEndTargetCalculated(mGestureState.getEndTarget(), - mActivityInterface)); - if (!ENABLE_QUICKSTEP_LIVE_TILE.get()) { mStateCallback.addChangeListener(STATE_APP_CONTROLLER_RECEIVED | STATE_LAUNCHER_PRESENT | STATE_SCREENSHOT_VIEW_SHOWN | STATE_CAPTURE_SCREENSHOT, @@ -313,12 +310,6 @@ public abstract class BaseSwipeUpHandlerV2, Q exte } setupRecentsViewUi(); - - if (mDeviceState.getNavMode() == TWO_BUTTONS) { - // If the device is in two button mode, swiping up will show overview with predictions - // so we need to kick off switching to the overview predictions as soon as possible - mActivityInterface.updateOverviewPredictionState(); - } linkRecentsViewScroll(); return true; @@ -400,6 +391,11 @@ public abstract class BaseSwipeUpHandlerV2, Q exte mGestureState.getActivityInterface().setOnDeferredActivityLaunchCallback( mOnDeferredActivityLaunch); + mGestureState.runOnceAtState(STATE_END_TARGET_SET, + () -> mDeviceState.getRotationTouchHelper(). + onEndTargetCalculated(mGestureState.getEndTarget(), + mActivityInterface)); + notifyGestureStartedAsync(); } @@ -423,7 +419,7 @@ public abstract class BaseSwipeUpHandlerV2, Q exte } protected void notifyGestureAnimationStartToRecents() { - mRecentsView.onGestureAnimationStart(mGestureState.getRunningTaskId()); + mRecentsView.onGestureAnimationStart(mGestureState.getRunningTask()); } private void launcherFrameDrawn() { @@ -451,12 +447,6 @@ public abstract class BaseSwipeUpHandlerV2, Q exte @Override public void onMotionPauseChanged(boolean isPaused) { setShelfState(isPaused ? PEEK : HIDE, ShelfPeekAnim.INTERPOLATOR, ShelfPeekAnim.DURATION); - - if (mDeviceState.isFullyGesturalNavMode() && isPaused) { - // In fully gestural nav mode, switch to overview predictions once the user has paused - // (this is a no-op if the predictions are already in that state) - mActivityInterface.updateOverviewPredictionState(); - } } public void maybeUpdateRecentsAttachedState() { @@ -555,14 +545,6 @@ public abstract class BaseSwipeUpHandlerV2, Q exte @Override public void updateFinalShift() { - if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { - if (mRecentsAnimationTargets != null) { - LiveTileOverlay.INSTANCE.update( - mTaskViewSimulator.getCurrentCropRect(), - mTaskViewSimulator.getCurrentCornerRadius()); - } - } - final boolean passed = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW; if (passed != mPassedOverviewThreshold) { mPassedOverviewThreshold = passed; @@ -573,6 +555,14 @@ public abstract class BaseSwipeUpHandlerV2, Q exte updateSysUiFlags(mCurrentShift.value); applyWindowTransform(); + if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { + if (mRecentsAnimationTargets != null) { + LiveTileOverlay.INSTANCE.update( + mTaskViewSimulator.getCurrentRect(), + mTaskViewSimulator.getCurrentCornerRadius()); + } + } + updateLauncherTransitionProgress(); } @@ -889,22 +879,7 @@ public abstract class BaseSwipeUpHandlerV2, Q exte animateToProgress(startShift, endShift, duration, interpolator, endTarget, velocityPxPerMs); } - private void doLogGesture(GestureEndTarget endTarget) { - DeviceProfile dp = mDp; - if (dp == null || mDownPos == null) { - // We probably never received an animation controller, skip logging. - return; - } - - int pageIndex = endTarget == LAST_TASK - ? LOG_NO_OP_PAGE_INDEX - : mRecentsView.getNextPage(); - UserEventDispatcher.newInstance(mContext).logStateChangeAction( - mLogAction, mLogDirection, - (int) mDownPos.x, (int) mDownPos.y, - ContainerType.NAVBAR, ContainerType.APP, - endTarget.containerType, - pageIndex); + private void doLogGesture(GestureEndTarget endTarget, @Nullable TaskView targetTask) { StatsLogManager.EventEnum event; switch (endTarget) { case HOME: @@ -922,10 +897,29 @@ public abstract class BaseSwipeUpHandlerV2, Q exte default: event = IGNORE; } - StatsLogManager.newInstance(mContext).logger() + StatsLogger logger = StatsLogManager.newInstance(mContext).logger() .withSrcState(LAUNCHER_STATE_BACKGROUND) - .withDstState(StatsLogManager.containerTypeToAtomState(endTarget.containerType)) - .log(event); + .withDstState(StatsLogManager.containerTypeToAtomState(endTarget.containerType)); + if (targetTask != null) { + logger.withItemInfo(targetTask.getItemInfo()); + } + logger.log(event); + + + DeviceProfile dp = mDp; + if (dp == null || mDownPos == null) { + // We probably never received an animation controller, skip logging. + return; + } + int pageIndex = endTarget == LAST_TASK + ? LOG_NO_OP_PAGE_INDEX + : mRecentsView.getNextPage(); + UserEventDispatcher.newInstance(mContext).logStateChangeAction( + mLogAction, mLogDirection, + (int) mDownPos.x, (int) mDownPos.y, + ContainerType.NAVBAR, ContainerType.APP, + endTarget.containerType, + pageIndex); } /** Animates to the given progress, where 0 is the current app and 1 is overview. */ @@ -1130,7 +1124,7 @@ public abstract class BaseSwipeUpHandlerV2, Q exte private void resumeLastTask() { mRecentsAnimationController.finish(false /* toRecents */, null); ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", false); - doLogGesture(LAST_TASK); + doLogGesture(LAST_TASK, null); reset(); } @@ -1145,6 +1139,7 @@ public abstract class BaseSwipeUpHandlerV2, Q exte @UiThread private void startNewTaskInternal() { + TaskView taskToLaunch = mRecentsView == null ? null : mRecentsView.getNextPageTaskView(); startNewTask(success -> { if (!success) { reset(); @@ -1153,7 +1148,7 @@ public abstract class BaseSwipeUpHandlerV2, Q exte endLauncherTransitionController(); updateSysUiFlags(1 /* windowProgress == overview */); } - doLogGesture(NEW_TASK); + doLogGesture(NEW_TASK, taskToLaunch); }); } @@ -1298,7 +1293,7 @@ public abstract class BaseSwipeUpHandlerV2, Q exte () -> mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED)); } ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", true); - doLogGesture(HOME); + doLogGesture(HOME, mRecentsView == null ? null : mRecentsView.getCurrentPageTaskView()); } protected abstract void finishRecentsControllerToHome(Runnable callback); @@ -1313,7 +1308,7 @@ public abstract class BaseSwipeUpHandlerV2, Q exte mRecentsView.onSwipeUpAnimationSuccess(); SystemUiProxy.INSTANCE.get(mContext).onOverviewShown(false, TAG); - doLogGesture(RECENTS); + doLogGesture(RECENTS, mRecentsView.getCurrentPageTaskView()); reset(); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java index 33b9cdee08..d1da0c1c10 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java @@ -140,7 +140,7 @@ public final class FallbackActivityInterface extends } @Override - public void onExitOverview(RecentsAnimationDeviceState deviceState, Runnable exitRunnable) { + public void onExitOverview(RotationTouchHelper deviceState, Runnable exitRunnable) { // no-op, fake landscape not supported for 3P } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java index fc7a119f21..1909f4772e 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java @@ -140,7 +140,6 @@ public class FallbackSwipeHandler extends private final long mDuration; FallbackHomeAnimationFactory(long duration) { - super(null); mDuration = duration; if (mRunningOverHome) { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java index edefbe1252..b02035516d 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java @@ -105,7 +105,7 @@ public final class LauncherActivityInterface extends // recents, we assume the first task is invisible, making translation off by one task. launcher.getStateManager().reapplyState(); launcher.getRootView().setForceHideBackArrow(false); - notifyRecentsOfOrientation(deviceState); + notifyRecentsOfOrientation(deviceState.getRotationTouchHelper()); } @Override @@ -120,7 +120,7 @@ public final class LauncherActivityInterface extends @Override public AnimationFactory prepareRecentsUI(RecentsAnimationDeviceState deviceState, boolean activityVisible, Consumer callback) { - notifyRecentsOfOrientation(deviceState); + notifyRecentsOfOrientation(deviceState.getRotationTouchHelper()); DefaultAnimationFactory factory = new DefaultAnimationFactory(callback) { @Override public void setShelfState(ShelfAnimState shelfState, Interpolator interpolator, @@ -228,7 +228,7 @@ public final class LauncherActivityInterface extends @Override - public void onExitOverview(RecentsAnimationDeviceState deviceState, Runnable exitRunnable) { + public void onExitOverview(RotationTouchHelper deviceState, Runnable exitRunnable) { final StateManager stateManager = getCreatedActivity().getStateManager(); stateManager.addStateListener( new StateManager.StateListener() { @@ -244,11 +244,11 @@ public final class LauncherActivityInterface extends }); } - private void notifyRecentsOfOrientation(RecentsAnimationDeviceState deviceState) { + private void notifyRecentsOfOrientation(RotationTouchHelper rotationTouchHelper) { // reset layout on swipe to home RecentsView recentsView = getCreatedActivity().getOverviewPanel(); - recentsView.setLayoutRotation(deviceState.getCurrentActiveRotation(), - deviceState.getDisplayRotation()); + recentsView.setLayoutRotation(rotationTouchHelper.getCurrentActiveRotation(), + rotationTouchHelper.getDisplayRotation()); } @Override @@ -261,16 +261,6 @@ public final class LauncherActivityInterface extends return true; } - @Override - public void updateOverviewPredictionState() { - Launcher launcher = getCreatedActivity(); - if (launcher == null) { - return; - } - PredictionUiStateManager.INSTANCE.get(launcher).switchClient( - PredictionUiStateManager.Client.OVERVIEW); - } - @Override public int getContainerType() { final Launcher launcher = getVisibleLauncher(); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandlerV2.java index fa7d2689f3..052d0a68a6 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandlerV2.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandlerV2.java @@ -16,6 +16,7 @@ package com.android.quickstep; import static com.android.launcher3.LauncherState.NORMAL; +import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION; import android.animation.AnimatorSet; import android.content.Context; @@ -28,6 +29,7 @@ import androidx.annotation.NonNull; import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.views.FloatingIconView; +import com.android.quickstep.util.RectFSpringAnim; import com.android.quickstep.util.StaggeredWorkspaceAnim; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; @@ -72,36 +74,39 @@ public class LauncherSwipeHandlerV2 extends mActivity.getRootView().setForceHideBackArrow(true); mActivity.setHintUserWillBeActive(); - homeAnimFactory = new HomeAnimationFactory(floatingIconView) { - - @Override - public RectF getWindowTargetRect() { - if (canUseWorkspaceView) { + if (canUseWorkspaceView) { + // We want the window alpha to be 0 once this threshold is met, so that the + // FolderIconView can be seen morphing into the icon shape. + float windowAlphaThreshold = 1f - SHAPE_PROGRESS_DURATION; + homeAnimFactory = new LauncherHomeAnimationFactory() { + @Override + public RectF getWindowTargetRect() { return iconLocation; - } else { - return super.getWindowTargetRect(); } - } - @NonNull - @Override - public AnimatorPlaybackController createActivityAnimationToHome() { - // 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( - NORMAL, accuracy, 0 /* animComponents */); - } + @Override + public void setAnimation(RectFSpringAnim anim) { + anim.addAnimatorListener(floatingIconView); + floatingIconView.setOnTargetChangeListener(anim::onTargetPositionChanged); + floatingIconView.setFastFinishRunnable(anim::end); + } - @Override - public void playAtomicAnimation(float velocity) { - new StaggeredWorkspaceAnim(mActivity, velocity, - true /* animateOverviewScrim */).start(); - } - }; + @Override + public void update(RectF currentRect, float progress, float radius) { + floatingIconView.update(currentRect, 1f, progress, windowAlphaThreshold, + radius, false); + } + @Override + public void onCancel() { + floatingIconView.fastFinish(); + } + }; + } else { + homeAnimFactory = new LauncherHomeAnimationFactory(); + } } else { - homeAnimFactory = new HomeAnimationFactory(null) { + homeAnimFactory = new HomeAnimationFactory() { @Override public AnimatorPlaybackController createActivityAnimationToHome() { return AnimatorPlaybackController.wrap(new AnimatorSet(), duration); @@ -118,4 +123,22 @@ public class LauncherSwipeHandlerV2 extends mRecentsAnimationController.finish( true /* toRecents */, callback, true /* sendUserLeaveHint */); } + + private class LauncherHomeAnimationFactory extends HomeAnimationFactory { + @NonNull + @Override + public AnimatorPlaybackController createActivityAnimationToHome() { + // 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( + NORMAL, accuracy, 0 /* animComponents */); + } + + @Override + public void playAtomicAnimation(float velocity) { + new StaggeredWorkspaceAnim(mActivity, velocity, + true /* animateOverviewScrim */).start(); + } + } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java index 434a929b5c..dca33789e5 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java @@ -29,7 +29,6 @@ import android.view.ViewConfiguration; import androidx.annotation.BinderThread; -import com.android.launcher3.appprediction.PredictionUiStateManager; import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.userevent.nano.LauncherLogProto; @@ -165,7 +164,7 @@ public class OverviewCommandHelper { mActivityInterface = mOverviewComponentObserver.getActivityInterface(); mCreateTime = SystemClock.elapsedRealtime(); mAnimationProvider = new AppToOverviewAnimationProvider<>(mActivityInterface, - RecentsModel.getRunningTaskId(), mDeviceState); + ActivityManagerWrapper.getInstance().getRunningTask(), mDeviceState); // Preload the plan mRecentsModel.getTasks(null); @@ -227,10 +226,6 @@ public class OverviewCommandHelper { LauncherLogProto.ContainerType.TASKSWITCHER); mUserEventLogged = true; } - - // Switch prediction client to overview - PredictionUiStateManager.INSTANCE.get(activity).switchClient( - PredictionUiStateManager.Client.OVERVIEW); return mAnimationProvider.onActivityReady(activity, wasVisible); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeUpAnimationLogic.java index dc8f1c54c8..e54a21c073 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeUpAnimationLogic.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeUpAnimationLogic.java @@ -17,7 +17,6 @@ package com.android.quickstep; import static com.android.launcher3.anim.Interpolators.ACCEL_1_5; import static com.android.launcher3.anim.Interpolators.DEACCEL; -import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION; import android.animation.Animator; import android.content.Context; @@ -28,7 +27,6 @@ import android.graphics.RectF; import android.view.animation.Interpolator; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.annotation.UiThread; import com.android.launcher3.DeviceProfile; @@ -37,7 +35,6 @@ import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.touch.PagedOrientationHandler; -import com.android.launcher3.views.FloatingIconView; import com.android.quickstep.util.RectFSpringAnim; import com.android.quickstep.util.TaskViewSimulator; import com.android.quickstep.util.TransformParams; @@ -85,7 +82,8 @@ public abstract class SwipeUpAnimationLogic { mTransformParams = transformParams; mTaskViewSimulator.setLayoutRotation( - mDeviceState.getCurrentActiveRotation(), mDeviceState.getDisplayRotation()); + mDeviceState.getRotationTouchHelper().getCurrentActiveRotation(), + mDeviceState.getRotationTouchHelper().getDisplayRotation()); } protected void initTransitionEndpoints(DeviceProfile dp) { @@ -148,12 +146,6 @@ public abstract class SwipeUpAnimationLogic { protected abstract class HomeAnimationFactory { - public FloatingIconView mIconView; - - public HomeAnimationFactory(@Nullable FloatingIconView iconView) { - mIconView = iconView; - } - public @NonNull RectF getWindowTargetRect() { PagedOrientationHandler orientationHandler = getOrientationHandler(); DeviceProfile dp = mDp; @@ -174,6 +166,12 @@ public abstract class SwipeUpAnimationLogic { public void playAtomicAnimation(float velocity) { // No-op } + + public void setAnimation(RectFSpringAnim anim) { } + + public void update(RectF currentRect, float progress, float radius) { } + + public void onCancel() { } } /** @@ -184,8 +182,6 @@ public abstract class SwipeUpAnimationLogic { protected RectFSpringAnim createWindowAnimationToHome(float startProgress, HomeAnimationFactory homeAnimationFactory) { final RectF targetRect = homeAnimationFactory.getWindowTargetRect(); - final FloatingIconView fiv = homeAnimationFactory.mIconView; - final boolean isFloatingIconView = fiv != null; mWindowTransitionController.setPlayFraction(startProgress / mDragLengthFactor); mTaskViewSimulator.apply(mTransformParams.setProgress(startProgress)); @@ -203,11 +199,7 @@ public abstract class SwipeUpAnimationLogic { windowToHomePositionMap.mapRect(startRect); RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mContext); - if (isFloatingIconView) { - anim.addAnimatorListener(fiv); - fiv.setOnTargetChangeListener(anim::onTargetPositionChanged); - fiv.setFastFinishRunnable(anim::end); - } + homeAnimationFactory.setAnimation(anim); SpringAnimationRunner runner = new SpringAnimationRunner( homeAnimationFactory, cropRectF, homeToWindowPositionMap); @@ -242,32 +234,27 @@ public abstract class SwipeUpAnimationLogic { final RectF mWindowCurrentRect = new RectF(); final Matrix mHomeToWindowPositionMap; + final HomeAnimationFactory mAnimationFactory; - final FloatingIconView mFIV; final AnimatorPlaybackController mHomeAnim; final RectF mCropRectF; final float mStartRadius; final float mEndRadius; - final float mWindowAlphaThreshold; SpringAnimationRunner(HomeAnimationFactory factory, RectF cropRectF, Matrix homeToWindowPositionMap) { + mAnimationFactory = factory; mHomeAnim = factory.createActivityAnimationToHome(); mCropRectF = cropRectF; mHomeToWindowPositionMap = homeToWindowPositionMap; cropRectF.roundOut(mCropRect); - mFIV = factory.mIconView; // End on a "round-enough" radius so that the shape reveal doesn't have to do too much // rounding at the end of the animation. mStartRadius = mTaskViewSimulator.getCurrentCornerRadius(); mEndRadius = cropRectF.width() / 2f; - - // We want the window alpha to be 0 once this threshold is met, so that the - // FolderIconView can be seen morphing into the icon shape. - mWindowAlphaThreshold = mFIV != null ? 1f - SHAPE_PROGRESS_DURATION : 1f; } @Override @@ -282,10 +269,7 @@ public abstract class SwipeUpAnimationLogic { .setCornerRadius(cornerRadius); mTransformParams.applySurfaceParams(mTransformParams.createSurfaceParams(this)); - if (mFIV != null) { - mFIV.update(currentRect, 1f, progress, - mWindowAlphaThreshold, mMatrix.mapRadius(cornerRadius), false); - } + mAnimationFactory.update(currentRect, progress, mMatrix.mapRadius(cornerRadius)); } @Override @@ -298,9 +282,7 @@ public abstract class SwipeUpAnimationLogic { @Override public void onCancel() { - if (mFIV != null) { - mFIV.fastFinish(); - } + mAnimationFactory.onCancel(); } @Override diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java index e9614d1351..db512fa0f9 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java @@ -19,6 +19,7 @@ package com.android.quickstep; import static android.view.Surface.ROTATION_0; import static com.android.launcher3.util.MainThreadInitializedObject.forOverride; +import static com.android.quickstep.views.OverviewActionsView.DISABLED_NO_THUMBNAIL; import static com.android.quickstep.views.OverviewActionsView.DISABLED_ROTATED; import android.annotation.SuppressLint; @@ -146,26 +147,29 @@ public class TaskOverlayFactory implements ResourceBasedOverride { */ public void initOverlay(Task task, ThumbnailData thumbnail, Matrix matrix, boolean rotated) { - final boolean isAllowedByPolicy = thumbnail.isRealSnapshot; + getActionsView().updateDisabledFlags(DISABLED_NO_THUMBNAIL, thumbnail == null); - getActionsView().updateDisabledFlags(DISABLED_ROTATED, rotated); + if (thumbnail != null) { + getActionsView().updateDisabledFlags(DISABLED_ROTATED, rotated); + final boolean isAllowedByPolicy = thumbnail.isRealSnapshot; - getActionsView().setCallbacks(new OverlayUICallbacks() { - @Override - public void onShare() { - if (isAllowedByPolicy) { - mImageApi.startShareActivity(); - } else { - showBlockedByPolicyMessage(); + getActionsView().setCallbacks(new OverlayUICallbacks() { + @Override + public void onShare() { + if (isAllowedByPolicy) { + mImageApi.startShareActivity(); + } else { + showBlockedByPolicyMessage(); + } } - } - @SuppressLint("NewApi") - @Override - public void onScreenshot() { - saveScreenshot(task); - } - }); + @SuppressLint("NewApi") + @Override + public void onScreenshot() { + saveScreenshot(task); + } + }); + } } /** diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java index 6e0b517b25..8837c0ec75 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java @@ -61,7 +61,6 @@ import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.logging.UserEventDispatcher; -import com.android.launcher3.model.AppLaunchTracker; import com.android.launcher3.provider.RestoreDbTask; import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.testing.TestLogging; @@ -258,6 +257,7 @@ public class TouchInteractionService extends Service implements PluginListener mAM.getRunningTask(false /* filterOnlyVisibleRecents */))); } return gestureState; @@ -660,7 +661,7 @@ public class TouchInteractionService extends Service implements PluginListener mAM.getRunningTask(true /* filterOnlyVisibleRecents */))); ComponentName homeComponent = mOverviewComponentObserver.getHomeIntent().getComponent(); ComponentName runningComponent = @@ -771,13 +772,7 @@ public class TouchInteractionService extends Service implements PluginListener { - AppLaunchTracker.INSTANCE.get(TouchInteractionService.this); - return false; - }).register(overviewIntent); - } else if (fromInit) { + if (activityInterface.getCreatedActivity() != 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. diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java index d20bbe9780..a946304779 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java @@ -63,12 +63,6 @@ public class FallbackRecentsView extends RecentsView mActivity.startHome(); } - @Override - public boolean shouldUseMultiWindowTaskSizeStrategy() { - // Just use the activity task size for multi-window as well. - return false; - } - /** * When starting gesture interaction from home, we add a temporary invisible tile corresponding * to the home task. This allows us to handle quick-switch similarly to a quick-switching @@ -76,7 +70,7 @@ public class FallbackRecentsView extends RecentsView */ public void onGestureAnimationStartOnHome(RunningTaskInfo homeTaskInfo) { mHomeTaskInfo = homeTaskInfo; - onGestureAnimationStart(homeTaskInfo == null ? -1 : homeTaskInfo.taskId); + onGestureAnimationStart(homeTaskInfo); } /** @@ -107,14 +101,15 @@ public class FallbackRecentsView extends RecentsView } @Override - protected boolean shouldAddDummyTaskView(int runningTaskId) { - if (mHomeTaskInfo != null && mHomeTaskInfo.taskId == runningTaskId + protected boolean shouldAddDummyTaskView(RunningTaskInfo runningTaskInfo) { + if (mHomeTaskInfo != null && runningTaskInfo != null && + mHomeTaskInfo.taskId == runningTaskInfo.taskId && getTaskViewCount() == 0) { // Do not add a dummy task if we are running over home with empty recents, so that we // show the empty recents message instead of showing a dummy task and later removing it. return false; } - return super.shouldAddDummyTaskView(runningTaskId); + return super.shouldAddDummyTaskView(runningTaskInfo); } @Override diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AccessibilityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AccessibilityInputConsumer.java index 5ad48ebabc..0c2c92cfb0 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AccessibilityInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AccessibilityInputConsumer.java @@ -99,7 +99,8 @@ public class AccessibilityInputConsumer extends DelegateInputConsumer { case ACTION_POINTER_DOWN: { if (mState == STATE_INACTIVE) { int pointerIndex = ev.getActionIndex(); - if (mDeviceState.isInSwipeUpTouchRegion(ev, pointerIndex) + if (mDeviceState.getRotationTouchHelper() + .isInSwipeUpTouchRegion(ev, pointerIndex) && mDelegate.allowInterceptByParent()) { setActive(ev); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java index 3a97216035..a676390ce3 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java @@ -147,7 +147,7 @@ public class DeviceLockedInputConsumer implements InputConsumer, if (!mThresholdCrossed) { // Cancel interaction in case of multi-touch interaction int ptrIdx = ev.getActionIndex(); - if (!mDeviceState.isInSwipeUpTouchRegion(ev, ptrIdx)) { + if (!mDeviceState.getRotationTouchHelper().isInSwipeUpTouchRegion(ev, ptrIdx)) { int action = ev.getAction(); ev.setAction(ACTION_CANCEL); finishTouchTracking(ev); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java index 26df9c7b93..6259f1f9fe 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java @@ -59,6 +59,7 @@ import com.android.quickstep.GestureState; import com.android.quickstep.InputConsumer; import com.android.quickstep.RecentsAnimationCallbacks; import com.android.quickstep.RecentsAnimationDeviceState; +import com.android.quickstep.RotationTouchHelper; import com.android.quickstep.TaskAnimationManager; import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.CachedEventDispatcher; @@ -86,6 +87,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC private final NavBarPosition mNavBarPosition; private final TaskAnimationManager mTaskAnimationManager; private final GestureState mGestureState; + private final RotationTouchHelper mRotationTouchHelper; private RecentsAnimationCallbacks mActiveCallbacks; private final CachedEventDispatcher mRecentsViewDispatcher = new CachedEventDispatcher(); private final InputMonitorCompat mInputMonitorCompat; @@ -163,6 +165,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC mPassedPilferInputSlop = mPassedWindowMoveSlop = continuingPreviousGesture; mDisableHorizontalSwipe = !mPassedPilferInputSlop && disableHorizontalSwipe; + mRotationTouchHelper = mDeviceState.getRotationTouchHelper(); } @Override @@ -230,7 +233,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC if (!mPassedPilferInputSlop) { // Cancel interaction in case of multi-touch interaction int ptrIdx = ev.getActionIndex(); - if (!mDeviceState.isInSwipeUpTouchRegion(ev, ptrIdx)) { + if (!mRotationTouchHelper.isInSwipeUpTouchRegion(ev, ptrIdx)) { forceCancelGesture(ev); } } @@ -424,7 +427,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC @Override public void notifyOrientationSetup() { - mDeviceState.onStartGesture(); + mRotationTouchHelper.onStartGesture(); } @Override diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java index 3cafd423ca..41203319b1 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java @@ -205,13 +205,15 @@ public class StaggeredWorkspaceAnim { ResourceProvider rp = DynamicResource.provider(v.getContext()); float stiffness = rp.getFloat(R.dimen.staggered_stiffness); float damping = rp.getFloat(R.dimen.staggered_damping_ratio); + float endTransY = 0; + float springVelocity = Math.abs(mVelocity) * Math.signum(endTransY - mSpringTransY); ValueAnimator springTransY = new SpringAnimationBuilder(v.getContext()) .setStiffness(stiffness) .setDampingRatio(damping) .setMinimumVisibleChange(1f) .setStartValue(mSpringTransY) - .setEndValue(0) - .setStartVelocity(mVelocity) + .setEndValue(endTransY) + .setStartVelocity(springVelocity) .build(v, VIEW_TRANSLATE_Y); springTransY.setStartDelay(startDelay); springTransY.addListener(new AnimatorListenerAdapter() { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java index c9ed498af1..64ae1e0479 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java @@ -15,6 +15,7 @@ */ package com.android.quickstep.util; +import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; import static com.android.launcher3.states.RotationHelper.deltaRotation; import static com.android.launcher3.touch.PagedOrientationHandler.MATRIX_POST_TRANSLATE; import static com.android.quickstep.util.RecentsOrientedState.postDisplayRotation; @@ -197,6 +198,15 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { return mTempRectF; } + /** + * Returns the current task bounds in the Launcher coordinate space. + */ + public RectF getCurrentRect() { + RectF result = getCurrentCropRect(); + mMatrix.mapRect(result); + return result; + } + public RecentsOrientedState getOrientationState() { return mOrientationState; } @@ -295,6 +305,10 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { builder.withMatrix(mMatrix) .withWindowCrop(mTmpCropRect) .withCornerRadius(getCurrentCornerRadius()); + + if (ENABLE_QUICKSTEP_LIVE_TILE.get() && params.getRecentsSurface() != null) { + builder.withRelativeLayerTo(params.getRecentsSurface(), Integer.MAX_VALUE); + } } /** diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TransformParams.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TransformParams.java index 0135f7472c..756331dcdf 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TransformParams.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TransformParams.java @@ -16,6 +16,7 @@ package com.android.quickstep.util; import android.util.FloatProperty; +import android.view.SurfaceControl; import com.android.launcher3.Utilities; import com.android.launcher3.anim.Interpolators; @@ -58,6 +59,7 @@ public class TransformParams { private float mCornerRadius; private RemoteAnimationTargets mTargetSet; private SurfaceTransactionApplier mSyncTransactionApplier; + private SurfaceControl mRecentsSurface; private BuilderProxy mHomeBuilderProxy = BuilderProxy.ALWAYS_VISIBLE; private BuilderProxy mBaseBuilderProxy = BuilderProxy.ALWAYS_VISIBLE; @@ -138,6 +140,8 @@ public class TransformParams { public SurfaceParams[] createSurfaceParams(BuilderProxy proxy) { RemoteAnimationTargets targets = mTargetSet; SurfaceParams[] surfaceParams = new SurfaceParams[targets.unfilteredApps.length]; + mRecentsSurface = getRecentsSurface(targets); + for (int i = 0; i < targets.unfilteredApps.length; i++) { RemoteAnimationTargetCompat app = targets.unfilteredApps[i]; SurfaceParams.Builder builder = new SurfaceParams.Builder(app.leash); @@ -165,6 +169,20 @@ public class TransformParams { return surfaceParams; } + private static SurfaceControl getRecentsSurface(RemoteAnimationTargets targets) { + for (int i = 0; i < targets.unfilteredApps.length; i++) { + RemoteAnimationTargetCompat app = targets.unfilteredApps[i]; + if (app.mode == targets.targetMode) { + if (app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_RECENTS) { + return app.leash.getSurfaceControl(); + } + } else { + return app.leash.getSurfaceControl(); + } + } + return null; + } + // Pubic getters so outside packages can read the values. public float getProgress() { @@ -179,6 +197,10 @@ public class TransformParams { return mCornerRadius; } + public SurfaceControl getRecentsSurface() { + return mRecentsSurface; + } + public RemoteAnimationTargets getTargetSet() { return mTargetSet; } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/AllAppsEduView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/AllAppsEduView.java index 0979c071bb..c06dd9c0bd 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/AllAppsEduView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/AllAppsEduView.java @@ -16,6 +16,7 @@ package com.android.quickstep.views; import static com.android.launcher3.LauncherState.ALL_APPS; +import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.anim.Interpolators.ACCEL; import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; import static com.android.launcher3.anim.Interpolators.LINEAR; @@ -42,8 +43,10 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.Utilities; +import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.Interpolators; +import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.util.Themes; @@ -51,6 +54,7 @@ import com.android.quickstep.util.MultiValueUpdateListener; /** * View used to educate the user on how to access All Apps when in No Nav Button navigation mode. + * Consumes all touches until after the animation is completed and the view is removed. */ public class AllAppsEduView extends AbstractFloatingView { @@ -110,9 +114,19 @@ public class AllAppsEduView extends AbstractFloatingView { return (type & TYPE_ALL_APPS_EDU) != 0; } + @Override + public boolean onBackPressed() { + return true; + } + + @Override + public boolean canInterceptEventsInSystemGestureRegion() { + return true; + } + @Override public boolean onControllerInterceptTouchEvent(MotionEvent ev) { - return mAnimation != null && mAnimation.isRunning(); + return true; } private void playAnimation() { @@ -139,7 +153,12 @@ public class AllAppsEduView extends AbstractFloatingView { config.userControlled = false; AnimatorPlaybackController stateAnimationController = mLauncher.getStateManager().createAnimationToNewWorkspace(ALL_APPS, config); - float maxAllAppsProgress = 0.15f; + float maxAllAppsProgress = mLauncher.getDeviceProfile().isLandscape ? 0.35f : 0.15f; + + AllAppsTransitionController allAppsController = mLauncher.getAllAppsController(); + PendingAnimation allAppsAlpha = new PendingAnimation(config.duration); + allAppsController.setAlphas(ALL_APPS, config, allAppsAlpha); + mAnimation.play(allAppsAlpha.buildAnim()); ValueAnimator intro = ValueAnimator.ofFloat(0, 1f); intro.setInterpolator(LINEAR); @@ -191,7 +210,8 @@ public class AllAppsEduView extends AbstractFloatingView { @Override public void onAnimationEnd(Animator animation) { mAnimation = null; - stateAnimationController.dispatchOnCancel(); + // Handles cancelling the animation used to hint towards All Apps. + mLauncher.getStateManager().goToState(NORMAL, false); handleClose(false); } }); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java index 846b94463f..1034234138 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java @@ -31,7 +31,6 @@ import android.animation.ObjectAnimator; import android.annotation.TargetApi; import android.content.Context; import android.os.Build; -import android.os.UserHandle; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.Surface; @@ -41,20 +40,15 @@ import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.Hotseat; import com.android.launcher3.LauncherState; import com.android.launcher3.anim.Interpolators; -import com.android.launcher3.appprediction.PredictionUiStateManager; -import com.android.launcher3.appprediction.PredictionUiStateManager.Client; -import com.android.launcher3.model.AppLaunchTracker; import com.android.launcher3.statehandlers.DepthController; import com.android.launcher3.statemanager.StateManager.StateListener; import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper; -import com.android.launcher3.util.TraceHelper; import com.android.launcher3.views.ScrimView; import com.android.quickstep.LauncherActivityInterface; import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.util.TransformParams; import com.android.systemui.plugins.PluginListener; import com.android.systemui.plugins.RecentsExtraCard; -import com.android.systemui.shared.recents.model.Task; /** * {@link RecentsView} used in Launcher activity @@ -180,18 +174,6 @@ public class LauncherRecentsView extends RecentsView super.onTaskLaunchAnimationEnd(success); } - @Override - public void onTaskLaunched(Task task) { - UserHandle user = UserHandle.of(task.key.userId); - AppLaunchTracker.INSTANCE.get(getContext()).onStartApp(task.getTopComponent(), user, - AppLaunchTracker.CONTAINER_OVERVIEW); - } - - @Override - public boolean shouldUseMultiWindowTaskSizeStrategy() { - return TraceHelper.whitelistIpcs("isInMultiWindowMode", mActivity::isInMultiWindowMode); - } - @Override public void scrollTo(int x, int y) { super.scrollTo(x, y); @@ -237,9 +219,6 @@ public class LauncherRecentsView extends RecentsView super.reset(); setLayoutRotation(Surface.ROTATION_0, Surface.ROTATION_0); - // We are moving to home or some other UI with no recents. Switch back to the home client, - // the home predictions should have been updated when the activity was resumed. - PredictionUiStateManager.INSTANCE.get(getContext()).switchClient(Client.HOME); } @Override diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java index a2da39855c..79d57c55a2 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java @@ -70,12 +70,14 @@ public class OverviewActionsView extends FrameLayo @IntDef(flag = true, value = { DISABLED_SCROLLING, - DISABLED_ROTATED}) + DISABLED_ROTATED, + DISABLED_NO_THUMBNAIL}) @Retention(RetentionPolicy.SOURCE) public @interface ActionsDisabledFlags { } public static final int DISABLED_SCROLLING = 1 << 0; public static final int DISABLED_ROTATED = 1 << 1; + public static final int DISABLED_NO_THUMBNAIL = 1 << 2; private static final int INDEX_CONTENT_ALPHA = 0; private static final int INDEX_VISIBILITY_ALPHA = 1; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java index 7b24b03f2b..1ad02a963d 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java @@ -55,10 +55,8 @@ import android.animation.LayoutTransition.TransitionListener; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.annotation.TargetApi; -import android.app.ActivityManager; -import android.content.ComponentName; +import android.app.ActivityManager.RunningTaskInfo; import android.content.Context; -import android.content.Intent; import android.content.res.Configuration; import android.graphics.Canvas; import android.graphics.Point; @@ -135,6 +133,7 @@ import com.android.quickstep.util.TransformParams; import com.android.systemui.plugins.ResourceProvider; import com.android.systemui.shared.recents.IPinnedStackAnimationListener; import com.android.systemui.shared.recents.model.Task; +import com.android.systemui.shared.recents.model.Task.TaskKey; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.LauncherEventUtil; @@ -147,7 +146,7 @@ import java.util.function.Consumer; /** * A list of recent tasks. */ -@TargetApi(Build.VERSION_CODES.P) +@TargetApi(Build.VERSION_CODES.R) public abstract class RecentsView extends PagedView implements Insettable, TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback, InvariantDeviceProfile.OnIDPChangeListener, TaskVisualsChangeListener, @@ -377,7 +376,7 @@ public abstract class RecentsView extends PagedView mOrientationState.setMultiWindowMode(inMultiWindowMode); setLayoutRotation(mOrientationState.getTouchRotation(), mOrientationState.getDisplayRotation()); - rotateAllChildTasks(); + updateChildTaskOrientations(); } if (!inMultiWindowMode && mOverviewStateEnabled) { // TODO: Re-enable layout transitions for addition of the unpinned task @@ -1041,13 +1040,13 @@ public abstract class RecentsView extends PagedView /** * Called when a gesture from an app is starting. */ - public void onGestureAnimationStart(int runningTaskId) { + public void onGestureAnimationStart(RunningTaskInfo runningTaskInfo) { // This needs to be called before the other states are set since it can create the task view if (mOrientationState.setGestureActive(true)) { updateOrientationHandler(); } - showCurrentTask(runningTaskId); + showCurrentTask(runningTaskInfo); setEnableFreeScroll(false); setEnableDrawingLiveTile(false); setRunningTaskHidden(true); @@ -1078,7 +1077,7 @@ public abstract class RecentsView extends PagedView pa.addListener(AnimationSuccessListener.forRunnable(() -> { setLayoutRotation(newRotation, mOrientationState.getDisplayRotation()); mActivity.getDragLayer().recreateControllers(); - rotateAllChildTasks(); + updateChildTaskOrientations(); setRecentsChangedOrientation(false).start(); })); pa.start(); @@ -1099,7 +1098,7 @@ public abstract class RecentsView extends PagedView } - private void rotateAllChildTasks() { + private void updateChildTaskOrientations() { for (int i = 0; i < getTaskViewCount(); i++) { getTaskViewAt(i).setOrientationState(mOrientationState); } @@ -1127,8 +1126,8 @@ public abstract class RecentsView extends PagedView /** * Returns true if we should add a dummy taskView for the running task id */ - protected boolean shouldAddDummyTaskView(int runningTaskId) { - return getTaskView(runningTaskId) == null; + protected boolean shouldAddDummyTaskView(RunningTaskInfo runningTaskInfo) { + return runningTaskInfo != null && getTaskView(runningTaskInfo.taskId) == null; } /** @@ -1137,8 +1136,8 @@ public abstract class RecentsView extends PagedView * All subsequent calls to reload will keep the task as the first item until {@link #reset()} * is called. Also scrolls the view to this task. */ - public void showCurrentTask(int runningTaskId) { - if (shouldAddDummyTaskView(runningTaskId)) { + public void showCurrentTask(RunningTaskInfo runningTaskInfo) { + if (shouldAddDummyTaskView(runningTaskInfo)) { boolean wasEmpty = getChildCount() == 0; // Add an empty view for now until the task plan is loaded and applied final TaskView taskView = mTaskViewPool.getView(); @@ -1148,10 +1147,7 @@ public abstract class RecentsView extends PagedView } // The temporary running task is only used for the duration between the start of the // gesture and the task list is loaded and applied - mTmpRunningTask = new Task(new Task.TaskKey(runningTaskId, 0, new Intent(), - new ComponentName(getContext(), getClass()), 0, 0), null, null, "", "", 0, 0, - false, true, false, false, new ActivityManager.TaskDescription(), 0, - new ComponentName("", ""), false); + mTmpRunningTask = Task.from(new TaskKey(runningTaskInfo), runningTaskInfo, false); taskView.bind(mTmpRunningTask, mOrientationState); // Measure and layout immediately so that the scroll values is updated instantly @@ -1162,7 +1158,7 @@ public abstract class RecentsView extends PagedView } boolean runningTaskTileHidden = mRunningTaskTileHidden; - setCurrentTask(runningTaskId); + setCurrentTask(runningTaskInfo == null ? -1 : runningTaskInfo.taskId); setCurrentPage(getRunningTaskIndex()); setRunningTaskViewShowScreenshot(false); setRunningTaskHidden(runningTaskTileHidden); @@ -1652,6 +1648,9 @@ public abstract class RecentsView extends PagedView super.setVisibility(visibility); if (mActionsView != null) { mActionsView.updateHiddenFlags(HIDDEN_NO_RECENTS, visibility != VISIBLE); + if (visibility != VISIBLE) { + mActionsView.updateDisabledFlags(OverviewActionsView.DISABLED_SCROLLING, false); + } } } @@ -1680,10 +1679,11 @@ public abstract class RecentsView extends PagedView : View.LAYOUT_DIRECTION_RTL); mClearAllButton.setRotation(mOrientationHandler.getDegreesRotated()); mActivity.getDragLayer().recreateControllers(); - boolean isInLandscape = mOrientationState.getTouchRotation() != 0 + boolean isInLandscape = mOrientationState.getTouchRotation() != ROTATION_0 || mOrientationState.getRecentsActivityRotation() != ROTATION_0; mActionsView.updateHiddenFlags(HIDDEN_NON_ZERO_ROTATION, !mOrientationState.canRecentsActivityRotate() && isInLandscape); + updateChildTaskOrientations(); resetPaddingFromTaskSize(); requestLayout(); // Reapply the current page to update page scrolls. @@ -1998,19 +1998,12 @@ public abstract class RecentsView extends PagedView protected void onTaskLaunchAnimationUpdate(float progress, TaskView tv) { } - public abstract boolean shouldUseMultiWindowTaskSizeStrategy(); - protected void onTaskLaunchAnimationEnd(boolean success) { if (success) { resetTaskVisuals(); } } - /** - * Called when task activity is launched - */ - public void onTaskLaunched(Task task){ } - @Override protected void notifyPageSwitchListener(int prevPage) { super.notifyPageSwitchListener(prevPage); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskMenuView.java index ef66b7a396..8b49f2c212 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskMenuView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskMenuView.java @@ -169,7 +169,9 @@ public class TaskMenuView extends AbstractFloatingView { } if (mIsOpen) { mOptionLayout.removeAllViews(); - populateAndLayoutMenu(); + if (!populateAndLayoutMenu()) { + close(false); + } } } @@ -186,14 +188,22 @@ public class TaskMenuView extends AbstractFloatingView { } mActivity.getDragLayer().addView(this); mTaskView = taskView; - populateAndLayoutMenu(); + if (!populateAndLayoutMenu()) { + return false; + } post(this::animateOpen); return true; } - private void populateAndLayoutMenu() { + /** @return true if successfully able to populate task view menu, false otherwise */ + private boolean populateAndLayoutMenu() { + if (mTaskView.getTask().icon == null) { + // Icon may not be loaded + return false; + } addMenuOptions(mTaskView); orientAroundTaskView(mTaskView); + return true; } private void addMenuOptions(TaskView taskView) { @@ -240,8 +250,10 @@ public class TaskMenuView extends AbstractFloatingView { setLayoutParams(params); setScaleX(taskView.getScaleX()); setScaleY(taskView.getScaleY()); + boolean canActivityRotate = taskView.getRecentsView() + .mOrientationState.canRecentsActivityRotate(); mOptionLayout.setOrientation(orientationHandler - .getTaskMenuLayoutOrientation(mOptionLayout)); + .getTaskMenuLayoutOrientation(canActivityRotate, mOptionLayout)); setPosition(sTempRect.left - insets.left, sTempRect.top - insets.top, taskView.getPagedOrientationHandler()); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java index b2f937f8c2..37f6faf523 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java @@ -357,7 +357,7 @@ public class TaskThumbnailView extends View implements PluginListener + + + + \ No newline at end of file diff --git a/quickstep/res/layout/gesture_tutorial_fragment.xml b/quickstep/res/layout/gesture_tutorial_fragment.xml index 459d65faf7..43bf0ea966 100644 --- a/quickstep/res/layout/gesture_tutorial_fragment.xml +++ b/quickstep/res/layout/gesture_tutorial_fragment.xml @@ -24,6 +24,14 @@ android:layout_height="match_parent" android:background="@drawable/gesture_tutorial_ripple"/> + + + android:padding="18dp" + android:src="@drawable/gesture_tutorial_close_button" + android:tint="?android:attr/textColorPrimary"/> + android:layout_marginEnd="@dimen/gesture_tutorial_title_margin_start_end"/> + android:layout_marginTop="10dp" + android:layout_marginEnd="@dimen/gesture_tutorial_subtitle_margin_start_end"/> + android:layout_marginBottom="10dp"/>