Merge "Update folder preview dark theme color" into main
diff --git a/OWNERS b/OWNERS
index 38963d0..b8aae78 100644
--- a/OWNERS
+++ b/OWNERS
@@ -12,7 +12,6 @@
jonmiranda@google.com
alexchau@google.com
patmanning@google.com
-tsuharesu@google.com
awickham@google.com
# Launcher workspace eng team
diff --git a/aconfig/launcher_search.aconfig b/aconfig/launcher_search.aconfig
index fc79200..97e56b7 100644
--- a/aconfig/launcher_search.aconfig
+++ b/aconfig/launcher_search.aconfig
@@ -12,4 +12,18 @@
namespace: "launcher_search"
description: "This flag enables the animation of the Private Space container"
bug: "299294792"
+}
+
+flag {
+ name: "private_space_sys_apps_separation"
+ namespace: "launcher_search"
+ description: "This flag enables showing system apps separate in Private Space container."
+ bug: "308054233"
+}
+
+flag {
+ name: "private_space_app_installer_button"
+ namespace: "launcher_search"
+ description: "This flag enables addition of App Installer button in Private Space container."
+ bug: "308064949"
}
\ No newline at end of file
diff --git a/go/quickstep/src/com/android/launcher3/AppSharing.java b/go/quickstep/src/com/android/launcher3/AppSharing.java
index cb1f1c7..78524d1 100644
--- a/go/quickstep/src/com/android/launcher3/AppSharing.java
+++ b/go/quickstep/src/com/android/launcher3/AppSharing.java
@@ -27,6 +27,7 @@
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
@@ -64,14 +65,17 @@
private static final String TAG = "AppSharing";
private static final String FILE_PROVIDER_SUFFIX = ".overview.fileprovider";
- private static final String APP_EXSTENSION = ".apk";
+ private static final String APP_EXTENSION = ".apk";
private static final String APP_MIME_TYPE = "application/application";
private final String mSharingComponent;
private AppShareabilityManager mShareabilityMgr;
private AppSharing(Launcher launcher) {
- mSharingComponent = launcher.getText(R.string.app_sharing_component).toString();
+ String sharingComponent = Settings.Secure.getString(launcher.getContentResolver(),
+ Settings.Secure.NEARBY_SHARING_COMPONENT);
+ mSharingComponent = TextUtils.isEmpty(sharingComponent) ? launcher.getText(
+ R.string.app_sharing_component).toString() : sharingComponent;
}
private Uri getShareableUri(Context context, String path, String displayName) {
@@ -147,7 +151,7 @@
PackageInfo packageInfo = packageManager.getPackageInfo(packageName, 0);
sourceDir = packageInfo.applicationInfo.sourceDir;
appLabel = packageManager.getApplicationLabel(packageInfo.applicationInfo)
- .toString() + APP_EXSTENSION;
+ + APP_EXTENSION;
} catch (Exception e) {
Log.e(TAG, "Could not find info for package \"" + packageName + "\"");
return;
@@ -175,9 +179,7 @@
return;
}
checkShareability(/* requestUpdateIfUnknown */ false);
- mTarget.runOnUiThread(() -> {
- mPopupDataProvider.redrawSystemShortcuts();
- });
+ mTarget.runOnUiThread(mPopupDataProvider::redrawSystemShortcuts);
}
private void checkShareability(boolean requestUpdateIfUnknown) {
diff --git a/quickstep/res/layout/overview_actions_container.xml b/quickstep/res/layout/overview_actions_container.xml
index 5bd5823..0fda0bf 100644
--- a/quickstep/res/layout/overview_actions_container.xml
+++ b/quickstep/res/layout/overview_actions_container.xml
@@ -55,15 +55,6 @@
android:theme="@style/ThemeControlHighlightWorkspaceColor"
android:visibility="gone" />
- <Button
- android:id="@+id/action_save_app_pair"
- style="@style/OverviewActionButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/action_save_app_pair"
- android:theme="@style/ThemeControlHighlightWorkspaceColor"
- android:visibility="gone" />
-
<Space
android:layout_width="0dp"
android:layout_height="1dp"
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 75315fe..6912e1a 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -228,8 +228,6 @@
<string name="action_screenshot">Screenshot</string>
<!-- Label for a button that enters split screen selection mode. [CHAR_LIMIT=20] -->
<string name="action_split">Split</string>
- <!-- Label for a button that saves a new app pair. [CHAR_LIMIT=20] -->
- <string name="action_save_app_pair">Save app pair</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 split screen</string>
<string name="toast_split_select_app_cancel"><b>Cancel</b></string>
diff --git a/quickstep/src/com/android/launcher3/model/AppEventProducer.java b/quickstep/src/com/android/launcher3/model/AppEventProducer.java
index 0dde1bd..17c39af 100644
--- a/quickstep/src/com/android/launcher3/model/AppEventProducer.java
+++ b/quickstep/src/com/android/launcher3/model/AppEventProducer.java
@@ -25,6 +25,7 @@
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PREDICTION;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION;
import static com.android.launcher3.logger.LauncherAtomExtensions.ExtendedContainers.ContainerCase.DEVICE_SEARCH_RESULT_CONTAINER;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_DRAGDROP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_DISMISS_PREDICTION_UNDO;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_CONVERTED_TO_ICON;
@@ -132,7 +133,8 @@
|| event == LAUNCHER_TASK_LAUNCH_SWIPE_DOWN
|| event == LAUNCHER_TASK_LAUNCH_TAP
|| event == LAUNCHER_QUICKSWITCH_RIGHT
- || event == LAUNCHER_QUICKSWITCH_LEFT) {
+ || event == LAUNCHER_QUICKSWITCH_LEFT
+ || event == LAUNCHER_APP_LAUNCH_DRAGDROP) {
sendEvent(atomInfo, ACTION_LAUNCH, CONTAINER_PREDICTION);
} else if (event == LAUNCHER_ITEM_DROPPED_ON_DONT_SUGGEST) {
sendEvent(atomInfo, ACTION_DISMISS, CONTAINER_PREDICTION);
@@ -287,6 +289,9 @@
case SHORTCUTS_CONTAINER: {
return "deep-shortcuts";
}
+ case TASK_BAR_CONTAINER: {
+ return "taskbar";
+ }
case FOLDER: {
FolderContainer fc = ci.getFolder();
switch (fc.getParentContainerCase()) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index f6703f3..fb25ec1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -107,6 +107,7 @@
import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.touch.ItemClickHandler.ItemClickProxy;
+import com.android.launcher3.uioverrides.ApiWrapper;
import com.android.launcher3.util.ActivityOptionsWrapper;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.DisplayController;
@@ -1056,9 +1057,8 @@
} else if (info.isPromise()) {
TestLogging.recordEvent(
TestProtocol.SEQUENCE_MAIN, "start: taskbarPromiseIcon");
- intent = new PackageManagerHelper(this)
- .getMarketIntent(info.getTargetPackage())
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent = ApiWrapper.getAppMarketActivityIntent(this,
+ info.getTargetPackage(), Process.myUserHandle());
startActivity(intent);
} else if (info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
@@ -1144,7 +1144,7 @@
componentKeys,
findExactPairMatch,
foundTasks -> {
- @Nullable Task foundTask = foundTasks.get(0);
+ @Nullable Task foundTask = foundTasks[0];
if (foundTask != null) {
TaskView foundTaskView = recents.getTaskViewByTaskId(foundTask.key.id);
if (foundTaskView != null
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index 6ddf9e9..faa67be 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -23,6 +23,7 @@
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SEARCH_ACTION;
import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.EXTENDED_CONTAINERS;
import static com.android.launcher3.logger.LauncherAtomExtensions.ExtendedContainers.ContainerCase.DEVICE_SEARCH_RESULT_CONTAINER;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_DRAGDROP;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -517,6 +518,9 @@
// Note, this must be done last to ensure no AutohideSuspendFlags are active, as
// that will prevent us from stashing until the timeout.
mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
+
+ mActivity.getStatsLogManager().logger().withItemInfo(mDragObject.dragInfo)
+ .log(LAUNCHER_APP_LAUNCH_DRAGDROP);
}
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index df2a43b..7edf0d3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -219,7 +219,7 @@
Collections.singletonList(splitSelectSource.itemInfo.getComponentKey()),
false /* findExactPairMatch */,
foundTasks -> {
- @Nullable Task foundTask = foundTasks.get(0);
+ @Nullable Task foundTask = foundTasks[0];
splitSelectSource.alreadyRunningTaskId = foundTask == null
? INVALID_TASK_ID
: foundTask.key.id;
@@ -238,7 +238,7 @@
Collections.singletonList(info.getComponentKey()),
false /* findExactPairMatch */,
foundTasks -> {
- @Nullable Task foundTask = foundTasks.get(0);
+ @Nullable Task foundTask = foundTasks[0];
if (foundTask != null) {
TaskView foundTaskView = recents.getTaskViewByTaskId(foundTask.key.id);
// TODO (b/266482558): This additional null check is needed because there
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index c482911..ec9f4e5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -130,6 +130,8 @@
super(context, attrs, defStyleAttr, defStyleRes);
TaskbarActivityContext activityContext = ActivityContext.lookupContext(context);
+ setAlpha(0);
+ setVisibility(INVISIBLE);
mIconOverlapAmount = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_overlap);
mIconSpacing = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_spacing);
mIconSize = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_size);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
index 4a26559..784c560 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
@@ -17,13 +17,16 @@
package com.android.launcher3.uioverrides;
import android.app.ActivityOptions;
+import android.app.PendingIntent;
import android.app.Person;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps;
import android.content.pm.LauncherUserInfo;
import android.content.pm.ShortcutInfo;
import android.graphics.drawable.ColorDrawable;
+import android.net.Uri;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.ArrayMap;
@@ -31,9 +34,12 @@
import com.android.launcher3.Flags;
import com.android.launcher3.Utilities;
+import com.android.launcher3.proxy.ProxyActivityStarter;
+import com.android.launcher3.util.StartActivityParams;
import com.android.launcher3.util.UserIconInfo;
import com.android.quickstep.util.FadeOutRemoteTransition;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -102,6 +108,44 @@
return users;
}
+ /**
+ * Returns the list of the system packages that are installed at user creation.
+ * An empty list denotes that all system packages are installed for that user at creation.
+ */
+ public static List<String> getPreInstalledSystemPackages(Context context, UserHandle user) {
+ LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
+ if (android.os.Flags.allowPrivateProfile() && Flags.enablePrivateSpace()
+ && Flags.privateSpaceSysAppsSeparation()) {
+ return launcherApps.getPreInstalledSystemPackages(user);
+ } else {
+ return new ArrayList<>();
+ }
+ }
+
+ /**
+ * Returns an intent which can be used to start the App Market activity (Installer
+ * Activity).
+ */
+ public static Intent getAppMarketActivityIntent(Context context, String packageName,
+ UserHandle user) {
+ LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
+ if (android.os.Flags.allowPrivateProfile() && Flags.enablePrivateSpace()
+ && Flags.privateSpaceAppInstallerButton()) {
+ StartActivityParams params = new StartActivityParams((PendingIntent) null, 0);
+ params.intentSender = launcherApps.getAppMarketActivityIntent(packageName, user);
+ return ProxyActivityStarter.getLaunchIntent(context, params);
+ } else {
+ return new Intent(Intent.ACTION_VIEW)
+ .setData(new Uri.Builder()
+ .scheme("market")
+ .authority("details")
+ .appendQueryParameter("id", packageName)
+ .build())
+ .putExtra(Intent.EXTRA_REFERRER, new Uri.Builder().scheme("android-app")
+ .authority(context.getPackageName()).build());
+ }
+ }
+
private static class NoopDrawable extends ColorDrawable {
@Override
public int getIntrinsicHeight() {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 9438e00..a065387 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -644,7 +644,7 @@
Collections.singletonList(splitSelectSource.itemInfo.getComponentKey()),
false /* findExactPairMatch */,
foundTasks -> {
- @Nullable Task foundTask = foundTasks.get(0);
+ @Nullable Task foundTask = foundTasks[0];
boolean taskWasFound = foundTask != null;
splitSelectSource.alreadyRunningTaskId = taskWasFound
? foundTask.key.id
diff --git a/quickstep/src/com/android/quickstep/LauncherRestoreEventLoggerImpl.kt b/quickstep/src/com/android/quickstep/LauncherRestoreEventLoggerImpl.kt
index 645ecf4..fc450f0 100644
--- a/quickstep/src/com/android/quickstep/LauncherRestoreEventLoggerImpl.kt
+++ b/quickstep/src/com/android/quickstep/LauncherRestoreEventLoggerImpl.kt
@@ -29,8 +29,8 @@
@BackupRestoreDataType private const val DATA_TYPE_APP_PAIR = "app_pair"
}
- private val backupManager: BackupManager = BackupManager(context)
- private val restoreEventLogger: BackupRestoreEventLogger = backupManager.delayedRestoreLogger
+ private val restoreEventLogger: BackupRestoreEventLogger =
+ BackupManager(context).delayedRestoreLogger
/**
* For logging when multiple items of a given data type failed to restore.
@@ -73,6 +73,18 @@
}
/**
+ * Helper to log successfully restoring multiple items from the Favorites table.
+ *
+ * @param favoritesId The id of the item type from [Favorites] that was restored.
+ * @param count number of items that restored.
+ */
+ override fun logFavoritesItemsRestored(favoritesId: Int, count: Int) {
+ if (Flags.enableLauncherBrMetrics()) {
+ restoreEventLogger.logItemsRestored(favoritesIdToDataType(favoritesId), count)
+ }
+ }
+
+ /**
* Helper to log a failure to restore a single item from the Favorites table.
*
* @param favoritesId The id of the item type from [Favorites] that was not restored.
@@ -114,7 +126,7 @@
*/
override fun reportLauncherRestoreResults() {
if (Flags.enableLauncherBrMetrics()) {
- backupManager.reportDelayedRestoreResult(restoreEventLogger)
+ BackupManager(context).reportDelayedRestoreResult(restoreEventLogger)
}
}
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index cc582d1..312cdc9 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -43,7 +43,6 @@
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.Snackbar;
import com.android.quickstep.util.RecentsOrientedState;
-import com.android.quickstep.views.GroupedTaskView;
import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskThumbnailView;
@@ -211,19 +210,13 @@
}
}
- protected void enterSplitSelect() {
+ private void enterSplitSelect() {
RecentsView overviewPanel = mThumbnailView.getTaskView().getRecentsView();
// Task has already been dismissed
if (overviewPanel == null) return;
overviewPanel.initiateSplitSelect(mThumbnailView.getTaskView());
}
- protected void saveAppPair() {
- GroupedTaskView taskView = (GroupedTaskView) mThumbnailView.getTaskView();
- taskView.getRecentsView().getSplitSelectController().getAppPairsController()
- .saveAppPair(taskView);
- }
-
/**
* Called when the overlay is no longer used.
*/
@@ -336,10 +329,6 @@
public void onSplit() {
endLiveTileMode(TaskOverlay.this::enterSplitSelect);
}
-
- public void onSaveAppPair() {
- endLiveTileMode(TaskOverlay.this::saveAppPair);
- }
}
}
@@ -353,8 +342,5 @@
/** User wants to start split screen with current app. */
void onSplit();
-
- /** User wants to save an app pair with current group of apps. */
- void onSaveAppPair();
}
}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index d1d2f97..86ba7ef 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -86,7 +86,6 @@
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.ConstantItem;
-import com.android.launcher3.DeviceProfile;
import com.android.launcher3.EncryptionType;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.R;
@@ -725,8 +724,7 @@
final int action = event.getActionMasked();
// Note this will create a new consumer every mouse click, as after ACTION_UP from the click
// an ACTION_HOVER_ENTER will fire as well.
- boolean isHoverActionWithoutConsumer =
- event.isHoverEvent() && (mUncheckedConsumer.getType() & TYPE_CURSOR_HOVER) == 0;
+ boolean isHoverActionWithoutConsumer = isHoverActionWithoutConsumer(event);
CompoundString reasonString = action == ACTION_DOWN
? new CompoundString("onMotionEvent: ") : CompoundString.NO_OP;
if (action == ACTION_DOWN || isHoverActionWithoutConsumer) {
@@ -846,6 +844,15 @@
traceToken.close();
}
+ private boolean isHoverActionWithoutConsumer(MotionEvent event) {
+ // Only process these events when taskbar is present.
+ TaskbarActivityContext tac = mTaskbarManager.getCurrentActivityContext();
+ boolean isTaskbarPresent = tac != null && tac.getDeviceProfile().isTaskbarPresent
+ && !tac.isPhoneMode();
+ return event.isHoverEvent() && (mUncheckedConsumer.getType() & TYPE_CURSOR_HOVER) == 0
+ && isTaskbarPresent;
+ }
+
// Talkback generates hover events on touch, which we do not want to consume.
private boolean isCursorHoverEvent(MotionEvent event) {
return event.isHoverEvent() && event.getSource() == InputDevice.SOURCE_MOUSE;
diff --git a/quickstep/src/com/android/quickstep/util/AppPairsController.java b/quickstep/src/com/android/quickstep/util/AppPairsController.java
index 3ca2531..0f3c029 100644
--- a/quickstep/src/com/android/quickstep/util/AppPairsController.java
+++ b/quickstep/src/com/android/quickstep/util/AppPairsController.java
@@ -130,7 +130,7 @@
Arrays.asList(app1Key, app2Key),
false /* findExactPairMatch */,
foundTasks -> {
- @Nullable Task foundTask1 = foundTasks.get(0);
+ @Nullable Task foundTask1 = foundTasks[0];
Intent task1Intent;
int task1Id;
if (foundTask1 != null) {
@@ -147,7 +147,7 @@
LAUNCHER_APP_PAIR_LAUNCH,
task1Id);
- @Nullable Task foundTask2 = foundTasks.get(1);
+ @Nullable Task foundTask2 = foundTasks[1];
if (foundTask2 != null) {
mSplitSelectStateController.setSecondTask(foundTask2);
} else {
diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
index b2d1b43..ad9f5ea 100644
--- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
@@ -49,6 +49,7 @@
import com.android.launcher3.statehandlers.DepthController
import com.android.launcher3.statemanager.StateManager
import com.android.launcher3.statemanager.StatefulActivity
+import com.android.launcher3.taskbar.TaskbarActivityContext
import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource
import com.android.launcher3.views.BaseDragLayer
import com.android.quickstep.TaskViewUtils
@@ -390,6 +391,14 @@
"trying to launch an app pair icon, but encountered an unexpected null"
}
+ // If launching an app pair from Taskbar inside of an app context, use fade-in animation
+ // TODO (b/316485863): Replace with desired app pair launch animation
+ if (launchingIconView.context is TaskbarActivityContext) {
+ composeFadeInSplitLaunchAnimator(
+ initialTaskId, secondTaskId, info, t, finishCallback)
+ return
+ }
+
composeIconSplitLaunchAnimator(launchingIconView, info, t, finishCallback)
} else {
// Fallback case: simple fade-in animation
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index d5899e4..a9fa337 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -105,7 +105,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Collections;
+import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
@@ -225,14 +225,14 @@
* tasks (i.e. searching for a running pair of tasks.)
*/
public void findLastActiveTasksAndRunCallback(@Nullable List<ComponentKey> componentKeys,
- boolean findExactPairMatch, Consumer<List<Task>> callback) {
+ boolean findExactPairMatch, Consumer<Task[]> callback) {
mRecentTasksModel.getTasks(taskGroups -> {
if (componentKeys == null || componentKeys.isEmpty()) {
- callback.accept(Collections.emptyList());
+ callback.accept(new Task[]{});
return;
}
- List<Task> lastActiveTasks = new ArrayList<>();
+ Task[] lastActiveTasks = new Task[componentKeys.size()];
if (findExactPairMatch) {
// Loop through tasks in reverse, since they are ordered with most-recent tasks last
@@ -240,32 +240,35 @@
GroupTask groupTask = taskGroups.get(i);
if (isInstanceOfAppPair(
groupTask, componentKeys.get(0), componentKeys.get(1))) {
- lastActiveTasks.add(groupTask.task1);
+ lastActiveTasks[0] = groupTask.task1;
break;
}
}
} else {
// For each key we are looking for, add to lastActiveTasks with the corresponding
// Task (or do nothing if not found).
- for (ComponentKey key : componentKeys) {
+ for (int i = 0; i < componentKeys.size(); i++) {
+ ComponentKey key = componentKeys.get(i);
Task lastActiveTask = null;
// Loop through tasks in reverse, since they are ordered with recent tasks last
- for (int i = taskGroups.size() - 1; i >= 0; i--) {
- GroupTask groupTask = taskGroups.get(i);
+ for (int j = taskGroups.size() - 1; j >= 0; j--) {
+ GroupTask groupTask = taskGroups.get(j);
Task task1 = groupTask.task1;
// Don't add duplicate Tasks
- if (isInstanceOfComponent(task1, key) && !lastActiveTasks.contains(task1)) {
+ if (isInstanceOfComponent(task1, key)
+ && !Arrays.asList(lastActiveTasks).contains(task1)) {
lastActiveTask = task1;
break;
}
Task task2 = groupTask.task2;
- if (isInstanceOfComponent(task2, key) && !lastActiveTasks.contains(task2)) {
+ if (isInstanceOfComponent(task2, key)
+ && !Arrays.asList(lastActiveTasks).contains(task2)) {
lastActiveTask = task2;
break;
}
}
- lastActiveTasks.add(lastActiveTask);
+ lastActiveTasks[i] = lastActiveTask;
}
}
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
index b4a8c4d..2ae64ff 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -21,7 +21,6 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.RunnableList;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
@@ -391,11 +390,7 @@
@Override
public void setOverlayEnabled(boolean overlayEnabled) {
- if (FeatureFlags.enableAppPairs()) {
- super.setOverlayEnabled(overlayEnabled);
- } else {
- // Intentional no-op to prevent setting smart actions overlay on thumbnails
- }
+ // Intentional no-op to prevent setting smart actions overlay on thumbnails
}
@Override
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index c442493..b549058 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -32,7 +32,6 @@
import com.android.launcher3.Flags;
import com.android.launcher3.Insettable;
import com.android.launcher3.R;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
import com.android.launcher3.util.MultiValueAlpha;
@@ -90,27 +89,14 @@
private static final int INDEX_SCROLL_ALPHA = 5;
private static final int NUM_ALPHAS = 6;
- public @interface ScreenshotButtonHiddenFlags { }
- public static final int FLAG_MULTIPLE_TASKS_HIDE_SCREENSHOT = 1 << 0;
-
public @interface SplitButtonHiddenFlags { }
- public static final int FLAG_IS_NOT_TABLET_HIDE_SPLIT = 1 << 0;
- public static final int FLAG_MULTIPLE_TASKS_HIDE_SPLIT = 1 << 1;
+ public static final int FLAG_IS_NOT_TABLET = 1 << 0;
public @interface SplitButtonDisabledFlags { }
- public static final int FLAG_SINGLE_TASK_DISABLE_SPLIT = 1 << 0;
-
- public @interface AppPairButtonHiddenFlags { }
- public static final int FLAG_SINGLE_TASK_HIDE_APP_PAIR = 1 << 0;
+ public static final int FLAG_SINGLE_TASK = 1 << 0;
private MultiValueAlpha mMultiValueAlpha;
-
- // The screenshot button is implemented as a Button in launcher3 and NexusLauncher, but is an
- // ImageButton in go launcher (does not share a common class with Button). Take care when
- // casting this.
- private View mScreenshotButton;
private Button mSplitButton;
- private Button mSaveAppPairButton;
@ActionsHiddenFlags
private int mHiddenFlags;
@@ -118,14 +104,11 @@
@ActionsDisabledFlags
protected int mDisabledFlags;
- @ScreenshotButtonHiddenFlags
- private int mScreenshotButtonHiddenFlags;
-
@SplitButtonHiddenFlags
private int mSplitButtonHiddenFlags;
- @AppPairButtonHiddenFlags
- private int mAppPairButtonHiddenFlags;
+ @SplitButtonDisabledFlags
+ private int mSplitButtonDisabledFlags;
@Nullable
protected T mCallbacks;
@@ -152,12 +135,9 @@
mMultiValueAlpha = new MultiValueAlpha(findViewById(R.id.action_buttons), NUM_ALPHAS);
mMultiValueAlpha.setUpdateVisibility(true);
- mScreenshotButton = findViewById(R.id.action_screenshot);
- mScreenshotButton.setOnClickListener(this);
+ findViewById(R.id.action_screenshot).setOnClickListener(this);
mSplitButton = findViewById(R.id.action_split);
mSplitButton.setOnClickListener(this);
- mSaveAppPairButton = findViewById(R.id.action_save_app_pair);
- mSaveAppPairButton.setOnClickListener(this);
}
/**
@@ -179,8 +159,6 @@
mCallbacks.onScreenshot();
} else if (id == R.id.action_split) {
mCallbacks.onSplit();
- } else if (id == R.id.action_save_app_pair) {
- mCallbacks.onSaveAppPair();
}
}
@@ -223,38 +201,7 @@
}
boolean isEnabled = (mDisabledFlags & ~DISABLED_ROTATED) == 0;
LayoutUtils.setViewEnabled(this, isEnabled);
- }
-
- /**
- * Updates a batch of flags to hide and show actions buttons when a grouped task (split screen)
- * is focused.
- * @param isGroupedTask True if the focused task is a grouped task.
- */
- public void updateForGroupedTask(boolean isGroupedTask) {
- // Update flags to see if split button should be hidden.
- updateSplitButtonHiddenFlags(FLAG_MULTIPLE_TASKS_HIDE_SPLIT, isGroupedTask);
- // Update flags to see if screenshot button should be hidden.
- updateScreenshotButtonHiddenFlags(FLAG_MULTIPLE_TASKS_HIDE_SCREENSHOT, isGroupedTask);
- // Update flags to see if save app pair button should be hidden.
- updateAppPairButtonHiddenFlags(FLAG_SINGLE_TASK_HIDE_APP_PAIR, !isGroupedTask);
- }
-
- /**
- * Updates the proper flags to indicate whether the "Screenshot" button should be hidden.
- *
- * @param flag The flag to update.
- * @param enable Whether to enable the hidden flag: True will cause view to be hidden.
- */
- private void updateScreenshotButtonHiddenFlags(@ScreenshotButtonHiddenFlags int flag,
- boolean enable) {
- if (enable) {
- mScreenshotButtonHiddenFlags |= flag;
- } else {
- mScreenshotButtonHiddenFlags &= ~flag;
- }
- if (mScreenshotButton == null) return;
- boolean shouldBeVisible = mScreenshotButtonHiddenFlags == 0;
- mScreenshotButton.setVisibility(shouldBeVisible ? VISIBLE : GONE);
+ updateSplitButtonEnabledState();
}
/**
@@ -263,8 +210,7 @@
* @param flag The flag to update.
* @param enable Whether to enable the hidden flag: True will cause view to be hidden.
*/
- void updateSplitButtonHiddenFlags(@SplitButtonHiddenFlags int flag,
- boolean enable) {
+ public void updateSplitButtonHiddenFlags(@SplitButtonHiddenFlags int flag, boolean enable) {
if (enable) {
mSplitButtonHiddenFlags |= flag;
} else {
@@ -277,24 +223,18 @@
}
/**
- * Updates the proper flags to indicate whether the "Save app pair" button should be disabled.
+ * Updates the proper flags to indicate whether the "Split screen" button should be disabled.
*
* @param flag The flag to update.
- * @param enable Whether to enable the hidden flag: True will cause view to be hidden.
+ * @param enable Whether to enable the disable flag: True will cause view to be disabled.
*/
- private void updateAppPairButtonHiddenFlags(@AppPairButtonHiddenFlags int flag, boolean enable) {
- if (!FeatureFlags.enableAppPairs()) {
- return;
- }
-
+ public void updateSplitButtonDisabledFlags(@SplitButtonDisabledFlags int flag, boolean enable) {
if (enable) {
- mAppPairButtonHiddenFlags |= flag;
+ mSplitButtonDisabledFlags |= flag;
} else {
- mAppPairButtonHiddenFlags &= ~flag;
+ mSplitButtonDisabledFlags &= ~flag;
}
- if (mSaveAppPairButton == null) return;
- boolean shouldBeVisible = mAppPairButtonHiddenFlags == 0;
- mSaveAppPairButton.setVisibility(shouldBeVisible ? VISIBLE : GONE);
+ updateSplitButtonEnabledState();
}
public MultiProperty getContentAlpha() {
@@ -372,7 +312,19 @@
? R.drawable.ic_split_horizontal
: R.drawable.ic_split_vertical;
mSplitButton.setCompoundDrawablesRelativeWithIntrinsicBounds(splitIconRes, 0, 0, 0);
- mSaveAppPairButton.setCompoundDrawablesRelativeWithIntrinsicBounds(
- R.drawable.ic_save_app_pair, 0, 0, 0);
}
+
+ /**
+ * Enables/disables the "Split" button based on the status of mSplitButtonDisabledFlags and
+ * mDisabledFlags.
+ */
+ private void updateSplitButtonEnabledState() {
+ if (mSplitButton == null) {
+ return;
+ }
+ boolean isParentEnabled = (mDisabledFlags & ~DISABLED_ROTATED) == 0;
+ boolean shouldBeEnabled = mSplitButtonDisabledFlags == 0 && isParentEnabled;
+ mSplitButton.setEnabled(shouldBeEnabled);
+ }
+
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index b5576c5..ca9d13e 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -62,7 +62,8 @@
import static com.android.quickstep.util.TaskGridNavHelper.DIRECTION_UP;
import static com.android.quickstep.views.ClearAllButton.DISMISS_ALPHA;
import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
-import static com.android.quickstep.views.OverviewActionsView.FLAG_IS_NOT_TABLET_HIDE_SPLIT;
+import static com.android.quickstep.views.OverviewActionsView.FLAG_IS_NOT_TABLET;
+import static com.android.quickstep.views.OverviewActionsView.FLAG_SINGLE_TASK;
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_ACTIONS_IN_MENU;
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_DESKTOP;
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NON_ZERO_ROTATION;
@@ -3947,25 +3948,18 @@
}
/**
- * Hides all overview actions if user is halfway through split selection, shows otherwise.
- * We only show split option if:
- * * Focused view is a single app
+ * Hides all overview actions if current page is for split apps, shows otherwise
+ * If actions are showing, we only show split option if
* * Device is large screen
+ * * There are at least 2 tasks to invoke split
*/
private void updateCurrentTaskActionsVisibility() {
boolean isCurrentSplit = getCurrentPageTaskView() instanceof GroupedTaskView;
- // Update flags to see if entire actions bar should be hidden.
- if (!FeatureFlags.enableAppPairs()) {
- mActionsView.updateHiddenFlags(HIDDEN_SPLIT_SCREEN, isCurrentSplit);
- }
+ mActionsView.updateHiddenFlags(HIDDEN_SPLIT_SCREEN, isCurrentSplit);
mActionsView.updateHiddenFlags(HIDDEN_SPLIT_SELECT_ACTIVE, isSplitSelectionActive());
- // Update flags to see if actions bar should show buttons for a single task or a pair of
- // tasks.
- mActionsView.updateForGroupedTask(isCurrentSplit);
- // Update flags to see if split button should be hidden or disabled.
- mActionsView.updateSplitButtonHiddenFlags(FLAG_IS_NOT_TABLET_HIDE_SPLIT,
+ mActionsView.updateSplitButtonHiddenFlags(FLAG_IS_NOT_TABLET,
!mActivity.getDeviceProfile().isTablet);
-
+ mActionsView.updateSplitButtonDisabledFlags(FLAG_SINGLE_TASK, /*enable=*/ false);
if (isDesktopModeSupported()) {
boolean isCurrentDesktop = getCurrentPageTaskView() instanceof DesktopTaskView;
mActionsView.updateHiddenFlags(HIDDEN_DESKTOP, isCurrentDesktop);
diff --git a/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java b/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
index 3a5fb04..9ad360f 100644
--- a/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
+++ b/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
@@ -16,8 +16,6 @@
package com.android.quickstep;
-import static com.android.launcher3.ui.TaplTestsLauncher3.getAppPackageName;
-
import static org.junit.Assert.assertTrue;
import android.os.SystemProperties;
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index 39633ea..0a325ac 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -28,10 +28,12 @@
import static com.android.launcher3.ui.AbstractLauncherUiTest.resolveSystemApp;
import static com.android.launcher3.ui.AbstractLauncherUiTest.startAppFast;
import static com.android.launcher3.ui.AbstractLauncherUiTest.startTestActivity;
-import static com.android.launcher3.ui.TaplTestsLauncher3.getAppPackageName;
+import static com.android.launcher3.ui.TaplTestsLauncher3Test.getAppPackageName;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.rule.ShellCommandRule.disableHeadsUpNotification;
import static com.android.launcher3.util.rule.ShellCommandRule.getLauncherCommand;
+import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
+import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -67,7 +69,6 @@
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.RuleChain;
@@ -131,8 +132,7 @@
UiDevice.getInstance(getInstrumentation()).executeShellCommand(
getLauncherCommand(getLauncherInMyProcess()));
// b/143488140
- mDevice.pressHome();
- mDevice.waitForIdle();
+ pressHomeAndWaitForOverviewClose();
}
}
};
@@ -186,9 +186,10 @@
mLauncher.getLaunchedAppState().switchToOverview();
}
- // b/143488140
+ // Staging; will be promoted to presubmit if stable
+ @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
+
//@NavigationModeSwitch
- @Ignore
@Test
public void goToOverviewFromApp() {
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
@@ -224,6 +225,10 @@
private void pressHomeAndWaitForOverviewClose() {
mDevice.pressHome();
+ waitForRecentsActivityStop();
+ }
+
+ private void waitForRecentsActivityStop() {
Wait.atMost("Recents activity didn't stop",
() -> getFromRecents(recents -> !recents.isStarted()),
DEFAULT_UI_TIMEOUT, mLauncher);
@@ -277,6 +282,7 @@
// Test dismissing all tasks.
pressHomeAndGoToOverview().dismissAllTasks();
+ waitForRecentsActivityStop(); // dismissAllTasks() will close Recents
assertTrue("Fallback Launcher not visible", TestHelpers.wait(Until.hasObject(By.pkg(
mOtherLauncherActivity.packageName).text(FALLBACK_LAUNCHER_TITLE)), WAIT_TIME_MS));
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 25adb62..842ec86 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -55,7 +55,6 @@
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -210,11 +209,12 @@
return launcher.<RecentsView>getOverviewPanel().getBottomRowTaskCountForTablet();
}
- @Ignore
+ // Staging; will be promoted to presubmit if stable
+ @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
+
@Test
@NavigationModeSwitch
@PortraitLandscape
- @ScreenRecord // b/238461765
public void testSwitchToOverview() throws Exception {
startTestAppsWithCheck();
assertNotNull("Workspace.switchToOverview() returned null",
@@ -236,7 +236,9 @@
}
}
- @Ignore
+ // Staging; will be promoted to presubmit if stable
+ @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
+
@Test
@NavigationModeSwitch
@PortraitLandscape
@@ -293,9 +295,11 @@
launchedAppState.switchToOverview();
}
+ // Staging; will be promoted to presubmit if stable
+ @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
+
@Test
@TaskbarModeSwitch
- @Ignore // b/314873201
public void testQuickSwitchToPreviousAppForTablet() throws Exception {
assumeTrue(mLauncher.isTablet());
startTestActivity(2);
diff --git a/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt b/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
index 929bd8e..de152fa 100644
--- a/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
@@ -19,6 +19,7 @@
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
+import android.view.ContextThemeWrapper
import android.view.SurfaceControl.Transaction
import android.view.View
import android.window.TransitionInfo
@@ -26,6 +27,7 @@
import com.android.launcher3.apppairs.AppPairIcon
import com.android.launcher3.statehandlers.DepthController
import com.android.launcher3.statemanager.StateManager
+import com.android.launcher3.taskbar.TaskbarActivityContext
import com.android.launcher3.util.SplitConfigurationOptions
import com.android.quickstep.views.GroupedTaskView
import com.android.quickstep.views.IconView
@@ -64,6 +66,8 @@
private val mockTaskIdAttributeContainer: TaskIdAttributeContainer = mock()
// AppPairIcon
private val mockAppPairIcon: AppPairIcon = mock()
+ private val mockContextThemeWrapper: ContextThemeWrapper = mock()
+ private val mockTaskbarActivityContext: TaskbarActivityContext = mock()
// SplitSelectSource
private val splitSelectSource: SplitConfigurationOptions.SplitSelectSource = mock()
@@ -247,6 +251,7 @@
@Test
fun playsAppropriateSplitLaunchAnimation_playsIconLaunchCorrectly() {
val spySplitAnimationController = spy(splitAnimationController)
+ whenever(mockAppPairIcon.context).thenReturn(mockContextThemeWrapper)
doNothing()
.whenever(spySplitAnimationController)
.composeIconSplitLaunchAnimator(any(), any(), any(), any())
@@ -271,6 +276,33 @@
}
@Test
+ fun playsAppropriateSplitLaunchAnimation_playsIconLaunchFromTaskbarContextCorrectly() {
+ val spySplitAnimationController = spy(splitAnimationController)
+ whenever(mockAppPairIcon.context).thenReturn(mockTaskbarActivityContext)
+ doNothing()
+ .whenever(spySplitAnimationController)
+ .composeFadeInSplitLaunchAnimator(any(), any(), any(), any(), any())
+
+ spySplitAnimationController.playSplitLaunchAnimation(
+ null /* launchingTaskView */,
+ mockAppPairIcon,
+ taskId,
+ taskId2,
+ null /* apps */,
+ null /* wallpapers */,
+ null /* nonApps */,
+ stateManager,
+ depthController,
+ transitionInfo,
+ transaction,
+ {} /* finishCallback */
+ )
+
+ verify(spySplitAnimationController)
+ .composeFadeInSplitLaunchAnimator(any(), any(), any(), any(), any())
+ }
+
+ @Test
fun playsAppropriateSplitLaunchAnimation_playsFadeInLaunchCorrectly() {
val spySplitAnimationController = spy(splitAnimationController)
doNothing()
diff --git a/quickstep/tests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt b/quickstep/tests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
index f41ac48..1e39a34 100644
--- a/quickstep/tests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
@@ -107,7 +107,7 @@
// Assertions happen in the callback we get from what we pass into
// #findLastActiveTasksAndRunCallback
val taskConsumer =
- Consumer<List<Task>> { assertNull("No tasks should have matched", it[0] /*task*/) }
+ Consumer<Array<Task>> { assertNull("No tasks should have matched", it[0] /*task*/) }
// Capture callback from recentsModel#getTasks()
val consumer =
@@ -148,7 +148,7 @@
// Assertions happen in the callback we get from what we pass into
// #findLastActiveTasksAndRunCallback
val taskConsumer =
- Consumer<List<Task>> {
+ Consumer<Array<Task>> {
assertEquals(
"ComponentName package mismatched",
it[0].key.baseIntent.component?.packageName,
@@ -201,7 +201,7 @@
// Assertions happen in the callback we get from what we pass into
// #findLastActiveTasksAndRunCallback
val taskConsumer =
- Consumer<List<Task>> { assertNull("No tasks should have matched", it[0] /*task*/) }
+ Consumer<Array<Task>> { assertNull("No tasks should have matched", it[0] /*task*/) }
// Capture callback from recentsModel#getTasks()
val consumer =
@@ -244,7 +244,7 @@
// Assertions happen in the callback we get from what we pass into
// #findLastActiveTasksAndRunCallback
val taskConsumer =
- Consumer<List<Task>> {
+ Consumer<Array<Task>> {
assertEquals(
"ComponentName package mismatched",
it[0].key.baseIntent.component?.packageName,
@@ -298,7 +298,7 @@
// Assertions happen in the callback we get from what we pass into
// #findLastActiveTasksAndRunCallback
val taskConsumer =
- Consumer<List<Task>> {
+ Consumer<Array<Task>> {
assertEquals(
"ComponentName package mismatched",
it[0].key.baseIntent.component?.packageName,
@@ -350,7 +350,7 @@
// Assertions happen in the callback we get from what we pass into
// #findLastActiveTasksAndRunCallback
val taskConsumer =
- Consumer<List<Task>> {
+ Consumer<Array<Task>> {
assertEquals("Expected array length 2", 2, it.size)
assertNull("No tasks should have matched", it[0] /*task*/)
assertEquals(
@@ -403,7 +403,7 @@
// Assertions happen in the callback we get from what we pass into
// #findLastActiveTasksAndRunCallback
val taskConsumer =
- Consumer<List<Task>> {
+ Consumer<Array<Task>> {
assertEquals("Expected array length 2", 2, it.size)
assertEquals(
"ComponentName package mismatched",
@@ -459,7 +459,7 @@
// Assertions happen in the callback we get from what we pass into
// #findLastActiveTasksAndRunCallback
val taskConsumer =
- Consumer<List<Task>> {
+ Consumer<Array<Task>> {
assertEquals("Expected array length 2", 2, it.size)
assertEquals(
"ComponentName package mismatched",
@@ -532,8 +532,8 @@
// Assertions happen in the callback we get from what we pass into
// #findLastActiveTasksAndRunCallback
val taskConsumer =
- Consumer<List<Task>> {
- assertEquals("Expected array length 1", 1, it.size)
+ Consumer<Array<Task>> {
+ assertEquals("Expected array length 2", 2, it.size)
assertEquals("Found wrong task", it[0], groupTask2.task1)
}
diff --git a/res/drawable/widget_internal_focus_bg.xml b/res/drawable/widget_internal_focus_bg.xml
index 4d4bea6..b1f45a4 100644
--- a/res/drawable/widget_internal_focus_bg.xml
+++ b/res/drawable/widget_internal_focus_bg.xml
@@ -23,6 +23,7 @@
<item android:state_selected="true">
<shape android:shape="rectangle">
<stroke android:color="#fff" android:width="2dp" />
+ <corners android:radius="@dimen/focus_outline_radius" />
</shape>
</item>
</selector>
\ No newline at end of file
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index e41a8a5..11dc6e2 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -52,8 +52,10 @@
import static com.android.launcher3.LauncherConstants.TraceEvents.ON_NEW_INTENT_EVT;
import static com.android.launcher3.LauncherConstants.TraceEvents.ON_RESUME_EVT;
import static com.android.launcher3.LauncherConstants.TraceEvents.ON_START_EVT;
+import static com.android.launcher3.LauncherPrefs.IS_FIRST_LOAD_AFTER_RESTORE;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.EDIT_MODE;
import static com.android.launcher3.LauncherState.FLAG_MULTI_PAGE;
@@ -63,6 +65,8 @@
import static com.android.launcher3.LauncherState.NO_SCALE;
import static com.android.launcher3.LauncherState.SPRING_LOADED;
import static com.android.launcher3.Utilities.postAsyncCallback;
+import static com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RESTORE_ERROR_BIND_FAILURE;
+import static com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RESTORE_ERROR_INVALID_LOCATION;
import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
import static com.android.launcher3.config.FeatureFlags.FOLDABLE_SINGLE_PAGE;
import static com.android.launcher3.config.FeatureFlags.MULTI_SELECT_EDIT_MODE;
@@ -162,6 +166,7 @@
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.PropertyListBuilder;
import com.android.launcher3.apppairs.AppPairIcon;
+import com.android.launcher3.backuprestore.LauncherRestoreEventLogger;
import com.android.launcher3.celllayout.CellPosMapper;
import com.android.launcher3.celllayout.CellPosMapper.CellPos;
import com.android.launcher3.celllayout.CellPosMapper.TwoPanelCellPosMapper;
@@ -2158,9 +2163,15 @@
int newItemsScreenId = -1;
int end = items.size();
View newView = null;
+ LauncherRestoreEventLogger restoreEventLogger = null;
+ Boolean isRestoreFromBackup = (Boolean) LauncherPrefs.get(getApplicationContext())
+ .get(IS_FIRST_LOAD_AFTER_RESTORE);
+ if (isRestoreFromBackup) {
+ restoreEventLogger = LauncherRestoreEventLogger.Companion
+ .newInstance(getApplicationContext());
+ }
for (int i = 0; i < end; i++) {
final ItemInfo item = items.get(i);
-
// Short circuit if we are loading dock items for a configuration which has no dock
if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT &&
mHotseat == null) {
@@ -2187,12 +2198,17 @@
(FolderInfo) item);
break;
}
- case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
+ case ITEM_TYPE_APPWIDGET:
case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET: {
- view = inflateAppWidget((LauncherAppWidgetInfo) item);
+ view = inflateAppWidget((LauncherAppWidgetInfo) item, restoreEventLogger);
if (view == null) {
continue;
}
+ // Widgets have more checks when inflating, so we have to wait until here
+ // to mark restored, instead of logging in LoaderTask.
+ if (restoreEventLogger != null) {
+ restoreEventLogger.logSingleFavoritesItemRestored(item.itemType);
+ }
break;
}
default:
@@ -2216,6 +2232,10 @@
if (FeatureFlags.IS_STUDIO_BUILD) {
throw (new RuntimeException(desc));
} else {
+ if (restoreEventLogger != null) {
+ restoreEventLogger.logSingleFavoritesItemRestoreFailed(item.itemType,
+ RESTORE_ERROR_INVALID_LOCATION);
+ }
getModelWriter().deleteItemFromDatabase(item, desc);
continue;
}
@@ -2274,6 +2294,9 @@
} else if (focusFirstItemForAccessibility && viewToFocus != null) {
viewToFocus.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
}
+ if (restoreEventLogger != null) {
+ restoreEventLogger.reportLauncherRestoreResults();
+ }
workspace.requestLayout();
}
@@ -2281,14 +2304,15 @@
* Add the views for a widget to the workspace.
*/
public void bindAppWidget(LauncherAppWidgetInfo item) {
- View view = inflateAppWidget(item);
+ View view = inflateAppWidget(item, null);
if (view != null) {
mWorkspace.addInScreen(view, item);
mWorkspace.requestLayout();
}
}
- private View inflateAppWidget(LauncherAppWidgetInfo item) {
+ private View inflateAppWidget(LauncherAppWidgetInfo item,
+ @Nullable LauncherRestoreEventLogger restoreEventLogger) {
if (item.hasOptionFlag(LauncherAppWidgetInfo.OPTION_SEARCH_WIDGET)) {
item.providerName = QsbContainerView.getSearchComponentName(this);
if (item.providerName == null) {
@@ -2305,11 +2329,9 @@
}
TraceHelper.INSTANCE.beginSection("BIND_WIDGET_id=" + item.appWidgetId);
-
try {
final LauncherAppWidgetProviderInfo appWidgetInfo;
String removalReason = "";
-
if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)) {
// If the provider is not ready, bind as a pending widget.
appWidgetInfo = null;
@@ -2349,6 +2371,10 @@
"Removing restored widget: id=" + item.appWidgetId
+ " belongs to component " + item.providerName + " user " + item.user
+ ", as the provider is null and " + removalReason);
+ if (restoreEventLogger != null) {
+ restoreEventLogger.logSingleFavoritesItemRestoreFailed(
+ ITEM_TYPE_APPWIDGET, RESTORE_ERROR_BIND_FAILURE);
+ }
return null;
}
@@ -2419,6 +2445,10 @@
if (appWidgetInfo == null) {
FileLog.e(TAG, "Removing invalid widget: id=" + item.appWidgetId);
getModelWriter().deleteWidgetInfo(item, getAppWidgetHolder(), removalReason);
+ if (restoreEventLogger != null) {
+ restoreEventLogger.logSingleFavoritesItemRestoreFailed(
+ ITEM_TYPE_APPWIDGET, RESTORE_ERROR_BIND_FAILURE);
+ }
return null;
}
diff --git a/src/com/android/launcher3/LauncherPrefs.kt b/src/com/android/launcher3/LauncherPrefs.kt
index 78056e6..51ba5c6 100644
--- a/src/com/android/launcher3/LauncherPrefs.kt
+++ b/src/com/android/launcher3/LauncherPrefs.kt
@@ -34,6 +34,7 @@
import com.android.launcher3.model.DeviceGridState
import com.android.launcher3.pm.InstallSessionHelper
import com.android.launcher3.provider.RestoreDbTask
+import com.android.launcher3.provider.RestoreDbTask.FIRST_LOAD_AFTER_RESTORE_KEY
import com.android.launcher3.states.RotationHelper
import com.android.launcher3.util.DisplayController
import com.android.launcher3.util.MainThreadInitializedObject
@@ -417,6 +418,13 @@
InvariantDeviceProfile.TYPE_PHONE,
EncryptionType.MOVE_TO_DEVICE_PROTECTED
)
+ @JvmField
+ val IS_FIRST_LOAD_AFTER_RESTORE =
+ backedUpItem(
+ FIRST_LOAD_AFTER_RESTORE_KEY,
+ false,
+ EncryptionType.MOVE_TO_DEVICE_PROTECTED
+ )
@JvmField val APP_WIDGET_IDS = backedUpItem(RestoreDbTask.APPWIDGET_IDS, "")
@JvmField val OLD_APP_WIDGET_IDS = backedUpItem(RestoreDbTask.APPWIDGET_OLD_IDS, "")
@JvmField
diff --git a/src/com/android/launcher3/backuprestore/LauncherRestoreEventLogger.kt b/src/com/android/launcher3/backuprestore/LauncherRestoreEventLogger.kt
index 16b1854..bdac05d 100644
--- a/src/com/android/launcher3/backuprestore/LauncherRestoreEventLogger.kt
+++ b/src/com/android/launcher3/backuprestore/LauncherRestoreEventLogger.kt
@@ -14,6 +14,15 @@
companion object {
const val TAG = "LauncherRestoreEventLogger"
+ // Restore Errors
+ const val RESTORE_ERROR_PROFILE_DELETED = "user_profile_deleted"
+ const val RESTORE_ERROR_MISSING_INFO = "missing_information_when_loading"
+ const val RESTORE_ERROR_BIND_FAILURE = "binding_to_view_failed"
+ const val RESTORE_ERROR_INVALID_LOCATION = "invalid_size_or_location"
+ const val RESTORE_ERROR_SHORTCUT_NOT_FOUND = "shortcut_not_found"
+ const val RESTORE_ERROR_APP_NOT_INSTALLED = "app_not_installed"
+ const val RESTORE_ERROR_WIDGETS_DISABLED = "widgets_disabled"
+
fun newInstance(context: Context?): LauncherRestoreEventLogger {
return ResourceBasedOverride.Overrides.getObject(
LauncherRestoreEventLogger::class.java,
@@ -54,6 +63,16 @@
}
/**
+ * Helper to log successfully restoring multiple items from the Favorites table.
+ *
+ * @param favoritesId The id of the item type from [Favorites] that was restored.
+ * @param count number of items that restored.
+ */
+ open fun logFavoritesItemsRestored(favoritesId: Int, count: Int) {
+ // no-op
+ }
+
+ /**
* Helper to log a failure to restore a single item from the Favorites table.
*
* @param favoritesId The id of the item type from [Favorites] that was not restored.
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 7dfce56..f9d282c 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -169,10 +169,6 @@
// TODO(Block 8): Clean up flags
// TODO(Block 9): Clean up flags
- public static final BooleanFlag UNFOLDED_WIDGET_PICKER = getDebugFlag(301918659,
- "UNFOLDED_WIDGET_PICKER", DISABLED, "Enable new widget picker that takes "
- + "advantage of the unfolded foldable format");
-
public static final BooleanFlag MULTI_SELECT_EDIT_MODE = getDebugFlag(270709220,
"MULTI_SELECT_EDIT_MODE", DISABLED, "Enable new multi-select edit mode "
+ "for home screen");
diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
index 683354b..ec6b94d 100644
--- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
+++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
@@ -259,7 +259,7 @@
query += " or " + LauncherSettings.Favorites.SCREEN + " = "
+ Workspace.SECOND_SCREEN_ID;
}
- loadWorkspace(new ArrayList<>(), query, null);
+ loadWorkspace(new ArrayList<>(), query, null, null);
final SparseArray<Size> spanInfo =
getLoadedLauncherWidgetInfo(previewContext.getBaseContext());
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index d8388c2..6651fa0 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -117,6 +117,9 @@
@UiEvent(doc = "Task launched from overview using SWIPE DOWN")
LAUNCHER_TASK_LAUNCH_SWIPE_DOWN(340),
+ @UiEvent(doc = "App launched by dragging and dropping, probably from taskbar")
+ LAUNCHER_APP_LAUNCH_DRAGDROP(1552),
+
@UiEvent(doc = "TASK dismissed from overview using SWIPE UP")
LAUNCHER_TASK_DISMISS_SWIPE_UP(341),
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index a98ec64..8dc2ab3 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -17,9 +17,16 @@
package com.android.launcher3.model;
import static com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN;
+import static com.android.launcher3.LauncherPrefs.IS_FIRST_LOAD_AFTER_RESTORE;
import static com.android.launcher3.LauncherPrefs.SHOULD_SHOW_SMARTSPACE;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR;
import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
+import static com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RESTORE_ERROR_APP_NOT_INSTALLED;
+import static com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RESTORE_ERROR_INVALID_LOCATION;
+import static com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RESTORE_ERROR_MISSING_INFO;
+import static com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RESTORE_ERROR_PROFILE_DELETED;
+import static com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RESTORE_ERROR_SHORTCUT_NOT_FOUND;
+import static com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RESTORE_ERROR_WIDGETS_DISABLED;
import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
import static com.android.launcher3.config.FeatureFlags.SMARTSPACE_AS_A_WIDGET;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION;
@@ -69,6 +76,7 @@
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.Utilities;
+import com.android.launcher3.backuprestore.LauncherRestoreEventLogger;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderGridOrganizer;
@@ -134,6 +142,7 @@
private final AllAppsList mBgAllAppsList;
protected final BgDataModel mBgDataModel;
private final ModelDelegate mModelDelegate;
+ private boolean mIsRestoreFromBackup;
private FirstScreenBroadcast mFirstScreenBroadcast;
@@ -148,7 +157,6 @@
private final IconCache mIconCache;
private final UserManagerState mUserManagerState;
-
protected final Map<ComponentKey, AppWidgetProviderInfo> mWidgetProvidersMap = new ArrayMap<>();
private Map<ShortcutKey, ShortcutInfo> mShortcutKeyToPinnedShortcuts;
@@ -172,7 +180,6 @@
mBgDataModel = bgModel;
mModelDelegate = modelDelegate;
mLauncherBinder = launcherBinder;
-
mLauncherApps = mApp.getContext().getSystemService(LauncherApps.class);
mUserManager = mApp.getContext().getSystemService(UserManager.class);
mUserCache = UserCache.getInstance(mApp.getContext());
@@ -221,9 +228,14 @@
TraceHelper.INSTANCE.beginSection(TAG);
LoaderMemoryLogger memoryLogger = new LoaderMemoryLogger();
+ mIsRestoreFromBackup =
+ (Boolean) LauncherPrefs.get(mApp.getContext()).get(IS_FIRST_LOAD_AFTER_RESTORE);
+ LauncherRestoreEventLogger restoreEventLogger = LauncherRestoreEventLogger
+ .Companion.newInstance(mApp.getContext());
try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
+
List<ShortcutInfo> allShortcuts = new ArrayList<>();
- loadWorkspace(allShortcuts, "", memoryLogger);
+ loadWorkspace(allShortcuts, "", memoryLogger, restoreEventLogger);
// Sanitize data re-syncs widgets/shortcuts based on the workspace loaded from db.
// sanitizeData should not be invoked if the workspace is loaded from a db different
@@ -314,8 +326,8 @@
mLauncherBinder.bindWidgets();
logASplit("bindWidgets");
verifyNotStopped();
-
LauncherPrefs prefs = LauncherPrefs.get(mApp.getContext());
+
if (SMARTSPACE_AS_A_WIDGET.get() && prefs.get(SHOULD_SHOW_SMARTSPACE)) {
mLauncherBinder.bindSmartspaceWidget();
// Turn off pref.
@@ -349,6 +361,11 @@
mModelDelegate.modelLoadComplete();
transaction.commit();
memoryLogger.clearLogs();
+ if (mIsRestoreFromBackup) {
+ restoreEventLogger.reportLauncherRestoreResults();
+ mIsRestoreFromBackup = false;
+ LauncherPrefs.get(mApp.getContext()).putSync(IS_FIRST_LOAD_AFTER_RESTORE.to(false));
+ }
} catch (CancellationException e) {
// Loader stopped, ignore
logASplit("Cancelled");
@@ -367,10 +384,12 @@
protected void loadWorkspace(
List<ShortcutInfo> allDeepShortcuts,
String selection,
- LoaderMemoryLogger memoryLogger) {
+ LoaderMemoryLogger memoryLogger,
+ @Nullable LauncherRestoreEventLogger restoreEventLogger
+ ) {
Trace.beginSection("LoadWorkspace");
try {
- loadWorkspaceImpl(allDeepShortcuts, selection, memoryLogger);
+ loadWorkspaceImpl(allDeepShortcuts, selection, memoryLogger, restoreEventLogger);
} finally {
Trace.endSection();
}
@@ -391,7 +410,8 @@
private void loadWorkspaceImpl(
List<ShortcutInfo> allDeepShortcuts,
String selection,
- @Nullable LoaderMemoryLogger memoryLogger) {
+ @Nullable LoaderMemoryLogger memoryLogger,
+ @Nullable LauncherRestoreEventLogger restoreEventLogger) {
final Context context = mApp.getContext();
final PackageManagerHelper pmHelper = new PackageManagerHelper(context);
final boolean isSafeMode = pmHelper.isSafeMode();
@@ -458,8 +478,8 @@
List<IconRequestInfo<WorkspaceItemInfo>> iconRequestInfos = new ArrayList<>();
while (!mStopped && c.moveToNext()) {
- processWorkspaceItem(c, memoryLogger, installingPkgs, isSdCardReady,
- tempPackageKey, widgetHelper, pmHelper,
+ processWorkspaceItem(c, memoryLogger, restoreEventLogger, installingPkgs,
+ isSdCardReady, tempPackageKey, widgetHelper, pmHelper,
iconRequestInfos, unlockedUsers, isSafeMode, allDeepShortcuts);
}
tryLoadWorkspaceIconsInBulk(iconRequestInfos);
@@ -518,6 +538,7 @@
private void processWorkspaceItem(LoaderCursor c,
LoaderMemoryLogger memoryLogger,
+ @Nullable LauncherRestoreEventLogger restoreEventLogger,
HashMap<PackageUserKey, SessionInfo> installingPkgs,
boolean isSdCardReady,
PackageUserKey tempPackageKey,
@@ -531,7 +552,11 @@
try {
if (c.user == null) {
// User has been deleted, remove the item.
- c.markDeleted("User has been deleted");
+ c.markDeleted("User of this item has been deleted");
+ if (mIsRestoreFromBackup && restoreEventLogger != null) {
+ restoreEventLogger.logSingleFavoritesItemRestoreFailed(
+ c.itemType, RESTORE_ERROR_PROFILE_DELETED);
+ }
return;
}
@@ -542,6 +567,10 @@
Intent intent = c.parseIntent();
if (intent == null) {
c.markDeleted("Invalid or null intent");
+ if (mIsRestoreFromBackup && restoreEventLogger != null) {
+ restoreEventLogger.logSingleFavoritesItemRestoreFailed(
+ c.itemType, RESTORE_ERROR_MISSING_INFO);
+ }
return;
}
@@ -552,6 +581,10 @@
if (TextUtils.isEmpty(targetPkg)) {
c.markDeleted("Shortcuts can't have null package");
+ if (mIsRestoreFromBackup && restoreEventLogger != null) {
+ restoreEventLogger.logSingleFavoritesItemRestoreFailed(
+ c.itemType, RESTORE_ERROR_MISSING_INFO);
+ }
return;
}
@@ -569,6 +602,9 @@
if (mLauncherApps.isActivityEnabled(cn, c.user)) {
// no special handling necessary for this item
c.markRestored();
+ if (mIsRestoreFromBackup && restoreEventLogger != null) {
+ restoreEventLogger.logSingleFavoritesItemRestored(c.itemType);
+ }
} else {
// Gracefully try to find a fallback activity.
intent = pmHelper.getAppLaunchIntent(targetPkg, c.user);
@@ -579,7 +615,11 @@
intent.toUri(0)).commit();
cn = intent.getComponent();
} else {
- c.markDeleted("Unable to find a launch target");
+ c.markDeleted("Intent null, unable to find a launch target");
+ if (mIsRestoreFromBackup && restoreEventLogger != null) {
+ restoreEventLogger.logSingleFavoritesItemRestoreFailed(
+ c.itemType, RESTORE_ERROR_MISSING_INFO);
+ }
return;
}
}
@@ -606,6 +646,10 @@
} else {
c.markDeleted("removing app that is not restored and not "
+ "installing. package: " + targetPkg);
+ if (mIsRestoreFromBackup && restoreEventLogger != null) {
+ restoreEventLogger.logSingleFavoritesItemRestoreFailed(
+ c.itemType, RESTORE_ERROR_APP_NOT_INSTALLED);
+ }
return;
}
} else if (pmHelper.isAppOnSdcard(targetPkg, c.user)) {
@@ -623,6 +667,10 @@
} else {
// Do not wait for external media load anymore.
c.markDeleted("Invalid package removed: " + targetPkg);
+ if (mIsRestoreFromBackup && restoreEventLogger != null) {
+ restoreEventLogger.logSingleFavoritesItemRestoreFailed(
+ c.itemType, RESTORE_ERROR_APP_NOT_INSTALLED);
+ }
return;
}
}
@@ -652,8 +700,12 @@
ShortcutInfo pinnedShortcut = mShortcutKeyToPinnedShortcuts.get(key);
if (pinnedShortcut == null) {
// The shortcut is no longer valid.
- c.markDeleted("Pinned shortcut not found for package: "
- + key.getPackageName());
+ c.markDeleted("Pinned shortcut not found from request."
+ + " package=" + key.getPackageName() + ", user=" + c.user);
+ if (mIsRestoreFromBackup && restoreEventLogger != null) {
+ restoreEventLogger.logSingleFavoritesItemRestoreFailed(
+ c.itemType, RESTORE_ERROR_SHORTCUT_NOT_FOUND);
+ }
return;
}
info = new WorkspaceItemInfo(pinnedShortcut, mApp.getContext());
@@ -672,6 +724,9 @@
info = c.loadSimpleWorkspaceItem();
info.runtimeStatusFlags |= FLAG_DISABLED_LOCKED_USER;
}
+ if (mIsRestoreFromBackup && restoreEventLogger != null) {
+ restoreEventLogger.logSingleFavoritesItemRestored(c.itemType);
+ }
} else { // item type == ITEM_TYPE_SHORTCUT
info = c.loadSimpleWorkspaceItem();
@@ -751,13 +806,19 @@
// no special handling required for restored folders
c.markRestored();
-
+ if (mIsRestoreFromBackup && restoreEventLogger != null) {
+ restoreEventLogger.logSingleFavoritesItemRestored(c.itemType);
+ }
c.checkAndAddItem(folderInfo, mBgDataModel, memoryLogger);
break;
case Favorites.ITEM_TYPE_APPWIDGET:
if (WidgetsModel.GO_DISABLE_WIDGETS) {
c.markDeleted("Only legacy shortcuts can have null package");
+ if (mIsRestoreFromBackup && restoreEventLogger != null) {
+ restoreEventLogger.logSingleFavoritesItemRestoreFailed(
+ c.itemType, RESTORE_ERROR_WIDGETS_DISABLED);
+ }
return;
}
// Follow through
@@ -774,6 +835,10 @@
component = QsbContainerView.getSearchComponentName(mApp.getContext());
if (component == null) {
c.markDeleted("Discarding SearchWidget without packagename ");
+ if (mIsRestoreFromBackup && restoreEventLogger != null) {
+ restoreEventLogger.logSingleFavoritesItemRestoreFailed(
+ c.itemType, RESTORE_ERROR_MISSING_INFO);
+ }
return;
}
} else {
@@ -799,6 +864,10 @@
final boolean isProviderReady = isValidProvider(provider);
if (!isSafeMode && !customWidget && wasProviderReady && !isProviderReady) {
c.markDeleted("Deleting widget that isn't installed anymore: " + provider);
+ if (mIsRestoreFromBackup && restoreEventLogger != null) {
+ restoreEventLogger.logSingleFavoritesItemRestoreFailed(
+ c.itemType, RESTORE_ERROR_APP_NOT_INSTALLED);
+ }
} else {
LauncherAppWidgetInfo appWidgetInfo;
if (isProviderReady) {
@@ -841,6 +910,10 @@
|= LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;
} else if (!isSafeMode) {
c.markDeleted("Unrestored widget removed: " + component);
+ if (mIsRestoreFromBackup && restoreEventLogger != null) {
+ restoreEventLogger.logSingleFavoritesItemRestoreFailed(
+ c.itemType, RESTORE_ERROR_APP_NOT_INSTALLED);
+ }
return;
}
@@ -862,6 +935,10 @@
if (appWidgetInfo.spanX <= 0 || appWidgetInfo.spanY <= 0) {
c.markDeleted("Widget has invalid size: "
+ appWidgetInfo.spanX + "x" + appWidgetInfo.spanY);
+ if (mIsRestoreFromBackup && restoreEventLogger != null) {
+ restoreEventLogger.logSingleFavoritesItemRestoreFailed(
+ c.itemType, RESTORE_ERROR_INVALID_LOCATION);
+ }
return;
}
LauncherAppWidgetProviderInfo widgetProviderInfo =
@@ -875,12 +952,15 @@
+ "x" + appWidgetInfo.spanY + " minSpan="
+ widgetProviderInfo.minSpanX + "x"
+ widgetProviderInfo.minSpanY);
- logWidgetInfo(mApp.getInvariantDeviceProfile(),
- widgetProviderInfo);
+ logWidgetInfo(mApp.getInvariantDeviceProfile(), widgetProviderInfo);
}
if (!c.isOnWorkspaceOrHotseat()) {
c.markDeleted("Widget found where container != CONTAINER_DESKTOP"
+ "nor CONTAINER_HOTSEAT - ignoring!");
+ if (mIsRestoreFromBackup && restoreEventLogger != null) {
+ restoreEventLogger.logSingleFavoritesItemRestoreFailed(
+ c.itemType, RESTORE_ERROR_INVALID_LOCATION);
+ }
return;
}
diff --git a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
index dc180d8..5141db9 100644
--- a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
+++ b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.content.Intent;
+import android.os.Process;
import androidx.annotation.Nullable;
@@ -26,7 +27,7 @@
import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.pm.PackageInstallInfo;
-import com.android.launcher3.util.PackageManagerHelper;
+import com.android.launcher3.uioverrides.ApiWrapper;
/**
* Represents an ItemInfo which also holds an icon.
@@ -216,7 +217,8 @@
String targetPackage = getTargetPackage();
return targetPackage != null
- ? new PackageManagerHelper(context).getMarketIntent(targetPackage)
+ ? ApiWrapper.getAppMarketActivityIntent(
+ context, targetPackage, Process.myUserHandle())
: null;
}
diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java
index 69bba69..f39f806 100644
--- a/src/com/android/launcher3/popup/SystemShortcut.java
+++ b/src/com/android/launcher3/popup/SystemShortcut.java
@@ -7,6 +7,7 @@
import android.content.Context;
import android.content.Intent;
import android.graphics.Rect;
+import android.os.Process;
import android.view.View;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.ImageView;
@@ -22,6 +23,7 @@
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.uioverrides.ApiWrapper;
import com.android.launcher3.util.InstantAppResolver;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PackageUserKey;
@@ -237,8 +239,9 @@
@Override
public void onClick(View view) {
- Intent intent = new PackageManagerHelper(view.getContext()).getMarketIntent(
- mItemInfo.getTargetComponent().getPackageName());
+ Intent intent = ApiWrapper.getAppMarketActivityIntent(view.getContext(),
+ mItemInfo.getTargetComponent().getPackageName(),
+ Process.myUserHandle());
mTarget.startActivitySafely(view, intent, mItemInfo);
AbstractFloatingView.closeAllOpenViews(mTarget);
}
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index dc8cd3a..20b2971 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -20,6 +20,7 @@
import static com.android.launcher3.InvariantDeviceProfile.TYPE_MULTI_DISPLAY;
import static com.android.launcher3.LauncherPrefs.APP_WIDGET_IDS;
+import static com.android.launcher3.LauncherPrefs.IS_FIRST_LOAD_AFTER_RESTORE;
import static com.android.launcher3.LauncherPrefs.OLD_APP_WIDGET_IDS;
import static com.android.launcher3.LauncherPrefs.RESTORE_DEVICE;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
@@ -83,6 +84,7 @@
private static final String TAG = "RestoreDbTask";
public static final String RESTORED_DEVICE_TYPE = "restored_task_pending";
+ public static final String FIRST_LOAD_AFTER_RESTORE_KEY = "first_load_after_restore";
private static final String INFO_COLUMN_NAME = "name";
private static final String INFO_COLUMN_DEFAULT_VALUE = "dflt_value";
@@ -340,9 +342,10 @@
* Marks the DB state as pending restoration
*/
public static void setPending(Context context) {
- FileLog.d(TAG, "Restore data received through full backup");
- LauncherPrefs.get(context)
- .putSync(RESTORE_DEVICE.to(new DeviceGridState(context).getDeviceType()));
+ DeviceGridState deviceGridState = new DeviceGridState(context);
+ FileLog.d(TAG, "restore initiated from backup: DeviceGridState=" + deviceGridState);
+ LauncherPrefs.get(context).putSync(RESTORE_DEVICE.to(deviceGridState.getDeviceType()));
+ LauncherPrefs.get(context).putSync(IS_FIRST_LOAD_AFTER_RESTORE.to(true));
}
@WorkerThread
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index 6d4103c..2c834bd 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -18,7 +18,6 @@
import static com.android.launcher3.allapps.AllAppsStore.DEFER_UPDATES_TEST;
import static com.android.launcher3.Flags.enableGridOnlyOverview;
import static com.android.launcher3.config.FeatureFlags.FOLDABLE_SINGLE_PAGE;
-import static com.android.launcher3.config.FeatureFlags.enableAppPairs;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import android.annotation.TargetApi;
@@ -283,11 +282,6 @@
return response;
}
- case TestProtocol.REQUEST_FLAG_ENABLE_APP_PAIRS: {
- response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD, enableAppPairs());
- return response;
- }
-
default:
return null;
}
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index a9c2a2e..839f98c 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -31,6 +31,7 @@
import android.content.Intent;
import android.content.pm.LauncherApps;
import android.content.pm.PackageInstaller.SessionInfo;
+import android.os.Process;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
@@ -58,8 +59,8 @@
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
+import com.android.launcher3.uioverrides.ApiWrapper;
import com.android.launcher3.util.ItemInfoMatcher;
-import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.views.FloatingIconView;
import com.android.launcher3.views.Snackbar;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
@@ -207,7 +208,8 @@
}
}
// Fallback to using custom market intent.
- Intent intent = new PackageManagerHelper(launcher).getMarketIntent(packageName);
+ Intent intent = ApiWrapper.getAppMarketActivityIntent(launcher,
+ packageName, Process.myUserHandle());
launcher.startActivitySafely(v, intent, item);
};
@@ -344,8 +346,8 @@
&& (((ItemInfoWithIcon) item).runtimeStatusFlags
& ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) {
ItemInfoWithIcon appInfo = (ItemInfoWithIcon) item;
- intent = new PackageManagerHelper(launcher)
- .getMarketIntent(appInfo.getTargetComponent().getPackageName());
+ intent = ApiWrapper.getAppMarketActivityIntent(launcher,
+ appInfo.getTargetComponent().getPackageName(), Process.myUserHandle());
} else {
intent = item.getIntent();
}
diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
index 51c047c..f7afcb9 100644
--- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
@@ -543,15 +543,19 @@
secondarySnapshotWidth = parentWidth;
secondarySnapshotHeight = totalThumbnailHeight - primarySnapshotHeight - dividerBar;
- secondarySnapshot.setTranslationY(0);
- primarySnapshot.setTranslationY(secondarySnapshotHeight + spaceAboveSnapshot + dividerBar);
+
+ int translationY = primarySnapshotHeight + spaceAboveSnapshot + dividerBar;
+ primarySnapshot.setTranslationY(spaceAboveSnapshot);
+ secondarySnapshot.setTranslationY(translationY - spaceAboveSnapshot);
+
primarySnapshot.measure(
View.MeasureSpec.makeMeasureSpec(primarySnapshotWidth, View.MeasureSpec.EXACTLY),
- View.MeasureSpec.makeMeasureSpec(primarySnapshotHeight, View.MeasureSpec.EXACTLY));
+ View.MeasureSpec.makeMeasureSpec(primarySnapshotHeight, View.MeasureSpec.EXACTLY)
+ );
secondarySnapshot.measure(
View.MeasureSpec.makeMeasureSpec(secondarySnapshotWidth, View.MeasureSpec.EXACTLY),
- View.MeasureSpec.makeMeasureSpec(secondarySnapshotHeight,
- View.MeasureSpec.EXACTLY));
+ View.MeasureSpec.makeMeasureSpec(secondarySnapshotHeight, View.MeasureSpec.EXACTLY)
+ );
}
@Override
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index 04b6710..87437bd 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -644,11 +644,12 @@
secondarySnapshotHeight = totalThumbnailHeight;
secondarySnapshotWidth = parentWidth - primarySnapshotWidth - scaledDividerBar;
- int translationX = primarySnapshotWidth + scaledDividerBar;
if (isRtl) {
+ int translationX = secondarySnapshotWidth + scaledDividerBar;
primarySnapshot.setTranslationX(-translationX);
secondarySnapshot.setTranslationX(0);
} else {
+ int translationX = primarySnapshotWidth + scaledDividerBar;
secondarySnapshot.setTranslationX(translationX);
primarySnapshot.setTranslationX(0);
}
diff --git a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
index 06526a8..dcbf7d1 100644
--- a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
@@ -343,13 +343,15 @@
secondarySnapshotHeight = totalThumbnailHeight - primarySnapshotHeight - dividerBar;
secondarySnapshot.setTranslationY(0);
primarySnapshot.setTranslationY(secondarySnapshotHeight + spaceAboveSnapshot + dividerBar);
+
primarySnapshot.measure(
View.MeasureSpec.makeMeasureSpec(primarySnapshotWidth, View.MeasureSpec.EXACTLY),
- View.MeasureSpec.makeMeasureSpec(primarySnapshotHeight, View.MeasureSpec.EXACTLY));
+ View.MeasureSpec.makeMeasureSpec(primarySnapshotHeight, View.MeasureSpec.EXACTLY)
+ );
secondarySnapshot.measure(
View.MeasureSpec.makeMeasureSpec(secondarySnapshotWidth, View.MeasureSpec.EXACTLY),
- View.MeasureSpec.makeMeasureSpec(secondarySnapshotHeight,
- View.MeasureSpec.EXACTLY));
+ View.MeasureSpec.makeMeasureSpec(secondarySnapshotHeight, View.MeasureSpec.EXACTLY)
+ );
}
/* ---------- The following are only used by TaskViewTouchHandler. ---------- */
diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java
index 91203a7..3f7a128 100644
--- a/src/com/android/launcher3/util/PackageManagerHelper.java
+++ b/src/com/android/launcher3/util/PackageManagerHelper.java
@@ -28,8 +28,8 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.graphics.Rect;
-import android.net.Uri;
import android.os.Bundle;
+import android.os.Process;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
@@ -46,6 +46,7 @@
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.uioverrides.ApiWrapper;
import java.net.URISyntaxException;
import java.util.List;
@@ -137,17 +138,6 @@
return (info.flags & ApplicationInfo.FLAG_SUSPENDED) != 0;
}
- public Intent getMarketIntent(String packageName) {
- return new Intent(Intent.ACTION_VIEW)
- .setData(new Uri.Builder()
- .scheme("market")
- .authority("details")
- .appendQueryParameter("id", packageName)
- .build())
- .putExtra(Intent.EXTRA_REFERRER, new Uri.Builder().scheme("android-app")
- .authority(mContext.getPackageName()).build());
- }
-
/**
* Creates a new market search intent.
*/
@@ -172,8 +162,8 @@
&& (((ItemInfoWithIcon) info).runtimeStatusFlags
& ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) {
ItemInfoWithIcon appInfo = (ItemInfoWithIcon) info;
- mContext.startActivity(new PackageManagerHelper(mContext)
- .getMarketIntent(appInfo.getTargetComponent().getPackageName()));
+ mContext.startActivity(ApiWrapper.getAppMarketActivityIntent(mContext,
+ appInfo.getTargetComponent().getPackageName(), Process.myUserHandle()));
return;
}
ComponentName componentName = null;
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
index 5d069ed..12b47e6 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
@@ -41,6 +41,7 @@
import androidx.annotation.Nullable;
import com.android.launcher3.CheckLongPressHelper;
+import com.android.launcher3.Flags;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -103,6 +104,9 @@
mLongPressHelper = new CheckLongPressHelper(this, this);
setAccessibilityDelegate(mLauncher.getAccessibilityDelegate());
setBackgroundResource(R.drawable.widget_internal_focus_bg);
+ if (Flags.enableFocusOutline()) {
+ setDefaultFocusHighlightEnabled(false);
+ }
if (Utilities.ATLEAST_Q && Themes.getAttrBoolean(mLauncher, R.attr.isWorkspaceDarkText)) {
setOnLightBackground(true);
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java b/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java
index fe5c1fd..b9f9ac5 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java
@@ -19,9 +19,11 @@
import android.app.ActivityOptions;
import android.app.Person;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.LauncherActivityInfo;
import android.content.pm.ShortcutInfo;
import android.graphics.drawable.ColorDrawable;
+import android.net.Uri;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.ArrayMap;
@@ -29,6 +31,7 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.util.UserIconInfo;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -80,6 +83,30 @@
return users;
}
+ /**
+ * Returns the list of the system packages that are installed at user creation.
+ * An empty list denotes that all system packages are installed for that user at creation.
+ */
+ public static List<String> getPreInstalledSystemPackages(Context context, UserHandle user) {
+ return new ArrayList<>();
+ }
+
+ /**
+ * Returns an intent which can be used to start the App Market activity (Installer
+ * Activity).
+ */
+ public static Intent getAppMarketActivityIntent(Context context, String packageName,
+ UserHandle user) {
+ return new Intent(Intent.ACTION_VIEW)
+ .setData(new Uri.Builder()
+ .scheme("market")
+ .authority("details")
+ .appendQueryParameter("id", packageName)
+ .build())
+ .putExtra(Intent.EXTRA_REFERRER, new Uri.Builder().scheme("android-app")
+ .authority(context.getPackageName()).build());
+ }
+
private static class NoopDrawable extends ColorDrawable {
@Override
public int getIntrinsicHeight() {
diff --git a/tests/Android.bp b/tests/Android.bp
index 84c3951..bdb53ba 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -66,14 +66,14 @@
filegroup {
name: "launcher-oop-tests-src",
srcs: [
- "src/com/android/launcher3/allapps/TaplOpenCloseAllApps.java",
- "src/com/android/launcher3/allapps/TaplTestsAllAppsIconsWorking.java",
+ "src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java",
+ "src/com/android/launcher3/allapps/TaplAllAppsIconsWorkingTest.java",
"src/com/android/launcher3/appiconmenu/TaplAppIconMenuTest.java",
"src/com/android/launcher3/dragging/TaplDragTest.java",
- "src/com/android/launcher3/dragging/TaplUninstallRemove.java",
+ "src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java",
"src/com/android/launcher3/ui/AbstractLauncherUiTest.java",
"src/com/android/launcher3/ui/PortraitLandscapeRunner.java",
- "src/com/android/launcher3/ui/TaplTestsLauncher3.java",
+ "src/com/android/launcher3/ui/TaplTestsLauncher3Test.java",
"src/com/android/launcher3/ui/widget/TaplWidgetPickerTest.java",
"src/com/android/launcher3/ui/workspace/TaplWorkspaceTest.java",
"src/com/android/launcher3/util/LauncherLayoutBuilder.java",
diff --git a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index 7eab910..fcb5158 100644
--- a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -171,7 +171,6 @@
public static final String REQUEST_EMULATE_PRINT_DEVICE = "emulate-print-device";
public static final String REQUEST_FLAG_ENABLE_GRID_ONLY_OVERVIEW = "enable-grid-only-overview";
- public static final String REQUEST_FLAG_ENABLE_APP_PAIRS = "enable-app-pairs";
/** Logs {@link Log#d(String, String)} if {@link #sDebugTracing} is true. */
public static void testLogD(String tag, String message) {
diff --git a/tests/src/com/android/launcher3/allapps/TaplTestsAllAppsIconsWorking.java b/tests/src/com/android/launcher3/allapps/TaplAllAppsIconsWorkingTest.java
similarity index 96%
rename from tests/src/com/android/launcher3/allapps/TaplTestsAllAppsIconsWorking.java
rename to tests/src/com/android/launcher3/allapps/TaplAllAppsIconsWorkingTest.java
index 9f6bbdf..27a2c75 100644
--- a/tests/src/com/android/launcher3/allapps/TaplTestsAllAppsIconsWorking.java
+++ b/tests/src/com/android/launcher3/allapps/TaplAllAppsIconsWorkingTest.java
@@ -33,7 +33,7 @@
* The test runs in Out of process (Oop) and in process.
* Makes sure the basic behaviors of Icons on AllApps are working.
*/
-public class TaplTestsAllAppsIconsWorking extends AbstractLauncherUiTest {
+public class TaplAllAppsIconsWorkingTest extends AbstractLauncherUiTest {
@Before
public void setUp() throws Exception {
diff --git a/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllApps.java b/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java
similarity index 98%
rename from tests/src/com/android/launcher3/allapps/TaplOpenCloseAllApps.java
rename to tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java
index 4f10287..92ff355 100644
--- a/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllApps.java
+++ b/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java
@@ -43,7 +43,7 @@
* Test that we can open and close the all apps in multiple situations.
* The test runs in Out of process (Oop) and in process.
*/
-public class TaplOpenCloseAllApps extends AbstractLauncherUiTest {
+public class TaplOpenCloseAllAppsTest extends AbstractLauncherUiTest {
public static final String READ_DEVICE_CONFIG_PERMISSION =
"android.permission.READ_DEVICE_CONFIG";
diff --git a/tests/src/com/android/launcher3/dragging/TaplDragTest.java b/tests/src/com/android/launcher3/dragging/TaplDragTest.java
index e040367..98905ea 100644
--- a/tests/src/com/android/launcher3/dragging/TaplDragTest.java
+++ b/tests/src/com/android/launcher3/dragging/TaplDragTest.java
@@ -15,11 +15,12 @@
*/
package com.android.launcher3.dragging;
-import static com.android.launcher3.util.TestConstants.AppNames.TEST_APP_NAME;
import static com.android.launcher3.util.TestConstants.AppNames.GMAIL_APP_NAME;
import static com.android.launcher3.util.TestConstants.AppNames.MAPS_APP_NAME;
import static com.android.launcher3.util.TestConstants.AppNames.STORE_APP_NAME;
-import static com.android.launcher3.ui.AbstractLauncherUiTest.initialize;
+import static com.android.launcher3.util.TestConstants.AppNames.TEST_APP_NAME;
+import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
+import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -39,10 +40,9 @@
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
import com.android.launcher3.util.TestUtil;
-import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
+import com.android.launcher3.util.rule.TestStabilityRule;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
/**
@@ -68,10 +68,11 @@
* are no longer in the Workspace then adds a third one to test adding an icon to an existing
* folder instead of creating one and drags it to the folder.
*/
+ // Staging; will be promoted to presubmit if stable
+ @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
+
@Test
@PortraitLandscape
- @ScreenRecord
- @Ignore // b/233075289
@PlatinumTest(focusArea = "launcher")
public void testDragToFolder() {
// TODO: add the use case to drag an icon to an existing folder. Currently it either fails
diff --git a/tests/src/com/android/launcher3/dragging/TaplUninstallRemove.java b/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
similarity index 98%
rename from tests/src/com/android/launcher3/dragging/TaplUninstallRemove.java
rename to tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
index 568fc9f..0b9de0f 100644
--- a/tests/src/com/android/launcher3/dragging/TaplUninstallRemove.java
+++ b/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
@@ -51,7 +51,7 @@
* Test runs in Out of process (Oop) and In process (Ipc)
* Test the behaviour of uninstalling and removing apps both from AllApps, Workspace and Hotseat.
*/
-public class TaplUninstallRemove extends AbstractLauncherUiTest {
+public class TaplUninstallRemoveTest extends AbstractLauncherUiTest {
@Before
public void setUp() throws Exception {
diff --git a/tests/src/com/android/launcher3/tapl/TaplUtilityTests.java b/tests/src/com/android/launcher3/tapl/TaplUtilityTest.java
similarity index 97%
rename from tests/src/com/android/launcher3/tapl/TaplUtilityTests.java
rename to tests/src/com/android/launcher3/tapl/TaplUtilityTest.java
index 15db1d8..4a1888a 100644
--- a/tests/src/com/android/launcher3/tapl/TaplUtilityTests.java
+++ b/tests/src/com/android/launcher3/tapl/TaplUtilityTest.java
@@ -20,7 +20,7 @@
import org.junit.Test;
-public class TaplUtilityTests {
+public class TaplUtilityTest {
@Test
public void testNewStringWithRegex() {
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3Test.java
similarity index 95%
rename from tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
rename to tests/src/com/android/launcher3/ui/TaplTestsLauncher3Test.java
index 229ea45..d26a9db 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3Test.java
@@ -27,7 +27,7 @@
@LargeTest
@RunWith(AndroidJUnit4.class)
-public class TaplTestsLauncher3 extends AbstractLauncherUiTest {
+public class TaplTestsLauncher3Test extends AbstractLauncherUiTest {
@Before
public void setUp() throws Exception {
diff --git a/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java b/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java
index f818564..6d57a71 100644
--- a/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java
+++ b/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java
@@ -20,6 +20,8 @@
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.allapps.AllAppsStore.DEFER_UPDATES_TEST;
import static com.android.launcher3.util.TestUtil.installDummyAppForUser;
+import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
+import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -39,10 +41,10 @@
import com.android.launcher3.allapps.WorkProfileManager;
import com.android.launcher3.tapl.LauncherInstrumentation;
import com.android.launcher3.util.TestUtil;
+import com.android.launcher3.util.rule.TestStabilityRule;
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import java.util.Objects;
@@ -123,8 +125,10 @@
LauncherInstrumentation.WAIT_TIME_MS);
}
+ // Staging; will be promoted to presubmit if stable
+ @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
+
@Test
- @Ignore("b/243855320")
public void toggleWorks() {
assumeTrue(mWorkProfileSetupSuccessful);
waitForWorkTabSetup();
diff --git a/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
index 27fda9b..d75b387 100644
--- a/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
@@ -47,7 +47,6 @@
@Rule
public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
- @PlatinumTest(focusArea = "launcher")
@Test
@PortraitLandscape
@ScreenRecordRule.ScreenRecord // b/289161193
diff --git a/tests/src/com/android/launcher3/util/ExecutorRunnableTest.kt b/tests/src/com/android/launcher3/util/ExecutorRunnableTest.kt
index b8d74aa..c9d118f 100644
--- a/tests/src/com/android/launcher3/util/ExecutorRunnableTest.kt
+++ b/tests/src/com/android/launcher3/util/ExecutorRunnableTest.kt
@@ -24,6 +24,7 @@
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -38,6 +39,8 @@
private var isTaskExecuted = false
private var isCallbackExecuted = false
+ @get:Rule(order = 0) val testStabilityRule = TestStabilityRule()
+
@Before
fun setup() {
reset()
diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java
index 8713b68..9f2ce22 100644
--- a/tests/tapl/com/android/launcher3/tapl/Background.java
+++ b/tests/tapl/com/android/launcher3/tapl/Background.java
@@ -16,8 +16,6 @@
package com.android.launcher3.tapl;
-import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
-
import static com.android.launcher3.tapl.OverviewTask.TASK_START_EVENT;
import static com.android.launcher3.testing.shared.TestProtocol.OVERVIEW_STATE_ORDINAL;
@@ -244,12 +242,11 @@
endY = startY;
}
- mLauncher.executeAndWaitForEvent(
+ mLauncher.executeAndWaitForLauncherStop(
() -> mLauncher.linearGesture(
startX, startY, endX, endY, 20, false,
LauncherInstrumentation.GestureScope.EXPECT_PILFER),
- event -> event.getEventType() == TYPE_WINDOW_STATE_CHANGED,
- () -> "Quick switch gesture didn't change window state", "swiping");
+ "swiping");
} else {
// Double press the recents button.
UiObject2 recentsButton = mLauncher.waitForNavigationUiObject("recent_apps");
@@ -258,10 +255,8 @@
"clicking Recents button for the first time");
mLauncher.getOverview();
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, SQUARE_BUTTON_EVENT);
- mLauncher.executeAndWaitForEvent(
+ mLauncher.executeAndWaitForLauncherStop(
() -> recentsButton.click(),
- event -> event.getEventType() == TYPE_WINDOW_STATE_CHANGED,
- () -> "Pressing recents button didn't change window state",
"clicking Recents button for the second time");
}
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, TASK_START_EVENT);
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index ec0c41c..b6b4a47 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -363,11 +363,8 @@
if (isTablet && Math.abs(task.getExactCenterX() - mLauncher.getExactScreenCenterX()) >= 1) {
return false;
}
- if (!mLauncher.isAppPairsEnabled() && task.isTaskSplit()) {
- // Overview actions aren't visible for split screen tasks.
- return false;
- }
- return true;
+ // Overview actions aren't visible for split screen tasks.
+ return !task.isTaskSplit();
}
private void verifyActionsViewVisibility() {
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 438174c..edc6aac 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -1820,10 +1820,6 @@
TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
- boolean isAppPairsEnabled() {
- return getTestInfo(TestProtocol.REQUEST_FLAG_ENABLE_APP_PAIRS).getBoolean(
- TestProtocol.TEST_INFO_RESPONSE_FIELD);
- }
public void sendPointer(long downTime, long currentTime, int action, Point point,
GestureScope gestureScope) {
sendPointer(downTime, currentTime, action, point, gestureScope,
@@ -2294,7 +2290,7 @@
int bottomBound = Math.min(
containerBounds.bottom,
getRealDisplaySize().y - getImeInsets().bottom);
- int y = (bottomBound + containerBounds.top) / 2;
+ int y = (bottomBound - containerBounds.top) / 2;
// Do not tap in the status bar.
y = Math.max(y, getWindowInsets().top);
diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java
index 105bc3b..6387b05 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widgets.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java
@@ -19,6 +19,7 @@
import static com.android.launcher3.tapl.LauncherInstrumentation.WAIT_TIME_MS;
import static com.android.launcher3.tapl.LauncherInstrumentation.log;
+import android.annotation.Nullable;
import android.graphics.Rect;
import androidx.test.uiautomator.By;
@@ -114,7 +115,13 @@
.getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
+ /** Get widget with supplied text. */
public Widget getWidget(String labelText) {
+ return getWidget(labelText, null);
+ }
+
+ /** Get widget with supplied text and app package */
+ public Widget getWidget(String labelText, @Nullable String testAppWidgetPackage) {
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"getting widget " + labelText + " in widgets list")) {
@@ -124,7 +131,8 @@
mLauncher.assertTrue("Widgets container didn't become scrollable",
fullWidgetsPicker.wait(Until.scrollable(true), WAIT_TIME_MS));
- final UiObject2 widgetsContainer = findTestAppWidgetsTableContainer();
+ final UiObject2 widgetsContainer =
+ findTestAppWidgetsTableContainer(testAppWidgetPackage);
mLauncher.assertTrue("Can't locate widgets list for the test app: "
+ mLauncher.getLauncherPackageName(),
widgetsContainer != null);
@@ -180,14 +188,22 @@
return searchBar;
}
- /** Finds the widgets list of this test app from the collapsed full widgets picker. */
- private UiObject2 findTestAppWidgetsTableContainer() {
+ /**
+ * Finds the widgets list of this test app or supplied test app package from the collapsed full
+ * widgets picker.
+ */
+ private UiObject2 findTestAppWidgetsTableContainer(@Nullable String testAppWidgetPackage) {
final BySelector headerSelector = By.res(mLauncher.getLauncherPackageName(),
"widgets_list_header");
final BySelector widgetPickerSelector = By.res(mLauncher.getLauncherPackageName(),
"container");
- final BySelector targetAppSelector = By.clazz("android.widget.TextView").text(
- mLauncher.getContext().getPackageName());
+
+ String packageName = mLauncher.getContext().getPackageName();
+ final BySelector targetAppSelector = By
+ .clazz("android.widget.TextView")
+ .text((testAppWidgetPackage == null || testAppWidgetPackage.isEmpty())
+ ? packageName
+ : testAppWidgetPackage);
final BySelector widgetsContainerSelector = By.res(mLauncher.getLauncherPackageName(),
"widgets_table");