Merge "[OneSearch] Add onesearch plugin api to trigger image from URL." into sc-v2-dev
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 6af0d60..88c98c0 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -193,6 +193,8 @@
<string name="action_split">Split</string>
<!-- Label for toast with instructions for split screen selection mode. [CHAR_LIMIT=50] -->
<string name="toast_split_select_app">Tap another app to use splitscreen</string>
+ <!-- Label for toast when app selected for split isn't supported. [CHAR_LIMIT=50] -->
+ <string name="toast_split_app_unsupported">App does not support split-screen.</string>
<!-- Message shown when an action is blocked by a policy enforced by the app or the organization managing the device. [CHAR_LIMIT=NONE] -->
<string name="blocked_by_policy">This action isn\'t allowed by the app or your organization</string>
diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionModel.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionModel.java
index 080633a..56945ba 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 @@
ArrayList<AppTargetEvent> events = new ArrayList<>();
ArrayList<ItemInfo> 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<AppTarget> 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 @@
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 b665db6..1305bbc 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 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.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.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 @@
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 @@
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 @@
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 0000000..738dd83
--- /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 55a140d..7794d27 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_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.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.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 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 @@
registerWidgetsPredictor(apm.createAppPredictionSession(
new AppPredictionContext.Builder(context)
.setUiSurface("widgets")
+ .setExtras(getBundleForWidgetsOnWorkspace(context, mDataModel))
.setPredictedTargetCount(NUM_OF_RECOMMENDED_WIDGETS_PREDICATION)
.build()));
}
@@ -306,12 +314,41 @@
}
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<AppTargetEvent> 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/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 8ae661f..172b396 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -70,7 +70,6 @@
import com.android.launcher3.views.ActivityContext;
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.SysUINavigationMode.Mode;
-import com.android.quickstep.SystemUiProxy;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.WindowManagerWrapper;
@@ -158,7 +157,8 @@
new TaskbarKeyguardController(this),
new StashedHandleViewController(this, stashedHandleView),
new TaskbarStashController(this),
- new TaskbarEduController(this));
+ new TaskbarEduController(this),
+ new TaskbarAutohideSuspendController(this));
}
public void init(TaskbarSharedState sharedState) {
@@ -375,7 +375,8 @@
* Updates the TaskbarContainer to MATCH_PARENT vs original Taskbar size.
*/
public void setTaskbarWindowFullscreen(boolean fullscreen) {
- SystemUiProxy.INSTANCE.getNoCreate().notifyTaskbarAutohideSuspend(fullscreen);
+ mControllers.taskbarAutohideSuspendController.updateFlag(
+ TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_FULLSCREEN, fullscreen);
mIsFullscreen = fullscreen;
setTaskbarWindowHeight(fullscreen ? MATCH_PARENT : mLastRequestedNonFullscreenHeight);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java
new file mode 100644
index 0000000..e42f83d
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java
@@ -0,0 +1,63 @@
+/*
+ * 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.taskbar;
+
+import androidx.annotation.IntDef;
+
+import com.android.quickstep.SystemUiProxy;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Normally Taskbar will auto-hide when entering immersive (fullscreen) apps. This controller allows
+ * us to suspend that behavior in certain cases (e.g. opening a Folder or dragging an icon).
+ */
+public class TaskbarAutohideSuspendController {
+
+ public static final int FLAG_AUTOHIDE_SUSPEND_FULLSCREEN = 1 << 0;
+ public static final int FLAG_AUTOHIDE_SUSPEND_DRAGGING = 1 << 1;
+ @IntDef(flag = true, value = {
+ FLAG_AUTOHIDE_SUSPEND_FULLSCREEN,
+ FLAG_AUTOHIDE_SUSPEND_DRAGGING,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AutohideSuspendFlag {}
+
+ private final SystemUiProxy mSystemUiProxy;
+
+ private @AutohideSuspendFlag int mAutohideSuspendFlags = 0;
+
+ public TaskbarAutohideSuspendController(TaskbarActivityContext activity) {
+ mSystemUiProxy = SystemUiProxy.INSTANCE.get(activity);
+ }
+
+ public void onDestroy() {
+ mSystemUiProxy.notifyTaskbarAutohideSuspend(false);
+ }
+
+ /**
+ * Adds or removes the given flag, then notifies system UI proxy whether to suspend auto-hide.
+ */
+ public void updateFlag(@AutohideSuspendFlag int flag, boolean enabled) {
+ if (enabled) {
+ mAutohideSuspendFlags |= flag;
+ } else {
+ mAutohideSuspendFlags &= ~flag;
+ }
+ mSystemUiProxy.notifyTaskbarAutohideSuspend(mAutohideSuspendFlags != 0);
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index 8684c29..7b0053e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -37,6 +37,7 @@
public final StashedHandleViewController stashedHandleViewController;
public final TaskbarStashController taskbarStashController;
public final TaskbarEduController taskbarEduController;
+ public final TaskbarAutohideSuspendController taskbarAutohideSuspendController;
/** Do not store this controller, as it may change at runtime. */
@NonNull public TaskbarUIController uiController = TaskbarUIController.DEFAULT;
@@ -53,7 +54,8 @@
TaskbarKeyguardController taskbarKeyguardController,
StashedHandleViewController stashedHandleViewController,
TaskbarStashController taskbarStashController,
- TaskbarEduController taskbarEduController) {
+ TaskbarEduController taskbarEduController,
+ TaskbarAutohideSuspendController taskbarAutoHideSuspendController) {
this.taskbarActivityContext = taskbarActivityContext;
this.taskbarDragController = taskbarDragController;
this.navButtonController = navButtonController;
@@ -67,6 +69,7 @@
this.stashedHandleViewController = stashedHandleViewController;
this.taskbarStashController = taskbarStashController;
this.taskbarEduController = taskbarEduController;
+ this.taskbarAutohideSuspendController = taskbarAutoHideSuspendController;
}
/**
@@ -75,6 +78,7 @@
* in constructors for now, as some controllers may still be waiting for init().
*/
public void init(TaskbarSharedState sharedState) {
+ taskbarDragController.init(this);
navbarButtonsViewController.init(this, sharedState);
if (taskbarActivityContext.isThreeButtonNav()) {
rotationButtonController.init();
@@ -101,5 +105,6 @@
taskbarUnfoldAnimationController.onDestroy();
taskbarViewController.onDestroy();
stashedHandleViewController.onDestroy();
+ taskbarAutohideSuspendController.onDestroy();
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index 1afbd17..3bcacb6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -15,9 +15,6 @@
*/
package com.android.launcher3.taskbar;
-import static android.view.View.INVISIBLE;
-import static android.view.View.VISIBLE;
-
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.Intent;
@@ -49,7 +46,6 @@
import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.graphics.DragPreviewProvider;
-import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -65,6 +61,9 @@
private final int mDragIconSize;
private final int[] mTempXY = new int[2];
+ // Initialized in init.
+ TaskbarControllers mControllers;
+
// Where the initial touch was relative to the dragged icon.
private int mRegistrationX;
private int mRegistrationY;
@@ -77,6 +76,10 @@
mDragIconSize = resources.getDimensionPixelSize(R.dimen.taskbar_icon_drag_icon_size);
}
+ public void init(TaskbarControllers controllers) {
+ mControllers = controllers;
+ }
+
/**
* Attempts to start a system drag and drop operation for the given View, using its tag to
* generate the ClipDescription and Intent.
@@ -90,19 +93,17 @@
BubbleTextView btv = (BubbleTextView) view;
mActivity.setTaskbarWindowFullscreen(true);
- view.post(() -> {
+ btv.post(() -> {
startInternalDrag(btv);
- btv.setVisibility(INVISIBLE);
+ btv.getIcon().setIsDisabled(true);
+ mControllers.taskbarAutohideSuspendController.updateFlag(
+ TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_DRAGGING, true);
});
return true;
}
private void startInternalDrag(BubbleTextView btv) {
- float iconScale = 1f;
- Drawable icon = btv.getIcon();
- if (icon instanceof FastBitmapDrawable) {
- iconScale = ((FastBitmapDrawable) icon).getAnimatedScale();
- }
+ float iconScale = btv.getIcon().getAnimatedScale();
// Clear the pressed state if necessary
btv.clearFocus();
@@ -239,16 +240,17 @@
shadowSize.set(mDragIconSize, mDragIconSize);
// The registration point was taken before the icon scaled to mDragIconSize, so
// offset the registration to where the touch is on the new size.
- int offset = (mDragIconSize - btv.getIconSize()) / 2;
- shadowTouchPoint.set(mRegistrationX + offset, mRegistrationY + offset);
+ int offsetX = (mDragIconSize - mDragObject.dragView.getDragRegionWidth()) / 2;
+ int offsetY = (mDragIconSize - mDragObject.dragView.getDragRegionHeight()) / 2;
+ shadowTouchPoint.set(mRegistrationX + offsetX, mRegistrationY + offsetY);
}
@Override
public void onDrawShadow(Canvas canvas) {
canvas.save();
- float scale = (float) mDragIconSize / btv.getIconSize();
+ float scale = mDragObject.dragView.getScaleX();
canvas.scale(scale, scale);
- btv.getIcon().draw(canvas);
+ mDragObject.dragView.draw(canvas);
canvas.restore();
}
};
@@ -330,7 +332,9 @@
private void maybeOnDragEnd() {
if (!isDragging()) {
- ((View) mDragObject.originalView).setVisibility(VISIBLE);
+ ((BubbleTextView) mDragObject.originalView).getIcon().setIsDisabled(false);
+ mControllers.taskbarAutohideSuspendController.updateFlag(
+ TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_DRAGGING, false);
}
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index e2441ed..73d1424 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -59,7 +59,6 @@
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 @@
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 a59b0d7..81e18f6 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -274,7 +274,6 @@
mFeedbackView.findViewById(R.id.gesture_tutorial_fragment_feedback_subtitle);
subtitle.setText(subtitleResId);
if (isGestureSuccessful) {
- hideCloseButton();
if (mTutorialFragment.isAtFinalStep()) {
showActionButton();
}
@@ -402,6 +401,7 @@
void transitToController() {
hideFeedback();
hideActionButton();
+ updateCloseButton();
updateSubtext();
updateDrawables();
updateLayout();
@@ -412,26 +412,21 @@
}
}
- 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 5a455c1..687a13a 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -599,6 +599,8 @@
private SplitConfigurationOptions.StagedSplitBounds mSplitBoundsConfig;
private final Toast mSplitToast = Toast.makeText(getContext(),
R.string.toast_split_select_app, Toast.LENGTH_SHORT);
+ private final Toast mSplitUnsupportedToast = Toast.makeText(getContext(),
+ R.string.toast_split_app_unsupported, Toast.LENGTH_SHORT);
/**
* Keeps track of the index of the TaskView that split screen was initialized with so we know
@@ -3878,6 +3880,11 @@
public void confirmSplitSelect(TaskView taskView) {
mSplitToast.cancel();
+ if (!taskView.getTask().isDockable) {
+ // Task not split screen supported
+ mSplitUnsupportedToast.show();
+ return;
+ }
RectF secondTaskStartingBounds = new RectF();
Rect secondTaskEndingBounds = new Rect();
// TODO(194414938) starting bounds seem slightly off, investigate
@@ -3920,6 +3927,7 @@
int duration = mActivity.getStateManager().getState().getTransitionDuration(getContext());
PendingAnimation pendingAnim = new PendingAnimation(duration);
mSplitToast.cancel();
+ mSplitUnsupportedToast.cancel();
if (!animate) {
resetFromSplitSelectionState();
return pendingAnim;
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index 03ab737..5c73fbb 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -210,7 +210,7 @@
@Override
public void onScrollChanged() {
- RecentsView rv = mTaskView.getRecentsView();
+ RecentsView rv = mActivity.getOverviewPanel();
setPosition(mTaskView.getX() - rv.getScrollX(), mTaskView.getY() - rv.getScrollY(),
rv.getOverScrollShift());
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 710afe0..4895b10 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -43,7 +43,6 @@
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -289,7 +288,6 @@
@Test
@PortraitLandscape
- @Ignore("b/203781041")
public void testOverviewForTablet() throws Exception {
if (!mLauncher.isTablet()) {
return;
diff --git a/src/com/android/launcher3/DropTargetBar.java b/src/com/android/launcher3/DropTargetBar.java
index eb42a65..9fb14f6 100644
--- a/src/com/android/launcher3/DropTargetBar.java
+++ b/src/com/android/launcher3/DropTargetBar.java
@@ -275,8 +275,12 @@
@Override
protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
- if (TestProtocol.sDebugTracing && visibility == VISIBLE) {
- Log.d(TestProtocol.NO_DROP_TARGET, "9");
+ if (TestProtocol.sDebugTracing) {
+ if (visibility == VISIBLE) {
+ Log.d(TestProtocol.NO_DROP_TARGET, "9");
+ } else {
+ Log.d(TestProtocol.NO_DROP_TARGET, "Hiding drop target", new Exception());
+ }
}
}
}
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index 33ab0d2..9774c46 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -40,6 +40,7 @@
import androidx.annotation.VisibleForTesting;
import androidx.core.content.ContextCompat;
+import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
@@ -220,6 +221,11 @@
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 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 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 0e3b501..d5479fb 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -54,18 +54,14 @@
}
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 @@
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 9ee0e25..7ffdf4c 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -1190,10 +1190,19 @@
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 @@
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 15bddd7..a860e7d 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -53,6 +53,10 @@
return mTask.getVisibleBounds().height();
}
+ int getVisibleWidth() {
+ return mTask.getVisibleBounds().width();
+ }
+
int getTaskCenterX() {
return mTask.getVisibleCenter().x;
}