diff --git a/quickstep/res/layout/predicted_hotseat_edu.xml b/quickstep/res/layout/predicted_hotseat_edu.xml index 1dab48267b..e4e3956c6e 100644 --- a/quickstep/res/layout/predicted_hotseat_edu.xml +++ b/quickstep/res/layout/predicted_hotseat_edu.xml @@ -73,6 +73,7 @@ launcher:containerType="hotseat" /> Split Tap another app to use splitscreen + + App does not support split-screen. This action isn\'t allowed by the app or your organization diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java index c41f2ceb14..119ae907f7 100644 --- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java +++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java @@ -28,17 +28,20 @@ import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.widget.Button; +import android.widget.LinearLayout; import android.widget.TextView; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.CellLayout; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Insettable; +import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.model.data.WorkspaceItemInfo; +import com.android.launcher3.uioverrides.ApiWrapper; import com.android.launcher3.uioverrides.PredictedAppIcon; import com.android.launcher3.views.AbstractSlideInView; @@ -89,8 +92,9 @@ public class HotseatEduDialog extends AbstractSlideInView implements I mHotseatWrapper = findViewById(R.id.hotseat_wrapper); mSampleHotseat = findViewById(R.id.sample_prediction); + Context context = getContext(); DeviceProfile grid = mActivityContext.getDeviceProfile(); - Rect padding = grid.getHotseatLayoutPadding(getContext()); + Rect padding = grid.getHotseatLayoutPadding(context); mSampleHotseat.getLayoutParams().height = grid.cellHeightPx; mSampleHotseat.setGridSize(grid.numShownHotseatIcons, 1); @@ -102,6 +106,15 @@ public class HotseatEduDialog extends AbstractSlideInView implements I mDismissBtn = findViewById(R.id.no_thanks); mDismissBtn.setOnClickListener(this::onDismiss); + LinearLayout buttonContainer = findViewById(R.id.button_container); + int adjustedMarginEnd = ApiWrapper.getHotseatEndOffset(context) + - buttonContainer.getPaddingEnd(); + if (InvariantDeviceProfile.INSTANCE.get(context) + .getDeviceProfile(context).isTaskbarPresent && adjustedMarginEnd > 0) { + ((LinearLayout.LayoutParams) buttonContainer.getLayoutParams()).setMarginEnd( + adjustedMarginEnd); + } + // update ui to reflect which migration method is going to be used if (FeatureFlags.HOTSEAT_MIGRATE_TO_FOLDER.get()) { ((TextView) findViewById(R.id.hotseat_edu_content)).setText( diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionModel.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionModel.java index 080633a653..56945ba0a6 100644 --- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionModel.java +++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionModel.java @@ -16,33 +16,25 @@ package com.android.launcher3.hybridhotseat; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION; +import static com.android.launcher3.model.PredictionHelper.getAppTargetFromItemInfo; +import static com.android.launcher3.model.PredictionHelper.isTrackedForHotseatPrediction; +import static com.android.launcher3.model.PredictionHelper.wrapAppTargetWithItemLocation; import android.app.prediction.AppTarget; import android.app.prediction.AppTargetEvent; -import android.app.prediction.AppTargetId; -import android.content.ComponentName; import android.content.Context; import android.os.Bundle; -import com.android.launcher3.LauncherSettings; -import com.android.launcher3.Workspace; import com.android.launcher3.model.BgDataModel; import com.android.launcher3.model.BgDataModel.FixedContainerItems; import com.android.launcher3.model.data.ItemInfo; -import com.android.launcher3.model.data.LauncherAppWidgetInfo; -import com.android.launcher3.model.data.WorkspaceItemInfo; -import com.android.launcher3.shortcuts.ShortcutKey; import java.util.ArrayList; -import java.util.Locale; /** * Model helper for app predictions in workspace */ public class HotseatPredictionModel { - private static final String APP_LOCATION_HOTSEAT = "hotseat"; - private static final String APP_LOCATION_WORKSPACE = "workspace"; - private static final String BUNDLE_KEY_PIN_EVENTS = "pin_events"; private static final String BUNDLE_KEY_CURRENT_ITEMS = "current_items"; @@ -54,15 +46,15 @@ public class HotseatPredictionModel { ArrayList events = new ArrayList<>(); ArrayList workspaceItems = dataModel.getAllWorkspaceItems(); for (ItemInfo item : workspaceItems) { - AppTarget target = getAppTargetFromInfo(context, item); - if (target != null && !isTrackedForPrediction(item)) continue; - events.add(wrapAppTargetWithLocation(target, AppTargetEvent.ACTION_PIN, item)); + AppTarget target = getAppTargetFromItemInfo(context, item); + if (target != null && !isTrackedForHotseatPrediction(item)) continue; + events.add(wrapAppTargetWithItemLocation(target, AppTargetEvent.ACTION_PIN, item)); } ArrayList currentTargets = new ArrayList<>(); FixedContainerItems hotseatItems = dataModel.extraItems.get(CONTAINER_HOTSEAT_PREDICTION); if (hotseatItems != null) { for (ItemInfo itemInfo : hotseatItems.items) { - AppTarget target = getAppTargetFromInfo(context, itemInfo); + AppTarget target = getAppTargetFromItemInfo(context, itemInfo); if (target != null) currentTargets.add(target); } } @@ -70,56 +62,4 @@ public class HotseatPredictionModel { bundle.putParcelableArrayList(BUNDLE_KEY_CURRENT_ITEMS, currentTargets); return bundle; } - - /** - * Creates and returns for {@link AppTarget} object given an {@link ItemInfo}. Returns null - * if item is not supported prediction - */ - public static AppTarget getAppTargetFromInfo(Context context, ItemInfo info) { - if (info == null) return null; - if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET - && info instanceof LauncherAppWidgetInfo - && ((LauncherAppWidgetInfo) info).providerName != null) { - ComponentName cn = ((LauncherAppWidgetInfo) info).providerName; - return new AppTarget.Builder(new AppTargetId("widget:" + cn.getPackageName()), - cn.getPackageName(), info.user).setClassName(cn.getClassName()).build(); - } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION - && info.getTargetComponent() != null) { - ComponentName cn = info.getTargetComponent(); - return new AppTarget.Builder(new AppTargetId("app:" + cn.getPackageName()), - cn.getPackageName(), info.user).setClassName(cn.getClassName()).build(); - } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT - && info instanceof WorkspaceItemInfo) { - ShortcutKey shortcutKey = ShortcutKey.fromItemInfo(info); - //TODO: switch to using full shortcut info - return new AppTarget.Builder(new AppTargetId("shortcut:" + shortcutKey.getId()), - shortcutKey.componentName.getPackageName(), shortcutKey.user).build(); - } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) { - return new AppTarget.Builder(new AppTargetId("folder:" + info.id), - context.getPackageName(), info.user).build(); - } - return null; - } - - /** - * Creates and returns {@link AppTargetEvent} from an {@link AppTarget}, action, and item - * location using {@link ItemInfo} - */ - public static AppTargetEvent wrapAppTargetWithLocation( - AppTarget target, int action, ItemInfo info) { - String location = String.format(Locale.ENGLISH, "%s/%d/[%d,%d]/[%d,%d]", - info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT - ? APP_LOCATION_HOTSEAT : APP_LOCATION_WORKSPACE, - info.screenId, info.cellX, info.cellY, info.spanX, info.spanY); - return new AppTargetEvent.Builder(target, action).setLaunchLocation(location).build(); - } - - /** - * Helper method to determine if {@link ItemInfo} should be tracked and reported to predictors - */ - public static boolean isTrackedForPrediction(ItemInfo info) { - return info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT || ( - info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP - && info.screenId == Workspace.FIRST_SCREEN_ID); - } } diff --git a/quickstep/src/com/android/launcher3/model/AppEventProducer.java b/quickstep/src/com/android/launcher3/model/AppEventProducer.java index b665db6ffc..1305bbc7b2 100644 --- a/quickstep/src/com/android/launcher3/model/AppEventProducer.java +++ b/quickstep/src/com/android/launcher3/model/AppEventProducer.java @@ -22,6 +22,7 @@ import static android.app.prediction.AppTargetEvent.ACTION_UNPIN; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PREDICTION; +import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_CONVERTED_TO_ICON; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOTSEAT_PREDICTION_PINNED; @@ -35,6 +36,8 @@ import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCH 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.model.PredictionHelper.isTrackedForHotseatPrediction; +import static com.android.launcher3.model.PredictionHelper.isTrackedForWidgetPrediction; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; import android.annotation.TargetApi; @@ -62,7 +65,6 @@ 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.data.ItemInfo; import com.android.launcher3.pm.UserCache; import com.android.launcher3.shortcuts.ShortcutRequest; import com.android.quickstep.logging.StatsLogCompatManager.StatsLogConsumer; @@ -141,6 +143,9 @@ public class AppEventProducer implements StatsLogConsumer { if (isTrackedForHotseatPrediction(mLastDragItem)) { sendEvent(mLastDragItem, ACTION_UNPIN, CONTAINER_HOTSEAT_PREDICTION); } + if (isTrackedForWidgetPrediction(atomInfo)) { + sendEvent(atomInfo, ACTION_PIN, CONTAINER_WIDGETS_PREDICTION); + } mLastDragItem = null; } else if (event == LAUNCHER_ITEM_DROP_FOLDER_CREATED) { if (isTrackedForHotseatPrediction(atomInfo)) { @@ -158,12 +163,15 @@ public class AppEventProducer implements StatsLogConsumer { if (mLastDragItem != null && isTrackedForHotseatPrediction(mLastDragItem)) { sendEvent(mLastDragItem, ACTION_UNPIN, CONTAINER_HOTSEAT_PREDICTION); } + if (mLastDragItem != null && isTrackedForWidgetPrediction(mLastDragItem)) { + sendEvent(mLastDragItem, ACTION_UNPIN, CONTAINER_WIDGETS_PREDICTION); + } } else if (event == LAUNCHER_HOTSEAT_PREDICTION_PINNED) { if (isTrackedForHotseatPrediction(atomInfo)) { sendEvent(atomInfo, ACTION_PIN, CONTAINER_HOTSEAT_PREDICTION); } } else if (event == LAUNCHER_ONRESUME) { - AppTarget target = new AppTarget.Builder(new AppTargetId("id:launcher"), + AppTarget target = new AppTarget.Builder(new AppTargetId("launcher:launcher"), mContext.getPackageName(), Process.myUserHandle()) .build(); sendEvent(target, atomInfo, ACTION_LAUNCH, CONTAINER_PREDICTION); @@ -302,19 +310,4 @@ public class AppEventProducer implements StatsLogConsumer { return TextUtils.isEmpty(componentNameString) ? null : ComponentName.unflattenFromString(componentNameString); } - - /** - * Helper method to determine if {@link ItemInfo} should be tracked and reported to predictors - */ - private static boolean isTrackedForHotseatPrediction(LauncherAtom.ItemInfo info) { - ContainerInfo ci = info.getContainerInfo(); - switch (ci.getContainerCase()) { - case HOTSEAT: - return true; - case WORKSPACE: - return ci.getWorkspace().getPageIndex() == 0; - default: - return false; - } - } } diff --git a/quickstep/src/com/android/launcher3/model/PredictionHelper.java b/quickstep/src/com/android/launcher3/model/PredictionHelper.java new file mode 100644 index 0000000000..738dd83cbc --- /dev/null +++ b/quickstep/src/com/android/launcher3/model/PredictionHelper.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2021 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.model; + +import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.WORKSPACE; + +import android.app.prediction.AppTarget; +import android.app.prediction.AppTargetEvent; +import android.app.prediction.AppTargetId; +import android.content.ComponentName; +import android.content.Context; + +import androidx.annotation.Nullable; + +import com.android.launcher3.LauncherSettings; +import com.android.launcher3.Workspace; +import com.android.launcher3.logger.LauncherAtom; +import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.model.data.LauncherAppWidgetInfo; +import com.android.launcher3.model.data.WorkspaceItemInfo; +import com.android.launcher3.shortcuts.ShortcutKey; + +import java.util.Locale; + +/** Helper class with methods for converting launcher items to form usable by predictors */ +public final class PredictionHelper { + private static final String APP_LOCATION_HOTSEAT = "hotseat"; + private static final String APP_LOCATION_WORKSPACE = "workspace"; + + /** + * Creates and returns an {@link AppTarget} object for an {@link ItemInfo}. Returns null + * if item type is not supported in predictions + */ + @Nullable + public static AppTarget getAppTargetFromItemInfo(Context context, ItemInfo info) { + if (info == null) return null; + if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET + && info instanceof LauncherAppWidgetInfo + && ((LauncherAppWidgetInfo) info).providerName != null) { + ComponentName cn = ((LauncherAppWidgetInfo) info).providerName; + return new AppTarget.Builder(new AppTargetId("widget:" + cn.getPackageName()), + cn.getPackageName(), info.user).setClassName(cn.getClassName()).build(); + } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION + && info.getTargetComponent() != null) { + ComponentName cn = info.getTargetComponent(); + return new AppTarget.Builder(new AppTargetId("app:" + cn.getPackageName()), + cn.getPackageName(), info.user).setClassName(cn.getClassName()).build(); + } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT + && info instanceof WorkspaceItemInfo) { + ShortcutKey shortcutKey = ShortcutKey.fromItemInfo(info); + //TODO: switch to using full shortcut info + return new AppTarget.Builder(new AppTargetId("shortcut:" + shortcutKey.getId()), + shortcutKey.componentName.getPackageName(), shortcutKey.user).build(); + } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) { + return new AppTarget.Builder(new AppTargetId("folder:" + info.id), + context.getPackageName(), info.user).build(); + } + return null; + } + + /** + * Creates and returns {@link AppTargetEvent} from an {@link AppTarget}, action, and item + * location using {@link ItemInfo} + */ + public static AppTargetEvent wrapAppTargetWithItemLocation( + AppTarget target, int action, ItemInfo info) { + String location = String.format(Locale.ENGLISH, "%s/%d/[%d,%d]/[%d,%d]", + info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT + ? APP_LOCATION_HOTSEAT : APP_LOCATION_WORKSPACE, + info.screenId, info.cellX, info.cellY, info.spanX, info.spanY); + return new AppTargetEvent.Builder(target, action).setLaunchLocation(location).build(); + } + + /** + * Helper method to determine if {@link ItemInfo} should be tracked and reported to hotseat + * predictors + */ + public static boolean isTrackedForHotseatPrediction(ItemInfo info) { + return info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT || ( + info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP + && info.screenId == Workspace.FIRST_SCREEN_ID); + } + + /** + * Helper method to determine if {@link LauncherAtom.ItemInfo} should be tracked and reported to + * hotseat predictors + */ + public static boolean isTrackedForHotseatPrediction(LauncherAtom.ItemInfo info) { + LauncherAtom.ContainerInfo ci = info.getContainerInfo(); + switch (ci.getContainerCase()) { + case HOTSEAT: + return true; + case WORKSPACE: + return ci.getWorkspace().getPageIndex() == 0; + default: + return false; + } + } + + /** + * Helper method to determine if {@link ItemInfo} should be tracked and reported to widget + * predictors + */ + public static boolean isTrackedForWidgetPrediction(ItemInfo info) { + return info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET + && info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP; + } + + /** + * Helper method to determine if {@link LauncherAtom.ItemInfo} should be tracked and reported + * to widget predictors + */ + public static boolean isTrackedForWidgetPrediction(LauncherAtom.ItemInfo info) { + return info.getItemCase() == LauncherAtom.ItemInfo.ItemCase.WIDGET + && info.getContainerInfo().getContainerCase() == WORKSPACE; + } +} diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java index 55a140dffb..7794d27d26 100644 --- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java +++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java @@ -25,8 +25,12 @@ import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICA import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT; import static com.android.launcher3.Utilities.getDevicePrefs; import static com.android.launcher3.hybridhotseat.HotseatPredictionModel.convertDataModelToAppTargetBundle; +import static com.android.launcher3.model.PredictionHelper.getAppTargetFromItemInfo; +import static com.android.launcher3.model.PredictionHelper.wrapAppTargetWithItemLocation; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; +import static java.util.stream.Collectors.toCollection; + import android.app.StatsManager; import android.app.prediction.AppPredictionContext; import android.app.prediction.AppPredictionManager; @@ -39,6 +43,7 @@ import android.content.SharedPreferences; import android.content.pm.LauncherActivityInfo; import android.content.pm.LauncherApps; import android.content.pm.ShortcutInfo; +import android.os.Bundle; import android.os.UserHandle; import android.util.Log; import android.util.StatsEvent; @@ -62,6 +67,7 @@ import com.android.launcher3.util.PersistedItemArray; import com.android.quickstep.logging.StatsLogCompatManager; import com.android.systemui.shared.system.SysUiStatsLog; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; @@ -75,6 +81,7 @@ public class QuickstepModelDelegate extends ModelDelegate { public static final String LAST_PREDICTION_ENABLED_STATE = "last_prediction_enabled_state"; private static final String LAST_SNAPSHOT_TIME_MILLIS = "LAST_SNAPSHOT_TIME_MILLIS"; + private static final String BUNDLE_KEY_ADDED_APP_WIDGETS = "added_app_widgets"; private static final int NUM_OF_RECOMMENDED_WIDGETS_PREDICATION = 20; private static final boolean IS_DEBUG = false; @@ -272,6 +279,7 @@ public class QuickstepModelDelegate extends ModelDelegate { registerWidgetsPredictor(apm.createAppPredictionSession( new AppPredictionContext.Builder(context) .setUiSurface("widgets") + .setExtras(getBundleForWidgetsOnWorkspace(context, mDataModel)) .setPredictedTargetCount(NUM_OF_RECOMMENDED_WIDGETS_PREDICATION) .build())); } @@ -306,12 +314,41 @@ public class QuickstepModelDelegate extends ModelDelegate { } private void onAppTargetEvent(AppTargetEvent event, int client) { - PredictorState state = client == CONTAINER_PREDICTION ? mAllAppsState : mHotseatState; + PredictorState state; + switch(client) { + case CONTAINER_PREDICTION: + state = mAllAppsState; + break; + case CONTAINER_WIDGETS_PREDICTION: + state = mWidgetsRecommendationState; + break; + case CONTAINER_HOTSEAT_PREDICTION: + default: + state = mHotseatState; + break; + } if (state.predictor != null) { state.predictor.notifyAppTargetEvent(event); } } + private Bundle getBundleForWidgetsOnWorkspace(Context context, BgDataModel dataModel) { + Bundle bundle = new Bundle(); + ArrayList widgetEvents = + dataModel.getAllWorkspaceItems().stream() + .filter(PredictionHelper::isTrackedForWidgetPrediction) + .map(item -> { + AppTarget target = getAppTargetFromItemInfo(context, item); + if (target == null) return null; + return wrapAppTargetWithItemLocation( + target, AppTargetEvent.ACTION_PIN, item); + }) + .filter(Objects::nonNull) + .collect(toCollection(ArrayList::new)); + bundle.putParcelableArrayList(BUNDLE_KEY_ADDED_APP_WIDGETS, widgetEvents); + return bundle; + } + static class PredictorState { public final FixedContainerItems items; diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index 3ab73bbc5c..e8aa2fa3c7 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -444,6 +444,10 @@ public abstract class AbsSwipeUpHandler, mAnimationFactory = mActivityInterface.prepareRecentsUI(mDeviceState, mWasLauncherAlreadyVisible, this::onAnimatorPlaybackControllerCreated); maybeUpdateRecentsAttachedState(false /* animate */); + if (mGestureState.getEndTarget() != null) { + // Update the end target in case the gesture ended before we init. + mAnimationFactory.setEndTarget(mGestureState.getEndTarget()); + } }; if (mWasLauncherAlreadyVisible) { // Launcher is visible, but might be about to stop. Thus, if we prepare recents diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java index e2441edee6..73d14246a0 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java @@ -59,7 +59,6 @@ import android.os.SystemProperties; import android.os.UserManager; import android.provider.Settings; import android.text.TextUtils; -import android.util.DisplayMetrics; import android.view.MotionEvent; import android.view.Surface; @@ -581,8 +580,7 @@ public class RecentsAnimationDeviceState implements final Info displayInfo = mDisplayController.getInfo(); return (mRotationTouchHelper.touchInOneHandedModeRegion(ev) && displayInfo.rotation != Surface.ROTATION_90 - && displayInfo.rotation != Surface.ROTATION_270 - && displayInfo.densityDpi < DisplayMetrics.DENSITY_600); + && displayInfo.rotation != Surface.ROTATION_270); } return false; } diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java index a59b0d76be..81e18f64cb 100644 --- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java +++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java @@ -274,7 +274,6 @@ abstract class TutorialController implements BackGestureAttemptCallback, mFeedbackView.findViewById(R.id.gesture_tutorial_fragment_feedback_subtitle); subtitle.setText(subtitleResId); if (isGestureSuccessful) { - hideCloseButton(); if (mTutorialFragment.isAtFinalStep()) { showActionButton(); } @@ -402,6 +401,7 @@ abstract class TutorialController implements BackGestureAttemptCallback, void transitToController() { hideFeedback(); hideActionButton(); + updateCloseButton(); updateSubtext(); updateDrawables(); updateLayout(); @@ -412,26 +412,21 @@ abstract class TutorialController implements BackGestureAttemptCallback, } } - void hideCloseButton() { - mCloseButton.setVisibility(GONE); - } - - void showCloseButton() { - mCloseButton.setVisibility(View.VISIBLE); + void updateCloseButton() { mCloseButton.setTextAppearance(Utilities.isDarkTheme(mContext) ? R.style.TextAppearance_GestureTutorial_Feedback_Subtext : R.style.TextAppearance_GestureTutorial_Feedback_Subtext_Dark); } void hideActionButton() { - showCloseButton(); + mCloseButton.setVisibility(View.VISIBLE); // Invisible to maintain the layout. mActionButton.setVisibility(View.INVISIBLE); mActionButton.setOnClickListener(null); } void showActionButton() { - hideCloseButton(); + mCloseButton.setVisibility(GONE); mActionButton.setVisibility(View.VISIBLE); mActionButton.setOnClickListener(this::onActionButtonClicked); } diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 5a455c172c..687a13a415 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -599,6 +599,8 @@ public abstract class RecentsView Toast.makeText(launcher, R.string.safemode_widget_error, Toast.LENGTH_SHORT).show(); return null; } else { + AbstractFloatingView floatingView = AbstractFloatingView.getTopOpenViewWithType( + launcher, TYPE_WIDGETS_FULL_SHEET); + if (floatingView != null) { + return (WidgetsFullSheet) floatingView; + } return WidgetsFullSheet.show(launcher, true /* animated */); } } @@ -279,7 +285,7 @@ public class OptionsPopupView extends ArrowPopup public final OnLongClickListener clickListener; public OptionItem(Context context, int labelRes, int iconRes, EventEnum eventId, - OnLongClickListener clickListener) { + OnLongClickListener clickListener) { this.labelRes = labelRes; this.label = context.getText(labelRes); this.icon = ContextCompat.getDrawable(context, iconRes); @@ -288,7 +294,7 @@ public class OptionsPopupView extends ArrowPopup } public OptionItem(CharSequence label, Drawable icon, EventEnum eventId, - OnLongClickListener clickListener) { + OnLongClickListener clickListener) { this.labelRes = 0; this.label = label; this.icon = icon; diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java index 0e3b5013d8..d5479fbd9e 100644 --- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java +++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java @@ -54,18 +54,14 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer { } private void flingForwardImpl() { - flingForwardImpl(0); - } - - private void flingForwardImpl(int rightMargin) { try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer("want to fling forward in overview")) { LauncherInstrumentation.log("Overview.flingForward before fling"); final UiObject2 overview = verifyActiveContainer(); final int leftMargin = mLauncher.getTargetInsets().left + mLauncher.getEdgeSensitivityWidth(); - mLauncher.scroll(overview, Direction.LEFT, new Rect(leftMargin + 1, 0, rightMargin, 0), - 20, false); + mLauncher.scroll(overview, Direction.LEFT, new Rect(leftMargin + 1, 0, 0, 0), 20, + false); try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer("flung forwards")) { verifyActiveContainer(); @@ -131,7 +127,7 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer { OverviewTask task = getCurrentTask(); mLauncher.assertNotNull("current task is null", task); - flingForwardImpl(task.getTaskCenterX()); + mLauncher.scrollLeftByDistance(verifyActiveContainer(), task.getVisibleWidth()); try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer("scrolled task off screen")) { diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index 9ee0e25bd7..7ffdf4cef8 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -1190,10 +1190,19 @@ public final class LauncherInstrumentation { return getVisibleBounds(container).bottom - bottomGestureStartOnScreen; } + int getRightGestureMarginInContainer(UiObject2 container) { + final int rightGestureStartOnScreen = getRightGestureStartOnScreen(); + return getVisibleBounds(container).right - rightGestureStartOnScreen; + } + int getBottomGestureStartOnScreen() { return getRealDisplaySize().y - getBottomGestureSize(); } + int getRightGestureStartOnScreen() { + return getRealDisplaySize().x - getWindowInsets().right; + } + void clickLauncherObject(UiObject2 object) { waitForObjectEnabled(object, "clickLauncherObject"); expectEvent(TestProtocol.SEQUENCE_MAIN, LauncherInstrumentation.EVENT_TOUCH_DOWN); @@ -1235,6 +1244,21 @@ public final class LauncherInstrumentation { true); } + void scrollLeftByDistance(UiObject2 container, int distance) { + final Rect containerRect = getVisibleBounds(container); + final int rightGestureMarginInContainer = getRightGestureMarginInContainer(container); + scroll( + container, + Direction.LEFT, + new Rect( + 0, + containerRect.width() - distance - rightGestureMarginInContainer, + 0, + rightGestureMarginInContainer), + 10, + true); + } + void scroll( UiObject2 container, Direction direction, Rect margins, int steps, boolean slowDown) { final Rect rect = getVisibleBounds(container); diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java index 15bddd7c88..a860e7d894 100644 --- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java +++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java @@ -53,6 +53,10 @@ public final class OverviewTask { return mTask.getVisibleBounds().height(); } + int getVisibleWidth() { + return mTask.getVisibleBounds().width(); + } + int getTaskCenterX() { return mTask.getVisibleCenter().x; }