Merge "Adding Test Parameters to Asserts." into main
diff --git a/Android.bp b/Android.bp
index 39b1ae0..eca0778 100644
--- a/Android.bp
+++ b/Android.bp
@@ -309,6 +309,8 @@
"AndroidManifest-common.xml",
],
min_sdk_version: "current",
+ // TODO(b/319712088): re-enable use_resource_processor
+ use_resource_processor: false,
}
// Build rule for Quickstep library
@@ -337,6 +339,8 @@
manifest: "quickstep/AndroidManifest.xml",
platform_apis: true,
min_sdk_version: "current",
+ // TODO(b/319712088): re-enable use_resource_processor
+ use_resource_processor: false,
}
// Build rule for Launcher3 Go app for Android Go devices.
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 4f580e0..517bd6d 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -20,7 +20,7 @@
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.launcher3">
- <uses-sdk android:targetSdkVersion="33" android:minSdkVersion="26"/>
+ <uses-sdk android:targetSdkVersion="33" android:minSdkVersion="30"/>
<!--
Manifest entries specific to Launcher3. This is merged with AndroidManifest-common.xml.
Refer comments around specific entries on how to extend individual components.
diff --git a/OWNERS b/OWNERS
index b8aae78..4409b33 100644
--- a/OWNERS
+++ b/OWNERS
@@ -25,5 +25,10 @@
andonian@google.com
sihua@google.com
+# Multitasking eng team
+tracyzhou@google.com
+peanutbutter@google.com
+jeremysim@google.com
+
per-file FeatureFlags.java, globs = set noparent
per-file FeatureFlags.java = sunnygoyal@google.com, winsonc@google.com, adamcohen@google.com, hyunyoungs@google.com, captaincole@google.com
diff --git a/aconfig/launcher_search.aconfig b/aconfig/launcher_search.aconfig
index 97e56b7..b846604 100644
--- a/aconfig/launcher_search.aconfig
+++ b/aconfig/launcher_search.aconfig
@@ -26,4 +26,11 @@
namespace: "launcher_search"
description: "This flag enables addition of App Installer button in Private Space container."
bug: "308064949"
-}
\ No newline at end of file
+}
+
+flag {
+ name: "private_space_restrict_accessibility_drag"
+ namespace: "launcher_search"
+ description: "This flag disables accessibility drag for Private Space Apps."
+ bug: "289223923"
+}
diff --git a/build.gradle b/build.gradle
index f4d7261..a453bfd 100644
--- a/build.gradle
+++ b/build.gradle
@@ -20,8 +20,8 @@
buildToolsVersion BUILD_TOOLS_VERSION
defaultConfig {
- minSdkVersion 26
- targetSdkVersion 30
+ minSdkVersion 30
+ targetSdkVersion 33
versionCode 1
versionName "1.0"
diff --git a/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml b/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml
index 672440f..e4942ae 100644
--- a/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml
+++ b/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml
@@ -159,7 +159,7 @@
style="@style/TextAppearance.GestureTutorial.ButtonLabel"
android:id="@+id/gesture_tutorial_menu_done_button"
android:layout_width="wrap_content"
- android:layout_height="40dp"
+ android:layout_height="48dp"
android:layout_marginVertical="16dp"
android:text="@string/gesture_tutorial_action_button_label"
android:background="@drawable/gesture_tutorial_action_button_background"
diff --git a/quickstep/res/layout/gesture_tutorial_step_menu.xml b/quickstep/res/layout/gesture_tutorial_step_menu.xml
index c8ee6e9..668a2e1 100644
--- a/quickstep/res/layout/gesture_tutorial_step_menu.xml
+++ b/quickstep/res/layout/gesture_tutorial_step_menu.xml
@@ -157,7 +157,7 @@
style="@style/TextAppearance.GestureTutorial.ButtonLabel"
android:id="@+id/gesture_tutorial_menu_done_button"
android:layout_width="wrap_content"
- android:layout_height="40dp"
+ android:layout_height="48dp"
android:layout_marginVertical="16dp"
android:text="@string/gesture_tutorial_action_button_label"
android:background="@drawable/gesture_tutorial_action_button_background"
diff --git a/quickstep/res/layout/taskbar.xml b/quickstep/res/layout/taskbar.xml
index 72d7485..736706a 100644
--- a/quickstep/res/layout/taskbar.xml
+++ b/quickstep/res/layout/taskbar.xml
@@ -35,7 +35,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"/>
- <FrameLayout
+ <com.android.launcher3.taskbar.navbutton.NearestTouchFrame
android:id="@+id/navbuttons_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -62,7 +62,7 @@
android:layout_height="match_parent"
android:gravity="center_vertical"
android:layout_gravity="end"/>
- </FrameLayout>
+ </com.android.launcher3.taskbar.navbutton.NearestTouchFrame>
<com.android.launcher3.taskbar.StashedHandleView
android:id="@+id/stashed_handle"
diff --git a/quickstep/res/layout/transient_taskbar.xml b/quickstep/res/layout/transient_taskbar.xml
index 0890a4e..6af7cf4 100644
--- a/quickstep/res/layout/transient_taskbar.xml
+++ b/quickstep/res/layout/transient_taskbar.xml
@@ -52,7 +52,7 @@
android:elevation="@dimen/bubblebar_elevation"
/>
- <FrameLayout
+ <com.android.launcher3.taskbar.navbutton.NearestTouchFrame
android:id="@+id/navbuttons_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -83,7 +83,7 @@
android:paddingTop="@dimen/taskbar_contextual_padding_top"
android:gravity="center_vertical"
android:layout_gravity="end"/>
- </FrameLayout>
+ </com.android.launcher3.taskbar.navbutton.NearestTouchFrame>
<com.android.launcher3.taskbar.StashedHandleView
android:id="@+id/stashed_handle"
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 9aab0a1..b23c283 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -230,6 +230,7 @@
<string name="action_split">Split</string>
<!-- Label for toast with instructions for split screen selection mode. [CHAR_LIMIT=50] -->
<string name="toast_split_select_app">Tap another app to use split screen</string>
+ <string name="toast_contextual_split_select_app">Choose another app to use split screen</string>
<string name="toast_split_select_app_cancel"><b>Cancel</b></string>
<string name="toast_split_select_cont_desc">Exit split screen selection</string>
<!-- Label for toast when app selected for split isn't supported. [CHAR_LIMIT=50] -->
diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
index 5d4e19d..842f0ef 100644
--- a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
+++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
@@ -24,9 +24,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
-import android.annotation.TargetApi;
import android.content.Context;
-import android.os.Build;
import android.os.Handler;
import android.os.RemoteException;
import android.view.IRemoteAnimationFinishedCallback;
@@ -57,7 +55,6 @@
* the runner implementation. When this animation manager is destroyed, we remove the Launcher
* reference to the runner, leaving only the weak ref from the runner.
*/
-@TargetApi(Build.VERSION_CODES.P)
public class LauncherAnimationRunner extends RemoteAnimationRunnerCompat {
private static final RemoteAnimationFactory DEFAULT_FACTORY =
diff --git a/quickstep/src/com/android/launcher3/LauncherInitListener.java b/quickstep/src/com/android/launcher3/LauncherInitListener.java
index f64b5cf..523923d 100644
--- a/quickstep/src/com/android/launcher3/LauncherInitListener.java
+++ b/quickstep/src/com/android/launcher3/LauncherInitListener.java
@@ -15,14 +15,10 @@
*/
package com.android.launcher3;
-import android.annotation.TargetApi;
-import android.os.Build;
-
import com.android.quickstep.util.ActivityInitListener;
import java.util.function.BiPredicate;
-@TargetApi(Build.VERSION_CODES.P)
public class LauncherInitListener extends ActivityInitListener<Launcher> {
/**
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 656af31..e8a3d3e 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -64,6 +64,7 @@
import static com.android.launcher3.views.FloatingIconView.getFloatingIconView;
import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch;
+import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback;
import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius;
import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows;
@@ -88,6 +89,7 @@
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.IBinder;
+import android.os.IRemoteCallback;
import android.os.Looper;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -351,6 +353,9 @@
new RemoteAnimationAdapter(runner, duration, statusBarTransitionDelay),
new RemoteTransition(runner.toRemoteTransition(),
mLauncher.getIApplicationThread(), "QuickstepLaunch"));
+ IRemoteCallback endCallback = completeRunnableListCallback(onEndCallback);
+ options.setOnAnimationAbortListener(endCallback);
+ options.setOnAnimationFinishedListener(endCallback);
return new ActivityOptionsWrapper(options, onEndCallback);
}
@@ -1663,14 +1668,20 @@
? Cuj.CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK
: Cuj.CUJ_LAUNCHER_APP_CLOSE_TO_HOME);
- anim.addListener(new AnimatorListenerAdapter() {
+ AnimatorListenerAdapter endListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
AccessibilityManagerCompat.sendTestProtocolEventToTest(
mLauncher, WALLPAPER_OPEN_ANIMATION_FINISHED_MESSAGE);
}
- });
+ };
+
+ if (fromPredictiveBack) {
+ rectFSpringAnim.addAnimatorListener(endListener);
+ } else {
+ anim.addListener(endListener);
+ }
// Only register the content animation for cancellation when state changes
mLauncher.getStateManager().setCurrentAnimation(anim);
diff --git a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
index e680ea9..caf8a0b 100644
--- a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
@@ -16,10 +16,8 @@
package com.android.launcher3.appprediction;
-import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
-import android.os.Build;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
@@ -50,7 +48,6 @@
import java.util.List;
import java.util.stream.Collectors;
-@TargetApi(Build.VERSION_CODES.P)
public class PredictionRowView<T extends Context & ActivityContext>
extends LinearLayout implements OnDeviceProfileChangeListener, FloatingHeaderRow {
diff --git a/quickstep/src/com/android/launcher3/model/AppEventProducer.java b/quickstep/src/com/android/launcher3/model/AppEventProducer.java
index e17fc88..a931f36 100644
--- a/quickstep/src/com/android/launcher3/model/AppEventProducer.java
+++ b/quickstep/src/com/android/launcher3/model/AppEventProducer.java
@@ -45,14 +45,12 @@
import static com.android.launcher3.model.PredictionHelper.isTrackedForWidgetPrediction;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
-import android.annotation.TargetApi;
import android.app.prediction.AppTarget;
import android.app.prediction.AppTargetEvent;
import android.app.prediction.AppTargetId;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ShortcutInfo;
-import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.os.Process;
@@ -84,7 +82,6 @@
/**
* Utility class to track stats log and emit corresponding app events
*/
-@TargetApi(Build.VERSION_CODES.R)
public class AppEventProducer implements StatsLogConsumer {
private static final int MSG_LAUNCH = 0;
diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
index 667f784..0ce1cb8 100644
--- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
+++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
@@ -68,6 +68,7 @@
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.pm.UserCache;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.Executors;
import com.android.launcher3.util.IntSparseArrayMap;
@@ -553,7 +554,10 @@
if (lai == null) {
return null;
}
- AppInfo info = new AppInfo(lai, user, mUMS.isUserQuiet(user));
+ AppInfo info = new AppInfo(
+ lai,
+ UserCache.INSTANCE.get(mAppState.getContext()).getUserInfo(user),
+ mUMS.isUserQuiet(user));
info.container = mContainer;
mAppState.getIconCache().getTitleAndIcon(info, lai, false);
mReadCount++;
diff --git a/quickstep/src/com/android/launcher3/model/WellbeingModel.java b/quickstep/src/com/android/launcher3/model/WellbeingModel.java
index 003c2fc..3d04cb6 100644
--- a/quickstep/src/com/android/launcher3/model/WellbeingModel.java
+++ b/quickstep/src/com/android/launcher3/model/WellbeingModel.java
@@ -20,7 +20,6 @@
import static com.android.launcher3.util.SimpleBroadcastReceiver.getPackageFilter;
-import android.annotation.TargetApi;
import android.app.RemoteAction;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
@@ -30,7 +29,6 @@
import android.content.pm.LauncherApps;
import android.database.ContentObserver;
import android.net.Uri;
-import android.os.Build;
import android.os.Bundle;
import android.os.DeadObjectException;
import android.os.Handler;
@@ -63,7 +61,6 @@
/**
* Data model for digital wellbeing status of apps.
*/
-@TargetApi(Build.VERSION_CODES.Q)
public final class WellbeingModel extends BgObjectWithLooper {
private static final String TAG = "WellbeingModel";
private static final int[] RETRY_TIMES_MS = {5000, 15000, 30000};
diff --git a/quickstep/src/com/android/launcher3/proxy/ProxyActivityStarter.java b/quickstep/src/com/android/launcher3/proxy/ProxyActivityStarter.java
index 6d90b035..212a5ff 100644
--- a/quickstep/src/com/android/launcher3/proxy/ProxyActivityStarter.java
+++ b/quickstep/src/com/android/launcher3/proxy/ProxyActivityStarter.java
@@ -53,13 +53,10 @@
try {
if (mParams.intent != null) {
- startActivityForResult(mParams.intent, mParams.requestCode, mParams.options);
+ startActivity();
return;
} else if (mParams.intentSender != null) {
- startIntentSenderForResult(mParams.intentSender, mParams.requestCode,
- mParams.fillInIntent, mParams.flagsMask, mParams.flagsValues,
- mParams.extraFlags,
- mParams.options);
+ startIntentSender();
return;
}
} catch (NullPointerException | ActivityNotFoundException | SecurityException
@@ -83,4 +80,26 @@
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
}
+
+ private void startActivity() throws SendIntentException {
+ if (mParams.requireActivityResult) {
+ startActivityForResult(mParams.intent, mParams.requestCode, mParams.options);
+ } else {
+ startActivity(mParams.intent, mParams.options);
+ finishAndRemoveTask();
+ }
+ }
+
+ private void startIntentSender() throws SendIntentException {
+ if (mParams.requireActivityResult) {
+ startIntentSenderForResult(mParams.intentSender, mParams.requestCode,
+ mParams.fillInIntent, mParams.flagsMask, mParams.flagsValues,
+ mParams.extraFlags,
+ mParams.options);
+ } else {
+ startIntentSender(mParams.intentSender, mParams.fillInIntent, mParams.flagsMask,
+ mParams.flagsValues, mParams.extraFlags, mParams.options);
+ finishAndRemoveTask();
+ }
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/DesktopNavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/DesktopNavbarButtonsViewController.java
index 0a9dfff..3635827 100644
--- a/quickstep/src/com/android/launcher3/taskbar/DesktopNavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/DesktopNavbarButtonsViewController.java
@@ -28,6 +28,7 @@
import androidx.annotation.Nullable;
import com.android.launcher3.R;
+import com.android.launcher3.taskbar.navbutton.NearestTouchFrame;
/**
* Controller for managing buttons and status icons in taskbar in a desktop environment.
@@ -43,7 +44,7 @@
private TaskbarControllers mControllers;
public DesktopNavbarButtonsViewController(TaskbarActivityContext context,
- @Nullable Context navigationBarPanelContext, FrameLayout navButtonsView) {
+ @Nullable Context navigationBarPanelContext, NearestTouchFrame navButtonsView) {
super(context, navigationBarPanelContext, navButtonsView);
mContext = context;
mNavButtonsView = navButtonsView;
diff --git a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
index 535c8ec..f981610 100644
--- a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
@@ -105,13 +105,6 @@
}
@Override
- protected boolean isInOverview() {
- TopTaskTracker.CachedTaskInfo topTask = TopTaskTracker.INSTANCE
- .get(mControllers.taskbarActivityContext).getCachedTopTask(true);
- return topTask.isRecentsTask();
- }
-
- @Override
public RecentsView getRecentsView() {
return mRecentsActivity.getOverviewPanel();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 20e977b..e1b6494 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -16,6 +16,7 @@
package com.android.launcher3.taskbar;
import static com.android.launcher3.QuickstepTransitionManager.TRANSIENT_TASKBAR_TRANSITION_DURATION;
+import static com.android.launcher3.config.FeatureFlags.enableSplitContextually;
import static com.android.launcher3.statemanager.BaseState.FLAG_NON_INTERACTIVE;
import static com.android.launcher3.taskbar.TaskbarEduTooltipControllerKt.TOOLTIP_STEP_FEATURES;
import static com.android.launcher3.taskbar.TaskbarLauncherStateController.FLAG_VISIBLE;
@@ -214,7 +215,14 @@
}
mTaskbarLauncherStateController.updateStateForFlag(FLAG_VISIBLE, isVisible);
- return mTaskbarLauncherStateController.applyState(fromInit ? 0 : duration, startAnimation);
+ // TODO(b/308851855): Skip animation for launching split from home, will refine later
+ boolean skipAnimForSplit = enableSplitContextually() &&
+ mLauncher.areBothSplitAppsConfirmed() &&
+ mLauncher.getStateManager().getState() == LauncherState.NORMAL;
+ if (skipAnimForSplit || fromInit) {
+ duration = 0;
+ }
+ return mTaskbarLauncherStateController.applyState(duration, startAnimation);
}
@Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index bd44a35..1a1c64d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -91,6 +91,7 @@
import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarButton;
import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory;
import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.NavButtonLayoutter;
+import com.android.launcher3.taskbar.navbutton.NearestTouchFrame;
import com.android.launcher3.util.DimensionUtils;
import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
import com.android.launcher3.util.MultiValueAlpha;
@@ -151,7 +152,7 @@
private final TaskbarActivityContext mContext;
private final @Nullable Context mNavigationBarPanelContext;
private final WindowManagerProxy mWindowManagerProxy;
- private final FrameLayout mNavButtonsView;
+ private final NearestTouchFrame mNavButtonsView;
private final LinearLayout mNavButtonContainer;
// Used for IME+A11Y buttons
private final ViewGroup mEndContextualContainer;
@@ -208,7 +209,7 @@
private ImageView mRecentsButton;
public NavbarButtonsViewController(TaskbarActivityContext context,
- @Nullable Context navigationBarPanelContext, FrameLayout navButtonsView) {
+ @Nullable Context navigationBarPanelContext, NearestTouchFrame navButtonsView) {
mContext = context;
mNavigationBarPanelContext = navigationBarPanelContext;
mWindowManagerProxy = WindowManagerProxy.INSTANCE.get(mContext);
@@ -517,6 +518,10 @@
return (mState & FLAG_IME_VISIBLE) != 0;
}
+ public boolean isImeRenderingNavButtons() {
+ return mIsImeRenderingNavButtons;
+ }
+
/**
* Returns true if the home button is disabled
*/
@@ -1003,6 +1008,8 @@
+ mOnTaskbarBackgroundNavButtonColorOverride.value);
pw.println(prefix + "\t\tmOnBackgroundNavButtonColorOverrideMultiplier="
+ mOnBackgroundNavButtonColorOverrideMultiplier.value);
+
+ mNavButtonsView.dumpLogs(prefix + "\t", pw);
}
private static String getStateString(int flags) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 9f65f81..3f5793f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -37,24 +37,23 @@
import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_DRAGGING;
import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_FULLSCREEN;
import static com.android.launcher3.testing.shared.ResourceUtils.getBoolByName;
+import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
-import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityOptions;
-import android.app.ActivityTaskManager;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo.Config;
import android.content.pm.LauncherApps;
import android.content.res.Resources;
-import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
+import android.os.IRemoteCallback;
import android.os.Process;
import android.os.Trace;
import android.provider.Settings;
@@ -66,7 +65,6 @@
import android.view.View;
import android.view.WindowInsets;
import android.view.WindowManager;
-import android.widget.FrameLayout;
import android.widget.Toast;
import androidx.annotation.NonNull;
@@ -104,6 +102,7 @@
import com.android.launcher3.taskbar.bubbles.BubbleDragController;
import com.android.launcher3.taskbar.bubbles.BubbleStashController;
import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController;
+import com.android.launcher3.taskbar.navbutton.NearestTouchFrame;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayController;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
@@ -133,13 +132,10 @@
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider;
import java.io.PrintWriter;
-import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
-import java.util.Set;
import java.util.function.Consumer;
-import java.util.stream.Collectors;
/**
* The {@link ActivityContext} with which we inflate Taskbar-related Views. This allows UI elements
@@ -236,7 +232,7 @@
mDragLayer = (TaskbarDragLayer) mLayoutInflater.inflate(taskbarLayout, null, false);
TaskbarView taskbarView = mDragLayer.findViewById(R.id.taskbar_view);
TaskbarScrimView taskbarScrimView = mDragLayer.findViewById(R.id.taskbar_scrim);
- FrameLayout navButtonsView = mDragLayer.findViewById(R.id.navbuttons_view);
+ NearestTouchFrame navButtonsView = mDragLayer.findViewById(R.id.navbuttons_view);
StashedHandleView stashedHandleView = mDragLayer.findViewById(R.id.stashed_handle);
BubbleBarView bubbleBarView = mDragLayer.findViewById(R.id.taskbar_bubbles);
StashedHandleView bubbleHandleView = mDragLayer.findViewById(R.id.stashed_bubble_handle);
@@ -743,13 +739,14 @@
@Override
public ActivityOptionsWrapper makeDefaultActivityOptions(int splashScreenStyle) {
RunnableList callbacks = new RunnableList();
- ActivityOptions options = ActivityOptions.makeCustomAnimation(
- this, 0, 0, Color.TRANSPARENT,
- Executors.MAIN_EXECUTOR.getHandler(), null,
- elapsedRealTime -> callbacks.executeAllAndDestroy());
+ ActivityOptions options = ActivityOptions.makeCustomAnimation(this, 0, 0);
options.setSplashScreenStyle(splashScreenStyle);
options.setPendingIntentBackgroundActivityStartMode(
ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
+ IRemoteCallback endCallback = completeRunnableListCallback(callbacks);
+ options.setOnAnimationAbortListener(endCallback);
+ options.setOnAnimationFinishedListener(endCallback);
+
return new ActivityOptionsWrapper(options, callbacks);
}
@@ -1178,25 +1175,15 @@
@Nullable Task foundTask = foundTasks[0];
if (foundTask != null) {
TaskView foundTaskView = recents.getTaskViewByTaskId(foundTask.key.id);
- if (foundTaskView != null) {
- // The foundTaskView contains the 1-2 taskIds we are looking for.
- // If we are already in-app and running the correct tasks, no need
- // to do anything.
- if (FeatureFlags.enableAppPairs()
- && isAlreadyInApp(foundTaskView.getTaskIds())) {
- return;
- }
- // If we are in Overview and the TaskView tile is visible, expand that
- // tile.
- if (foundTaskView.isVisibleToUser()) {
- TestLogging.recordEvent(
- TestProtocol.SEQUENCE_MAIN, "start: taskbarAppIcon");
- foundTaskView.launchTasks();
- return;
- }
+ if (foundTaskView != null
+ && foundTaskView.isVisibleToUser()) {
+ TestLogging.recordEvent(
+ TestProtocol.SEQUENCE_MAIN, "start: taskbarAppIcon");
+ foundTaskView.launchTasks();
+ return;
}
}
- // If none of the above cases apply, launch a new app or app pair.
+
if (findExactPairMatch) {
// We did not find the app pair we were looking for, so launch one.
recents.getSplitSelectController().getAppPairsController().launchAppPair(
@@ -1208,27 +1195,6 @@
);
}
- /**
- * Checks if a given list of taskIds are all already running in-app.
- */
- private boolean isAlreadyInApp(int[] ids) {
- if (mControllers.uiController.isInOverview()) {
- return false;
- }
-
- RunningTaskInfo[] currentlyRunningTasks = ActivityManagerWrapper.getInstance()
- .getRunningTasks(false /* filterOnlyVisibleRecents */);
- Set<Integer> currentlyRunningIds = Arrays.stream(currentlyRunningTasks)
- .map(task -> task.taskId).collect(Collectors.toSet());
-
- for (int id : ids) {
- if (id != ActivityTaskManager.INVALID_TASK_ID && !currentlyRunningIds.contains(id)) {
- return false;
- }
- }
- return true;
- }
-
private void startItemInfoActivity(ItemInfo info) {
Intent intent = new Intent(info.getIntent())
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index 633383d..b8e6889 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -309,7 +309,12 @@
controllers.bubbleControllers.isPresent &&
controllers.bubbleControllers.get().bubbleBarViewController.isBubbleBarVisible()
var insetsIsTouchableRegion = true
- if (context.dragLayer.alpha < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD) {
+ if (context.isPhoneButtonNavMode &&
+ (!controllers.navbarButtonsViewController.isImeVisible
+ || !controllers.navbarButtonsViewController.isImeRenderingNavButtons)) {
+ insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_FRAME)
+ insetsIsTouchableRegion = false
+ } else if (context.dragLayer.alpha < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD) {
// Let touches pass through us.
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION)
debugTouchableRegion.lastSetTouchableReason = "Taskbar is invisible"
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index a850680..8e4a78f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -207,7 +207,7 @@
applyState();
boolean disallowLongClick =
FeatureFlags.enableSplitContextually()
- ? mLauncher.isSplitSelectionEnabled()
+ ? mLauncher.isSplitSelectionActive()
: finalState == LauncherState.OVERVIEW_SPLIT_SELECT;
com.android.launcher3.taskbar.Utilities.setOverviewDragState(
mControllers, finalState.disallowTaskbarGlobalDrag(),
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
index 41b777b..e2c71bf 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.taskbar;
+import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.InsetsFrameProvider.SOURCE_DISPLAY;
import static android.view.WindowInsets.Type.mandatorySystemGestures;
import static android.view.WindowInsets.Type.navigationBars;
@@ -53,8 +54,8 @@
public float navButtonsDarkIntensity;
// TaskbarManager#onNavigationBarLumaSamplingEnabled()
- public int mLumaSamplingDisplayId;
- public boolean mIsLumaSamplingEnabled;
+ public int mLumaSamplingDisplayId = DEFAULT_DISPLAY;
+ public boolean mIsLumaSamplingEnabled = true;
public boolean setupUIVisible = false;
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
index 1e3f4f1..aa2b29d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
@@ -50,6 +50,22 @@
var width: Float = 0f
+ /**
+ * Set whether the drawable is anchored to the left or right edge of the container.
+ *
+ * When `anchorLeft` is set to `true`, drawable left edge aligns up with the container left
+ * edge. Drawable can be drawn outside container bounds on the right edge. When it is set to
+ * `false` (the default), drawable right edge aligns up with the container right edge. Drawable
+ * can be drawn outside container bounds on the left edge.
+ */
+ var anchorLeft: Boolean = false
+ set(value) {
+ if (field != value) {
+ field = value
+ invalidateSelf()
+ }
+ }
+
init {
paint.color = context.getColor(R.color.taskbar_background)
paint.flags = Paint.ANTI_ALIAS_FLAG
@@ -106,15 +122,9 @@
// Draw background.
val radius = backgroundHeight / 2f
- canvas.drawRoundRect(
- canvas.width.toFloat() - width,
- 0f,
- canvas.width.toFloat(),
- canvas.height.toFloat(),
- radius,
- radius,
- paint
- )
+ val left = if (anchorLeft) 0f else canvas.width.toFloat() - width
+ val right = if (anchorLeft) width else canvas.width.toFloat()
+ canvas.drawRoundRect(left, 0f, right, canvas.height.toFloat(), radius, radius, paint)
if (showingArrow) {
// Draw arrow.
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index ec9f4e5..fbc7da1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -197,6 +197,18 @@
updateChildrenRenderNodeProperties();
}
+ @Override
+ public void onRtlPropertiesChanged(int layoutDirection) {
+ // TODO(b/313661121): set this based on bubble bar position and not LTR or RTL
+ boolean onLeft = layoutDirection == LAYOUT_DIRECTION_RTL;
+ mBubbleBarBackground.setAnchorLeft(onLeft);
+ mRelativePivotX = onLeft ? 0f : 1f;
+ }
+
+ private boolean isOnLeft() {
+ return getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+ }
+
/**
* Updates the bounds with translation that may have been applied and returns the result.
*/
@@ -275,18 +287,31 @@
int bubbleCount = getChildCount();
final float ty = (mBubbleBarBounds.height() - mIconSize) / 2f;
final boolean animate = getVisibility() == VISIBLE;
+ final boolean onLeft = isOnLeft();
for (int i = 0; i < bubbleCount; i++) {
BubbleView bv = (BubbleView) getChildAt(i);
bv.setTranslationY(ty);
// the position of the bubble when the bar is fully expanded
- final float expandedX = i * (mIconSize + mIconSpacing);
+ final float expandedX;
// the position of the bubble when the bar is fully collapsed
- final float collapsedX = i == 0 ? 0 : mIconOverlapAmount;
+ final float collapsedX;
+ if (onLeft) {
+ // If bar is on the left, bubbles are ordered right to left
+ expandedX = (bubbleCount - i - 1) * (mIconSize + mIconSpacing);
+ // Shift the first bubble only if there are more bubbles in addition to overflow
+ collapsedX = i == 0 && bubbleCount > 2 ? mIconOverlapAmount : 0;
+ } else {
+ // Bubbles ordered left to right, don't move the first bubble
+ expandedX = i * (mIconSize + mIconSpacing);
+ collapsedX = i == 0 ? 0 : mIconOverlapAmount;
+ }
if (mIsBarExpanded) {
+ // If bar is on the right, account for bubble bar expanding and shifting left
+ final float expandedBarShift = onLeft ? 0 : currentWidth - expandedWidth;
// where the bubble will end up when the animation ends
- final float targetX = currentWidth - expandedWidth + expandedX;
+ final float targetX = expandedX + expandedBarShift;
bv.setTranslationX(widthState * (targetX - collapsedX) + collapsedX);
// if we're fully expanded, set the z level to 0 or to bubble elevation if dragged
if (widthState == 1f) {
@@ -296,7 +321,9 @@
bv.setBehindStack(false, animate);
bv.setAlpha(1);
} else {
- final float targetX = currentWidth - collapsedWidth + collapsedX;
+ // If bar is on the right, account for bubble bar expanding and shifting left
+ final float collapsedBarShift = onLeft ? 0 : currentWidth - collapsedWidth;
+ final float targetX = collapsedX + collapsedBarShift;
bv.setTranslationX(widthState * (expandedX - targetX) + targetX);
bv.setZ((MAX_BUBBLES * mBubbleElevation) - i);
// If we're not the first bubble we're behind the stack
@@ -318,18 +345,22 @@
final float expandedArrowPosition = arrowPositionForSelectedWhenExpanded();
final float interpolatedWidth =
widthState * (expandedWidth - collapsedWidth) + collapsedWidth;
- if (mIsBarExpanded) {
- // when the bar is expanding, the selected bubble is always the first, so the arrow
- // always shifts with the interpolated width.
- final float arrowPosition = currentWidth - interpolatedWidth + collapsedArrowPosition;
- mBubbleBarBackground.setArrowPosition(arrowPosition);
+ final float arrowPosition;
+ if (onLeft) {
+ float interpolatedShift = (expandedArrowPosition - collapsedArrowPosition) * widthState;
+ arrowPosition = collapsedArrowPosition + interpolatedShift;
} else {
- final float targetPosition = currentWidth - collapsedWidth + collapsedArrowPosition;
- final float arrowPosition =
- targetPosition + widthState * (expandedArrowPosition - targetPosition);
- mBubbleBarBackground.setArrowPosition(arrowPosition);
+ if (mIsBarExpanded) {
+ // when the bar is expanding, the selected bubble is always the first, so the arrow
+ // always shifts with the interpolated width.
+ arrowPosition = currentWidth - interpolatedWidth + collapsedArrowPosition;
+ } else {
+ final float targetPosition = currentWidth - collapsedWidth + collapsedArrowPosition;
+ arrowPosition =
+ targetPosition + widthState * (expandedArrowPosition - targetPosition);
+ }
}
-
+ mBubbleBarBackground.setArrowPosition(arrowPosition);
mBubbleBarBackground.setArrowAlpha((int) (255 * widthState));
mBubbleBarBackground.setWidth(interpolatedWidth);
}
@@ -394,12 +425,14 @@
Log.w(TAG, "trying to update selection arrow without a selected view!");
return;
}
- final int index = indexOfChild(mSelectedBubbleView);
// Find the center of the bubble when it's expanded, set the arrow position to it.
- final float tx = getPaddingStart() + index * (mIconSize + mIconSpacing) + mIconSize / 2f;
-
+ final float tx = arrowPositionForSelectedWhenExpanded();
+ final float currentArrowPosition = mBubbleBarBackground.getArrowPositionX();
+ if (shouldAnimate && currentArrowPosition > expandedWidth()) {
+ Log.d(TAG, "arrow out of bounds of expanded view, skip animation");
+ shouldAnimate = false;
+ }
if (shouldAnimate) {
- final float currentArrowPosition = mBubbleBarBackground.getArrowPositionX();
ValueAnimator animator = ValueAnimator.ofFloat(currentArrowPosition, tx);
animator.setDuration(ARROW_POSITION_ANIMATION_DURATION_MS);
animator.addUpdateListener(animation -> {
@@ -416,12 +449,27 @@
private float arrowPositionForSelectedWhenExpanded() {
final int index = indexOfChild(mSelectedBubbleView);
- return getPaddingStart() + index * (mIconSize + mIconSpacing) + mIconSize / 2f;
+ final int bubblePosition;
+ if (isOnLeft()) {
+ // Bubble positions are reversed. First bubble is on the right.
+ bubblePosition = getChildCount() - index - 1;
+ } else {
+ bubblePosition = index;
+ }
+ return getPaddingStart() + bubblePosition * (mIconSize + mIconSpacing) + mIconSize / 2f;
}
private float arrowPositionForSelectedWhenCollapsed() {
final int index = indexOfChild(mSelectedBubbleView);
- return getPaddingStart() + index * (mIconOverlapAmount) + mIconSize / 2f;
+ final int bubblePosition;
+ if (isOnLeft()) {
+ // Bubble positions are reversed. First bubble may be shifted, if there are more
+ // bubbles than the current bubble and overflow.
+ bubblePosition = index == 0 && getChildCount() > 2 ? 1 : 0;
+ } else {
+ bubblePosition = index;
+ }
+ return getPaddingStart() + bubblePosition * (mIconOverlapAmount) + mIconSize / 2f;
}
@Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index 065dd58..6bb7b04 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -21,6 +21,7 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.util.Log;
+import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
@@ -289,7 +290,8 @@
*/
public void addBubble(BubbleBarItem b) {
if (b != null) {
- mBarView.addView(b.getView(), 0, new FrameLayout.LayoutParams(mIconSize, mIconSize));
+ mBarView.addView(b.getView(), 0,
+ new FrameLayout.LayoutParams(mIconSize, mIconSize, Gravity.LEFT));
b.getView().setOnClickListener(mBubbleClickListener);
mBubbleDragController.setupBubbleView(b.getView());
} else {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
index c998d97..f88460f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
@@ -16,6 +16,7 @@
package com.android.launcher3.taskbar.bubbles;
import static android.view.View.INVISIBLE;
+import static android.view.View.LAYOUT_DIRECTION_RTL;
import static android.view.View.VISIBLE;
import android.animation.Animator;
@@ -124,22 +125,35 @@
private void updateBounds() {
// As more bubbles get added, the icon bounds become larger. To ensure a consistent
// handle bar position, we pin it to the edge of the screen.
- final int right =
- mActivity.getDeviceProfile().widthPx - mBarViewController.getHorizontalMargin();
-
final int stashedCenterY = mStashedHandleView.getHeight() - mStashedTaskbarHeight / 2;
+ if (isOnLeft()) {
+ final int left = mBarViewController.getHorizontalMargin();
+ mStashedHandleBounds.set(
+ left,
+ stashedCenterY - mStashedHandleHeight / 2,
+ left + mStashedHandleWidth,
+ stashedCenterY + mStashedHandleHeight / 2);
+ mStashedHandleView.setPivotX(0);
+ } else {
+ final int right =
+ mActivity.getDeviceProfile().widthPx - mBarViewController.getHorizontalMargin();
+ mStashedHandleBounds.set(
+ right - mStashedHandleWidth,
+ stashedCenterY - mStashedHandleHeight / 2,
+ right,
+ stashedCenterY + mStashedHandleHeight / 2);
+ mStashedHandleView.setPivotX(mStashedHandleView.getWidth());
+ }
- mStashedHandleBounds.set(
- right - mStashedHandleWidth,
- stashedCenterY - mStashedHandleHeight / 2,
- right,
- stashedCenterY + mStashedHandleHeight / 2);
mStashedHandleView.updateSampledRegion(mStashedHandleBounds);
-
- mStashedHandleView.setPivotX(mStashedHandleView.getWidth());
mStashedHandleView.setPivotY(mStashedHandleView.getHeight() - mStashedTaskbarHeight / 2f);
}
+ private boolean isOnLeft() {
+ // TODO(b/313661121): set this based on bubble bar position and not LTR or RTL
+ return mStashedHandleView.getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+ }
+
public void onDestroy() {
mRegionSamplingHelper.stopAndDestroy();
mRegionSamplingHelper = null;
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt
index 22f0131..672bc0d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt
@@ -56,7 +56,7 @@
*/
fun getUiLayoutter(
deviceProfile: DeviceProfile,
- navButtonsView: FrameLayout,
+ navButtonsView: NearestTouchFrame,
imeSwitcher: ImageView?,
rotationButton: RotationButton?,
a11yButton: ImageView?,
@@ -78,6 +78,7 @@
return when {
isPhoneNavMode -> {
if (!deviceProfile.isLandscape) {
+ navButtonsView.setIsVertical(false)
PhonePortraitNavLayoutter(
resources,
navButtonContainer,
@@ -88,6 +89,7 @@
a11yButton
)
} else if (surfaceRotation == ROTATION_90) {
+ navButtonsView.setIsVertical(true)
PhoneLandscapeNavLayoutter(
resources,
navButtonContainer,
@@ -98,6 +100,7 @@
a11yButton
)
} else {
+ navButtonsView.setIsVertical(true)
PhoneSeascapeNavLayoutter(
resources,
navButtonContainer,
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/NearestTouchFrame.java b/quickstep/src/com/android/launcher3/taskbar/navbutton/NearestTouchFrame.java
new file mode 100644
index 0000000..a477303
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/NearestTouchFrame.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar.navbutton;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * Redirects touches that aren't handled by any child view to the nearest
+ * clickable child. Only takes effect on <sw600dp.
+ */
+public class NearestTouchFrame extends FrameLayout {
+
+ private final List<View> mClickableChildren = new ArrayList<>();
+ private final List<View> mAttachedChildren = new ArrayList<>();
+ private final boolean mIsActive;
+
+ private boolean mIsVertical;
+ private View mTouchingChild;
+ private final Map<View, Rect> mTouchableRegions = new HashMap<>();
+ /**
+ * Used to sort all child views either by their left position or their top position,
+ * depending on if this layout is used horizontally or vertically, respectively
+ */
+ private final Comparator<View> mChildRegionComparator =
+ (view1, view2) -> {
+ int startingCoordView1 = mIsVertical ? view1.getTop() : view1.getLeft();
+ int startingCoordView2 = mIsVertical ? view2.getTop() : view2.getLeft();
+
+ return startingCoordView1 - startingCoordView2;
+ };
+
+ public NearestTouchFrame(Context context, AttributeSet attrs) {
+ this(context, attrs, context.getResources().getConfiguration());
+ }
+
+ public NearestTouchFrame(Context context, AttributeSet attrs, Configuration c) {
+ super(context, attrs);
+ mIsActive = c.smallestScreenWidthDp < 600;
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ mClickableChildren.clear();
+ mAttachedChildren.clear();
+ mTouchableRegions.clear();
+ addClickableChildren(this);
+ cacheClosestChildLocations();
+ }
+
+ /**
+ * Populates {@link #mTouchableRegions} with the regions where each clickable child is the
+ * closest for a given point on this layout.
+ */
+ private void cacheClosestChildLocations() {
+ if (getWidth() == 0 || getHeight() == 0) {
+ return;
+ }
+
+ // Sort by either top or left depending on mIsVertical, then take out all children
+ // that are not attached to window
+ mClickableChildren.sort(mChildRegionComparator);
+ mClickableChildren.stream()
+ .filter(View::isAttachedToWindow)
+ .forEachOrdered(mAttachedChildren::add);
+
+ // Cache bounds of children
+ // Mark coordinates where the actual child layout resides in this frame's window
+ for (int i = 0; i < mAttachedChildren.size(); i++) {
+ View child = mAttachedChildren.get(i);
+ if (!child.isAttachedToWindow()) {
+ continue;
+ }
+ Rect childRegion = getChildsBounds(child);
+
+ // We compute closest child from this child to the previous one
+ if (i == 0) {
+ // First child, nothing to the left/top of it
+ if (mIsVertical) {
+ childRegion.top = 0;
+ } else {
+ childRegion.left = 0;
+ }
+ mTouchableRegions.put(child, childRegion);
+ continue;
+ }
+
+ View previousChild = mAttachedChildren.get(i - 1);
+ Rect previousChildBounds = mTouchableRegions.get(previousChild);
+ int midPoint;
+ if (mIsVertical) {
+ int distance = childRegion.top - previousChildBounds.bottom;
+ midPoint = distance / 2;
+ childRegion.top -= midPoint;
+ previousChildBounds.bottom += midPoint - ((distance % 2) == 0 ? 1 : 0);
+ } else {
+ int distance = childRegion.left - previousChildBounds.right;
+ midPoint = distance / 2;
+ childRegion.left -= midPoint;
+ previousChildBounds.right += midPoint - ((distance % 2) == 0 ? 1 : 0);
+ }
+
+ if (i == mClickableChildren.size() - 1) {
+ // Last child, nothing to right/bottom of it
+ if (mIsVertical) {
+ childRegion.bottom = getHeight();
+ } else {
+ childRegion.right = getWidth();
+ }
+ }
+
+ mTouchableRegions.put(child, childRegion);
+ }
+ }
+
+ void setIsVertical(boolean isVertical) {
+ mIsVertical = isVertical;
+ }
+
+ private Rect getChildsBounds(View child) {
+ int left = child.getLeft();
+ int top = child.getTop();
+ int right = left + child.getWidth();
+ int bottom = top + child.getHeight();
+ return new Rect(left, top, right, bottom);
+ }
+
+ private void addClickableChildren(ViewGroup group) {
+ final int N = group.getChildCount();
+ for (int i = 0; i < N; i++) {
+ View child = group.getChildAt(i);
+ if (child.isClickable()) {
+ mClickableChildren.add(child);
+ } else if (child instanceof ViewGroup) {
+ addClickableChildren((ViewGroup) child);
+ }
+ }
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (mIsActive) {
+ int x = (int) event.getX();
+ int y = (int) event.getY();
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ mTouchingChild = mClickableChildren
+ .stream()
+ .filter(View::isAttachedToWindow)
+ .filter(view -> mTouchableRegions.get(view).contains(x, y))
+ .findFirst()
+ .orElse(null);
+
+ }
+ if (mTouchingChild != null) {
+ // Translate the touch event to the view center of the touching child.
+ event.offsetLocation(mTouchingChild.getWidth() / 2 - x,
+ mTouchingChild.getHeight() / 2 - y);
+ return mTouchingChild.getVisibility() == VISIBLE
+ && mTouchingChild.dispatchTouchEvent(event);
+ }
+ }
+ return super.onTouchEvent(event);
+ }
+
+ public void dumpLogs(String prefix, PrintWriter pw) {
+ pw.println(prefix + "NearestTouchFrame:");
+
+ pw.println(String.format("%s\tmIsVertical=%s", prefix, mIsVertical));
+ pw.println(String.format("%s\tmTouchingChild=%s", prefix, mTouchingChild));
+ pw.println(String.format("%s\tmTouchableRegions=%s", prefix,
+ mTouchableRegions.keySet().stream()
+ .map(key -> key + "=" + mTouchableRegions.get(key))
+ .collect(Collectors.joining(", ", "{", "}"))));
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
index 3ebc8ed..5c4eb9d 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
@@ -138,6 +138,11 @@
|| Flags.enablePrivateSpaceInstallShortcut())) {
StartActivityParams params = new StartActivityParams((PendingIntent) null, 0);
params.intentSender = launcherApps.getAppMarketActivityIntent(packageName, user);
+ ActivityOptions options = ActivityOptions.makeBasic()
+ .setPendingIntentBackgroundActivityStartMode(ActivityOptions
+ .MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
+ params.options = options.toBundle();
+ params.requireActivityResult = false;
return ProxyActivityStarter.getLaunchIntent(context, params);
} else {
return new Intent(Intent.ACTION_VIEW)
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
index d834935..22f24f1 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
@@ -59,7 +59,7 @@
return RemoteViews.startPendingIntent(hostView, pendingIntent,
remoteResponse.getLaunchOptions(view));
}
- if (mLauncher.isSplitSelectionEnabled()) {
+ if (mLauncher.isSplitSelectionActive()) {
// Log metric
StatsLogManager.StatsLogger logger = mLauncher.getStatsLogManager().logger();
logger.log(LAUNCHER_SPLIT_WIDGET_ATTEMPT);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 2e8e613..0991fce 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -54,6 +54,7 @@
import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN;
import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback;
import static com.android.quickstep.util.SplitAnimationTimings.TABLET_HOME_TO_SPLIT;
import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
@@ -67,7 +68,6 @@
import android.content.Intent;
import android.content.IntentSender;
import android.content.res.Configuration;
-import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.RectF;
import android.hardware.display.DisplayManager;
@@ -75,6 +75,7 @@
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.IRemoteCallback;
import android.os.SystemProperties;
import android.os.Trace;
import android.util.AttributeSet;
@@ -145,7 +146,6 @@
import com.android.launcher3.uioverrides.touchcontrollers.TwoButtonNavbarTouchController;
import com.android.launcher3.util.ActivityOptionsWrapper;
import com.android.launcher3.util.DisplayController;
-import com.android.launcher3.util.Executors;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.NavigationMode;
import com.android.launcher3.util.ObjectWrapper;
@@ -725,10 +725,14 @@
}
@Override
- public boolean isSplitSelectionEnabled() {
+ public boolean isSplitSelectionActive() {
return mSplitSelectStateController.isSplitSelectActive();
}
+ public boolean areBothSplitAppsConfirmed() {
+ return mSplitSelectStateController.isBothSplitAppsConfirmed();
+ }
+
@Override
public void onStateTransitionCompletedAfterSwipeToHome(LauncherState finalState) {
if (mTaskbarUIController != null) {
@@ -1136,13 +1140,14 @@
@Override
public ActivityOptionsWrapper makeDefaultActivityOptions(int splashScreenStyle) {
RunnableList callbacks = new RunnableList();
- ActivityOptions options = ActivityOptions.makeCustomAnimation(
- this, 0, 0, Color.TRANSPARENT,
- Executors.MAIN_EXECUTOR.getHandler(), null,
- elapsedRealTime -> callbacks.executeAllAndDestroy());
+ ActivityOptions options = ActivityOptions.makeCustomAnimation(this, 0, 0);
options.setSplashScreenStyle(splashScreenStyle);
options.setPendingIntentBackgroundActivityStartMode(
ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
+
+ IRemoteCallback endCallback = completeRunnableListCallback(callbacks);
+ options.setOnAnimationAbortListener(endCallback);
+ options.setOnAnimationFinishedListener(endCallback);
return new ActivityOptionsWrapper(options, callbacks);
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index 23e922c..27224f2 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -17,6 +17,7 @@
import static com.android.app.animation.Interpolators.LINEAR;
import static com.android.launcher3.LauncherState.CLEAR_ALL_BUTTON;
+import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.LauncherState.OVERVIEW_ACTIONS;
import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_ACTIONS_FADE;
@@ -27,6 +28,7 @@
import static com.android.quickstep.views.RecentsView.TASK_PRIMARY_SPLIT_TRANSLATION;
import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_SPLIT_TRANSLATION;
import static com.android.quickstep.views.TaskView.FLAG_UPDATE_ALL;
+import static com.android.wm.shell.Flags.enableSplitContextual;
import android.animation.AnimatorSet;
import android.annotation.TargetApi;
@@ -120,7 +122,9 @@
*/
private void handleSplitSelectionState(@NonNull LauncherState toState,
@NonNull PendingAnimation builder, boolean animate) {
- if (toState != OVERVIEW_SPLIT_SELECT) {
+ boolean goingToOverviewFromWorkspaceContextual = enableSplitContextual() &&
+ toState == OVERVIEW && mLauncher.isSplitSelectionActive();
+ if (toState != OVERVIEW_SPLIT_SELECT && !goingToOverviewFromWorkspaceContextual) {
// Not going to split
return;
}
@@ -135,9 +139,11 @@
SplitAnimationTimings timings =
AnimUtils.getDeviceOverviewToSplitTimings(mLauncher.getDeviceProfile().isTablet);
-
- mRecentsView.createSplitSelectInitAnimation(builder,
- toState.getTransitionDuration(mLauncher, true /* isToState */));
+ if (!goingToOverviewFromWorkspaceContextual) {
+ // This animation is already done for the contextual case, don't redo it
+ mRecentsView.createSplitSelectInitAnimation(builder,
+ toState.getTransitionDuration(mLauncher, true /* isToState */));
+ }
// Shift tasks vertically downward to get out of placeholder view
builder.setFloat(mRecentsView, taskViewsFloat.first,
toState.getSplitSelectTranslation(mLauncher),
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index 396d0ab..7650235 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -17,6 +17,7 @@
import static com.android.app.animation.Interpolators.DECELERATE_2;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW;
+import static com.android.wm.shell.Flags.enableSplitContextual;
import android.content.Context;
import android.graphics.Rect;
@@ -120,10 +121,22 @@
if (showFloatingSearch) {
elements |= FLOATING_SEARCH_BAR;
}
+ if (enableSplitContextual() && launcher.isSplitSelectionActive()) {
+ elements &= ~CLEAR_ALL_BUTTON;
+ }
return elements;
}
@Override
+ public float getSplitSelectTranslation(Launcher launcher) {
+ if (!enableSplitContextual() || !launcher.isSplitSelectionActive()) {
+ return 0f;
+ }
+ RecentsView recentsView = launcher.getOverviewPanel();
+ return recentsView.getSplitSelectTranslation();
+ }
+
+ @Override
public int getFloatingSearchBarRestingMarginBottom(Launcher launcher) {
return areElementsVisible(launcher, FLOATING_SEARCH_BAR) ? 0
: super.getFloatingSearchBarRestingMarginBottom(launcher);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
index 19bfe06..ec84550 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
@@ -59,7 +59,7 @@
private static final long MAX_TASK_DISMISS_ANIMATION_DURATION = 600;
public static final int TASK_DISMISS_VIBRATION_PRIMITIVE =
- Utilities.ATLEAST_R ? VibrationEffect.Composition.PRIMITIVE_TICK : -1;
+ VibrationEffect.Composition.PRIMITIVE_TICK;
public static final float TASK_DISMISS_VIBRATION_PRIMITIVE_SCALE = 1f;
public static final VibrationEffect TASK_DISMISS_VIBRATION_FALLBACK =
VibrationConstants.EFFECT_TEXTURE_TICK;
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index cbf6ad6..60d0e2b 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -64,7 +64,6 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
-import android.annotation.TargetApi;
import android.app.ActivityManager;
import android.app.TaskInfo;
import android.app.WindowConfiguration;
@@ -75,7 +74,6 @@
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
-import android.os.Build;
import android.os.IBinder;
import android.os.SystemClock;
import android.util.Log;
@@ -161,7 +159,6 @@
/**
* Handles the navigation gestures when Launcher is the default home activity.
*/
-@TargetApi(Build.VERSION_CODES.R)
public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
Q extends RecentsView, S extends BaseState<S>>
extends SwipeUpAnimationLogic implements OnApplyWindowInsetsListener,
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 2dd6a29..377b866 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -35,13 +35,11 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
-import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.PointF;
import android.graphics.Rect;
-import android.os.Build;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.RemoteAnimationTarget;
@@ -77,7 +75,6 @@
/**
* Utility class which abstracts out the logical differences between Launcher and RecentsActivity.
*/
-@TargetApi(Build.VERSION_CODES.P)
public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_TYPE>,
ACTIVITY_TYPE extends StatefulActivity<STATE_TYPE>> {
diff --git a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
index 57b9a39..e77a450 100644
--- a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
@@ -29,7 +29,6 @@
import static com.android.quickstep.OverviewComponentObserver.startHomeIntentSafely;
import android.animation.ObjectAnimator;
-import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityOptions;
import android.content.Context;
@@ -37,7 +36,6 @@
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
-import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -66,7 +64,6 @@
import com.android.launcher3.util.DisplayController;
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.fallback.RecentsState;
-import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties;
import com.android.quickstep.util.TransformParams;
@@ -82,7 +79,6 @@
/**
* Handles the navigation gestures when a 3rd party launcher is the default home activity.
*/
-@TargetApi(Build.VERSION_CODES.R)
public class FallbackSwipeHandler extends
AbsSwipeUpHandler<RecentsActivity, FallbackRecentsView, RecentsState> {
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index 575be5f..d02909c 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -29,9 +29,7 @@
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.SET_END_TARGET_HOME;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.SET_END_TARGET_NEW_TASK;
-import android.annotation.TargetApi;
import android.content.Intent;
-import android.os.Build;
import android.view.MotionEvent;
import android.view.RemoteAnimationTarget;
@@ -58,7 +56,6 @@
* Manages the state for an active system gesture, listens for events from the system and Launcher,
* and fires events when the states change.
*/
-@TargetApi(Build.VERSION_CODES.R)
public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationListener {
final Predicate<RemoteAnimationTarget> mLastStartedTaskIdPredicate = new Predicate<>() {
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index b2429ad..315316d 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -18,10 +18,8 @@
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID;
-import android.annotation.TargetApi;
import android.content.Intent;
import android.graphics.PointF;
-import android.os.Build;
import android.os.SystemClock;
import android.os.Trace;
import android.view.View;
@@ -51,7 +49,6 @@
/**
* Helper class to handle various atomic commands for switching between Overview.
*/
-@TargetApi(Build.VERSION_CODES.P)
public class OverviewCommandHelper {
public static final int TYPE_SHOW = 1;
diff --git a/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java b/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java
index d1939ef..3c902e6 100644
--- a/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java
+++ b/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java
@@ -15,10 +15,8 @@
*/
package com.android.quickstep;
-import android.annotation.TargetApi;
import android.content.Context;
import android.content.pm.PackageManager;
-import android.os.Build;
import android.os.Looper;
import android.os.Trace;
import android.os.UserManager;
@@ -30,7 +28,6 @@
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
@SuppressWarnings("unused")
-@TargetApi(Build.VERSION_CODES.R)
public class QuickstepProcessInitializer extends MainProcessInitializer {
private static final String TAG = "QuickstepProcessInitializer";
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index 7c263b8..f3704e09 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -23,12 +23,10 @@
import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
import static com.android.wm.shell.util.GroupedRecentTaskInfo.TYPE_FREEFORM;
-import android.annotation.TargetApi;
import android.app.ActivityManager;
import android.app.KeyguardManager;
import android.app.TaskInfo;
import android.content.ComponentName;
-import android.os.Build;
import android.os.Process;
import android.os.RemoteException;
import android.util.SparseBooleanArray;
@@ -53,7 +51,6 @@
/**
* Manages the recent task list from the system, caching it as necessary.
*/
-@TargetApi(Build.VERSION_CODES.R)
public class RecentTasksList {
private static final TaskLoadResult INVALID_RESULT = new TaskLoadResult(-1, false, 0);
diff --git a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
index 98d0ece..2e70703 100644
--- a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
+++ b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
@@ -20,11 +20,13 @@
import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
import static com.android.wm.shell.util.SplitBounds.KEY_EXTRA_SPLIT_BOUNDS;
+import android.app.WindowConfiguration;
import android.content.Context;
import android.graphics.Rect;
import android.util.Log;
import android.view.RemoteAnimationTarget;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.util.SplitConfigurationOptions;
@@ -35,6 +37,8 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
/**
* Glues together the necessary components to animate a remote target using a
@@ -43,7 +47,9 @@
public class RemoteTargetGluer {
private static final String TAG = "RemoteTargetGluer";
- private static final int DEFAULT_NUM_HANDLES = 2;
+ // This is the default number of handles to create when we don't know how many tasks are running
+ // (e.g. if we're in split screen). Allocate extra for potential tasks overlaid, like volume.
+ private static final int DEFAULT_NUM_HANDLES = 4;
private RemoteTargetHandle[] mRemoteTargetHandles;
private SplitConfigurationOptions.SplitBounds mSplitBounds;
@@ -107,7 +113,7 @@
for (int i = 0; i < mRemoteTargetHandles.length; i++) {
RemoteAnimationTarget primaryTaskTarget = targets.apps[i];
mRemoteTargetHandles[i].mTransformParams.setTargetSet(
- createRemoteAnimationTargetsForTarget(targets, null));
+ createRemoteAnimationTargetsForTarget(targets, Collections.emptyList()));
mRemoteTargetHandles[i].mTaskViewSimulator.setPreview(primaryTaskTarget, null);
}
return mRemoteTargetHandles;
@@ -177,18 +183,42 @@
RemoteAnimationTarget topLeftTarget = targets.findTask(mSplitBounds.leftTopTaskId);
RemoteAnimationTarget bottomRightTarget = targets.findTask(
mSplitBounds.rightBottomTaskId);
+ List<RemoteAnimationTarget> overlayTargets = Arrays.stream(targets.apps).filter(
+ target -> target.windowConfiguration.getWindowingMode()
+ != WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW).toList();
// remoteTargetHandle[0] denotes topLeft task, so we pass in the bottomRight to exclude,
// vice versa
mRemoteTargetHandles[0].mTransformParams.setTargetSet(
- createRemoteAnimationTargetsForTarget(targets, bottomRightTarget));
- mRemoteTargetHandles[0].mTaskViewSimulator.setPreview(topLeftTarget,
- mSplitBounds);
+ createRemoteAnimationTargetsForTarget(targets,
+ Collections.singletonList(bottomRightTarget)));
+ mRemoteTargetHandles[0].mTaskViewSimulator.setPreview(topLeftTarget, mSplitBounds);
mRemoteTargetHandles[1].mTransformParams.setTargetSet(
- createRemoteAnimationTargetsForTarget(targets, topLeftTarget));
- mRemoteTargetHandles[1].mTaskViewSimulator.setPreview(bottomRightTarget,
- mSplitBounds);
+ createRemoteAnimationTargetsForTarget(targets,
+ Collections.singletonList(topLeftTarget)));
+ mRemoteTargetHandles[1].mTaskViewSimulator.setPreview(bottomRightTarget, mSplitBounds);
+
+ // Set the remaining overlay tasks to be their own TaskViewSimulator as fullscreen tasks
+ if (!overlayTargets.isEmpty()) {
+ ArrayList<RemoteAnimationTarget> targetsToExclude = new ArrayList<>();
+ targetsToExclude.add(topLeftTarget);
+ targetsToExclude.add(bottomRightTarget);
+ // Start i at 2 to account for top/left and bottom/right split handles already made
+ for (int i = 2; i < targets.apps.length; i++) {
+ if (i >= mRemoteTargetHandles.length) {
+ Log.e(TAG, String.format("Attempting to animate an untracked target"
+ + " (%d handles allocated, but %d want to animate)",
+ mRemoteTargetHandles.length, targets.apps.length));
+ break;
+ }
+ mRemoteTargetHandles[i].mTransformParams.setTargetSet(
+ createRemoteAnimationTargetsForTarget(targets, targetsToExclude));
+ mRemoteTargetHandles[i].mTaskViewSimulator.setPreview(
+ overlayTargets.get(i - 2));
+ }
+
+ }
}
return mRemoteTargetHandles;
}
@@ -214,32 +244,38 @@
/**
* Ensures that we aren't excluding ancillary targets such as home/recents
*
- * @param targetToExclude Will be excluded from the resulting return value.
- * Pass in {@code null} to not exclude anything
+ * @param targetsToExclude Will be excluded from the resulting return value.
+ * Pass in an empty list to not exclude anything
* @return RemoteAnimationTargets where all the app targets from the passed in
- * {@param targets} are included except {@param targetToExclude}
+ * {@code targets} are included except {@code targetsToExclude}
*/
private RemoteAnimationTargets createRemoteAnimationTargetsForTarget(
- RemoteAnimationTargets targets,
- RemoteAnimationTarget targetToExclude) {
- ArrayList<RemoteAnimationTarget> targetsWithoutExcluded = new ArrayList<>();
+ @NonNull RemoteAnimationTargets targets,
+ @NonNull List<RemoteAnimationTarget> targetsToExclude) {
+ ArrayList<RemoteAnimationTarget> targetsToInclude = new ArrayList<>();
for (RemoteAnimationTarget targetCompat : targets.unfilteredApps) {
- if (targetCompat == targetToExclude) {
+ boolean skipTarget = false;
+ for (RemoteAnimationTarget excludingTarget : targetsToExclude) {
+ if (targetCompat == excludingTarget) {
+ skipTarget = true;
+ break;
+ }
+ if (excludingTarget != null
+ && excludingTarget.taskInfo != null
+ && targetCompat.taskInfo != null
+ && excludingTarget.taskInfo.parentTaskId == targetCompat.taskInfo.taskId) {
+ // Also exclude corresponding parent task
+ skipTarget = true;
+ }
+ }
+ if (skipTarget) {
continue;
}
- if (targetToExclude != null
- && targetToExclude.taskInfo != null
- && targetCompat.taskInfo != null
- && targetToExclude.taskInfo.parentTaskId == targetCompat.taskInfo.taskId) {
- // Also exclude corresponding parent task
- continue;
- }
-
- targetsWithoutExcluded.add(targetCompat);
+ targetsToInclude.add(targetCompat);
}
- final RemoteAnimationTarget[] filteredApps = targetsWithoutExcluded.toArray(
- new RemoteAnimationTarget[targetsWithoutExcluded.size()]);
+ final RemoteAnimationTarget[] filteredApps = targetsToInclude.toArray(
+ new RemoteAnimationTarget[0]);
return new RemoteAnimationTargets(
filteredApps, targets.wallpapers, targets.nonApps, targets.targetMode);
}
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 4e84f4a..8ff43f0 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -43,14 +43,12 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
-import android.annotation.TargetApi;
import android.content.ComponentName;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.Matrix.ScaleToFit;
import android.graphics.Rect;
import android.graphics.RectF;
-import android.os.Build;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.view.View;
@@ -94,7 +92,6 @@
/**
* Utility class for helpful methods related to {@link TaskView} objects and their tasks.
*/
-@TargetApi(Build.VERSION_CODES.R)
public final class TaskViewUtils {
private TaskViewUtils() {}
@@ -196,12 +193,13 @@
remoteTargetHandles = gluer.assignTargets(targets);
}
}
+
final int recentsActivityRotation =
recentsView.getPagedViewOrientedState().getRecentsActivityRotation();
- for (RemoteTargetHandle remoteTargetGluer : remoteTargetHandles) {
- remoteTargetGluer.getTaskViewSimulator().getOrientationState().setRecentsRotation(
- recentsActivityRotation);
- remoteTargetGluer.getTransformParams().setSyncTransactionApplier(applier);
+ for (RemoteTargetHandle remoteTargetHandle : remoteTargetHandles) {
+ remoteTargetHandle.getTaskViewSimulator().getOrientationState()
+ .setRecentsRotation(recentsActivityRotation);
+ remoteTargetHandle.getTransformParams().setSyncTransactionApplier(applier);
}
int taskIndex = recentsView.indexOfChild(v);
@@ -394,6 +392,13 @@
out.addListener(new AnimationSuccessListener() {
@Override
+ public void onAnimationStart(Animator animation) {
+ for (RemoteTargetHandle remoteTargetHandle : remoteTargetHandles) {
+ remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(false);
+ }
+ }
+
+ @Override
public void onAnimationSuccess(Animator animator) {
if (isQuickSwitch) {
InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_QUICK_SWITCH);
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index ce6ddd8..55a7985 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -56,7 +56,6 @@
import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_SPLIT_SCREEN;
import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_STARTING_WINDOW;
-import android.annotation.TargetApi;
import android.app.PendingIntent;
import android.app.RemoteAction;
import android.app.Service;
@@ -66,7 +65,6 @@
import android.content.res.Configuration;
import android.graphics.Region;
import android.graphics.drawable.Icon;
-import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
@@ -152,7 +150,6 @@
/**
* Service connected by system-UI for handling touch interaction.
*/
-@TargetApi(Build.VERSION_CODES.R)
public class TouchInteractionService extends Service {
private static final String SUBSTRING_PREFIX = "; ";
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index 1008da3..0ee50a4 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -24,9 +24,7 @@
import static com.android.quickstep.fallback.RecentsState.OVERVIEW_SPLIT_SELECT;
import android.animation.AnimatorSet;
-import android.annotation.TargetApi;
import android.content.Context;
-import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
@@ -55,7 +53,6 @@
import java.util.ArrayList;
-@TargetApi(Build.VERSION_CODES.R)
public class FallbackRecentsView extends RecentsView<RecentsActivity, RecentsState>
implements StateListener<RecentsState> {
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index eedd204..c8c7dc2 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -31,12 +31,10 @@
import static com.android.launcher3.util.VelocityUtils.PX_PER_MS;
import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID;
-import android.annotation.TargetApi;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.graphics.PointF;
-import android.os.Build;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
@@ -71,7 +69,6 @@
/**
* Input consumer for handling events originating from an activity other than Launcher
*/
-@TargetApi(Build.VERSION_CODES.P)
public class OtherActivityInputConsumer extends ContextWrapper implements InputConsumer {
public static final String DOWN_EVT = "OtherActivityInputConsumer.DOWN";
diff --git a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
index a36f501..4198e2d 100644
--- a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
@@ -54,6 +54,8 @@
static final String KEY_TUTORIAL_TYPE = "tutorial_type";
static final String KEY_GESTURE_COMPLETE = "gesture_complete";
static final String KEY_USE_TUTORIAL_MENU = "use_tutorial_menu";
+ public static final double SQUARE_ASPECT_RATIO_BOTTOM_BOUND = 0.95;
+ public static final double SQUARE_ASPECT_RATIO_UPPER_BOUND = 1.05;
@Nullable private TutorialType[] mTutorialSteps;
private GestureSandboxFragment mCurrentFragment;
@@ -159,14 +161,20 @@
* Gesture animations are only in landscape for large screens and portrait for mobile. This
* method enforces the following flows:
* 1) phone / two-panel closed -> lock to portrait
- * 2) two-panel open / tablet + portrait -> prompt the user to rotate the screen
- * 3) two-panel open / tablet + landscape -> hide potential rotating prompt
+ * 2) Large screen + portrait -> prompt the user to rotate the screen
+ * 3) Large screen + landscape -> hide potential rotating prompt
+ * 4) Square aspect ratio -> no action taken as the animations will fit both orientations
*/
private void correctUserOrientation() {
DeviceProfile deviceProfile = InvariantDeviceProfile.INSTANCE.get(
getApplicationContext()).getDeviceProfile(this);
if (deviceProfile.isTablet) {
- boolean showRotationPrompt = getResources().getConfiguration().orientation
+ // The tutorial will work in either orientation if the height and width are similar
+ boolean isAspectRatioSquare =
+ deviceProfile.aspectRatio > SQUARE_ASPECT_RATIO_BOTTOM_BOUND
+ && deviceProfile.aspectRatio < SQUARE_ASPECT_RATIO_UPPER_BOUND;
+ boolean showRotationPrompt = !isAspectRatioSquare
+ && getResources().getConfiguration().orientation
== ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
GestureSandboxFragment recreatedFragment =
diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
index df552cf..1129e02 100644
--- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
@@ -17,9 +17,7 @@
import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL;
-import android.annotation.TargetApi;
import android.graphics.PointF;
-import android.os.Build;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -30,7 +28,6 @@
import java.util.Map;
/** A {@link TutorialController} for the Home tutorial. */
-@TargetApi(Build.VERSION_CODES.R)
final class HomeGestureTutorialController extends SwipeUpGestureTutorialController {
HomeGestureTutorialController(HomeGestureTutorialFragment fragment, TutorialType tutorialType) {
diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
index 65f3a01..a04dd44 100644
--- a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
@@ -21,9 +21,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
-import android.annotation.TargetApi;
import android.graphics.PointF;
-import android.os.Build;
import android.os.Handler;
import androidx.annotation.ColorInt;
@@ -42,7 +40,6 @@
import java.util.Map;
/** A {@link TutorialController} for the Overview tutorial. */
-@TargetApi(Build.VERSION_CODES.R)
final class OverviewGestureTutorialController extends SwipeUpGestureTutorialController {
private static final float LAUNCHER_COLOR_BLENDING_RATIO = 0.4f;
diff --git a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
index 87defc5..d5cc447 100644
--- a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
@@ -29,13 +29,11 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
-import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Outline;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
-import android.os.Build;
import android.view.View;
import android.view.ViewOutlineProvider;
@@ -63,7 +61,6 @@
import com.android.quickstep.util.SurfaceTransaction.MockProperties;
import com.android.quickstep.util.TransformParams;
-@TargetApi(Build.VERSION_CODES.R)
abstract class SwipeUpGestureTutorialController extends TutorialController {
private static final int FAKE_PREVIOUS_TASK_MARGIN = Utilities.dpToPx(24);
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index cf9fc74..d265918 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -139,7 +139,7 @@
if (IS_VERBOSE) {
Log.d(TAG, String.format("\nwriteSnapshot(%d):\n%s", instanceId.getId(), info));
}
- if (!Utilities.ATLEAST_R || Utilities.isRunningInTestHarness()) {
+ if (Utilities.isRunningInTestHarness()) {
return;
}
SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_SNAPSHOT,
@@ -342,9 +342,6 @@
@Override
public void log(EventEnum event) {
- if (!Utilities.ATLEAST_R) {
- return;
- }
if (DEBUG) {
String name = (event instanceof Enum) ? ((Enum) event).name() :
event.getId() + "";
diff --git a/quickstep/src/com/android/quickstep/util/AnimUtils.java b/quickstep/src/com/android/quickstep/util/AnimUtils.java
index 7fbbb6e..1f2a02c 100644
--- a/quickstep/src/com/android/quickstep/util/AnimUtils.java
+++ b/quickstep/src/com/android/quickstep/util/AnimUtils.java
@@ -16,6 +16,13 @@
package com.android.quickstep.util;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+
+import android.os.Bundle;
+import android.os.IRemoteCallback;
+
+import com.android.launcher3.util.RunnableList;
+
/**
* Utility class containing methods to help manage animations, interpolators, and timings.
*/
@@ -48,4 +55,16 @@
? SplitAnimationTimings.TABLET_APP_PAIR_LAUNCH
: SplitAnimationTimings.PHONE_APP_PAIR_LAUNCH;
}
+
+ /**
+ * Returns a IRemoteCallback which completes the provided list as a result
+ */
+ public static IRemoteCallback completeRunnableListCallback(RunnableList list) {
+ return new IRemoteCallback.Stub() {
+ @Override
+ public void sendResult(Bundle bundle) {
+ MAIN_EXECUTOR.execute(list::executeAllAndDestroy);
+ }
+ };
+ }
}
diff --git a/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
index b663970..1abedb7 100644
--- a/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
@@ -43,6 +43,7 @@
import com.android.quickstep.RecentsAnimationTargets;
import com.android.quickstep.RecentsModel;
import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.TopTaskTracker;
import com.android.quickstep.views.FloatingTaskView;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.recents.model.Task;
@@ -75,7 +76,9 @@
@BinderThread
public void enterStageSplit(boolean leftOrTop) {
- if (!enableSplitContextually()) {
+ if (!enableSplitContextually() ||
+ // Do not enter stage split from keyboard shortcuts if the user is already in split
+ TopTaskTracker.INSTANCE.get(mLauncher).getRunningSplitTaskIds().length == 2) {
return;
}
RecentsAnimationCallbacks callbacks = new RecentsAnimationCallbacks(
diff --git a/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java b/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java
index df5765c..a26d056 100644
--- a/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java
+++ b/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java
@@ -15,8 +15,6 @@
*/
package com.android.quickstep.util;
-import android.annotation.TargetApi;
-import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.view.SurfaceControl;
@@ -34,7 +32,6 @@
* android.view.SyncRtSurfaceTransactionApplier
* with some Launcher specific utility methods
*/
-@TargetApi(Build.VERSION_CODES.R)
public class SurfaceTransactionApplier extends ReleaseCheck {
private static final int MSG_UPDATE_SEQUENCE_NUMBER = 0;
diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
index 57b265b..937a728 100644
--- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
+++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
@@ -21,7 +21,6 @@
import static com.android.launcher3.Utilities.prefixTextWithIcon;
import static com.android.launcher3.util.Executors.THREAD_POOL_EXECUTOR;
-import android.annotation.TargetApi;
import android.app.ActivityOptions;
import android.content.ActivityNotFoundException;
import android.content.Intent;
@@ -33,7 +32,6 @@
import android.icu.text.MeasureFormat.FormatWidth;
import android.icu.util.Measure;
import android.icu.util.MeasureUnit;
-import android.os.Build;
import android.os.UserHandle;
import android.util.Log;
import android.util.Pair;
@@ -61,7 +59,6 @@
import java.time.Duration;
import java.util.Locale;
-@TargetApi(Build.VERSION_CODES.Q)
public final class DigitalWellBeingToast {
private static final float THRESHOLD_LEFT_ICON_ONLY = 0.4f;
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 997624f..6b3484d 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -81,7 +81,6 @@
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
-import android.annotation.TargetApi;
import android.app.WindowConfiguration;
import android.content.Context;
import android.content.Intent;
@@ -98,7 +97,6 @@
import android.graphics.RectF;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
-import android.os.Build;
import android.os.Bundle;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -231,7 +229,6 @@
/**
* A list of recent tasks.
*/
-@TargetApi(Build.VERSION_CODES.R)
public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_TYPE>,
STATE_TYPE extends BaseState<STATE_TYPE>> extends PagedView implements Insettable,
TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback,
diff --git a/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java b/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java
index f39a901..c4b93b7 100644
--- a/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java
+++ b/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java
@@ -120,10 +120,12 @@
private void init() {
TextView cancelTextView = findViewById(R.id.split_instructions_text_cancel);
+ TextView instructionTextView = findViewById(R.id.split_instructions_text);
if (FeatureFlags.enableSplitContextually()) {
cancelTextView.setVisibility(VISIBLE);
cancelTextView.setOnClickListener((v) -> exitSplitSelection());
+ instructionTextView.setText(R.string.toast_contextual_split_select_app);
}
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 66a880b..68710a7 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -57,7 +57,6 @@
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
-import android.os.Handler;
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.util.Log;
@@ -119,8 +118,6 @@
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
-import kotlin.Unit;
-
import java.lang.annotation.Retention;
import java.util.Arrays;
import java.util.Collections;
@@ -129,6 +126,8 @@
import java.util.function.Consumer;
import java.util.stream.Stream;
+import kotlin.Unit;
+
/**
* A task in the Recents view.
*/
@@ -970,20 +969,6 @@
}
/**
- * Returns ActivityOptions for overriding task transition animation.
- */
- private ActivityOptions makeCustomAnimation(Context context, int enterResId,
- int exitResId, final Runnable callback, final Handler callbackHandler) {
- return ActivityOptions.makeCustomTaskAnimation(context, enterResId, exitResId,
- callbackHandler,
- elapsedRealTime -> {
- if (callback != null) {
- callbackHandler.post(callback);
- }
- }, null /* finishedListener */);
- }
-
- /**
* Launch of the current task (both live and inactive tasks) with an animation.
*/
@Nullable
@@ -1034,15 +1019,6 @@
recentsView.getDepthController());
anim.addListener(new AnimatorListenerAdapter() {
@Override
- public void onAnimationStart(Animator animation) {
- recentsView.runActionOnRemoteHandles(
- (Consumer<RemoteTargetHandle>) remoteTargetHandle ->
- remoteTargetHandle
- .getTaskViewSimulator()
- .setDrawsBelowRecents(false));
- }
-
- @Override
public void onAnimationEnd(Animator animator) {
if (mTask != null && mTask.key.displayId != getRootViewDisplayId()) {
launchTaskAnimated();
@@ -1348,10 +1324,8 @@
setPivotX((right - left) * 0.5f);
setPivotY(mSnapshotView.getTop() + mSnapshotView.getHeight() * 0.5f);
}
- if (Utilities.ATLEAST_Q) {
- SYSTEM_GESTURE_EXCLUSION_RECT.get(0).set(0, 0, getWidth(), getHeight());
- setSystemGestureExclusionRects(SYSTEM_GESTURE_EXCLUSION_RECT);
- }
+ SYSTEM_GESTURE_EXCLUSION_RECT.get(0).set(0, 0, getWidth(), getHeight());
+ setSystemGestureExclusionRects(SYSTEM_GESTURE_EXCLUSION_RECT);
}
/**
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt b/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
index 9c7f014..9c7fdc6 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
@@ -27,7 +27,7 @@
class NavButtonLayoutFactoryTest {
private val mockDeviceProfile: DeviceProfile = mock()
- private val mockParentButtonContainer: FrameLayout = mock()
+ private val mockParentButtonContainer: NearestTouchFrame = mock()
private val mockNavLayout: LinearLayout = mock()
private val mockStartContextualLayout: ViewGroup = mock()
private val mockEndContextualLayout: ViewGroup = mock()
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
index a71d74a..df73e09 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
@@ -15,18 +15,14 @@
*/
package com.android.quickstep;
-import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
-import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
import static com.android.quickstep.TaskbarModeSwitchRule.Mode.PERSISTENT;
import android.graphics.Rect;
import androidx.test.filters.LargeTest;
-import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
-import com.android.launcher3.util.rule.TestStabilityRule;
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
@@ -34,9 +30,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.io.Closeable;
-import java.io.IOException;
-
@LargeTest
@RunWith(AndroidJUnit4.class)
public class TaplTestsPersistentTaskbar extends AbstractTaplTestsTaskbar {
@@ -51,27 +44,20 @@
}
@Test
- @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/320490387
@NavigationModeSwitch(mode = NavigationModeSwitchRule.Mode.THREE_BUTTON)
public void testThreeButtonsTaskbarBoundsAfterConfigChangeDuringIme() {
- // Start off in light mode.
- try (Closeable c = InstrumentationRegistry.getInstrumentation().getUiAutomation()
- .executeShellCommand("cmd uimode night no")) {
- Rect taskbarBoundsBefore = getTaskbar().getVisibleBounds();
- startImeTestActivity();
- // IME should stash the taskbar, which hides icons even in 3 button mode.
- mLauncher.getLaunchedAppState().assertTaskbarHidden();
- // Switch to dark mode (any configuration change here would do).
- InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
- "cmd uimode night yes").close();
- // Close IME to check new taskbar bounds.
- mLauncher.pressBack();
- Rect taskbarBoundsAfter = getTaskbar().getVisibleBounds();
- Assert.assertEquals(
- "Taskbar bounds are not the same after a configuration change while stashed.",
- taskbarBoundsBefore, taskbarBoundsAfter);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
+ Rect taskbarBoundsBefore = getTaskbar().getVisibleBounds();
+ // Go home and to an IME activity (any configuration change would do, as long as it
+ // triggers taskbar insets or height change while taskbar is stashed).
+ mLauncher.goHome();
+ startImeTestActivity();
+ // IME should stash the taskbar, which hides icons even in 3 button mode.
+ mLauncher.getLaunchedAppState().assertTaskbarHidden();
+ // Close IME to check new taskbar bounds.
+ startTestActivity(2);
+ Rect taskbarBoundsAfter = getTaskbar().getVisibleBounds();
+ Assert.assertEquals(
+ "Taskbar bounds are not the same after a configuration change while stashed.",
+ taskbarBoundsBefore, taskbarBoundsAfter);
}
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 1b8866a..fcb8320 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;
@@ -334,9 +333,6 @@
@Test
@TaskbarModeSwitch
- @ScreenRecord // b/314873201
- // Staging; will be promoted to presubmit if stable
- @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
public void testQuickSwitchToPreviousAppForTablet() throws Exception {
assumeTrue(mLauncher.isTablet());
startTestActivity(2);
diff --git a/res/drawable/encrypted_24px.xml b/res/drawable/encrypted_24px.xml
deleted file mode 100644
index cf4d2df..0000000
--- a/res/drawable/encrypted_24px.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="960"
- android:viewportHeight="960"
- android:tint="?attr/colorControlNormal">
- <path
- android:fillColor="@android:color/white"
- android:pathData="M420,600L540,600L517,471Q537,461 548.5,442Q560,423 560,400Q560,367 536.5,343.5Q513,320 480,320Q447,320 423.5,343.5Q400,367 400,400Q400,423 411.5,442Q423,461 443,471L420,600ZM480,880Q341,845 250.5,720.5Q160,596 160,444L160,200L480,80L800,200L800,444Q800,596 709.5,720.5Q619,845 480,880ZM480,796Q584,763 652,664Q720,565 720,444L720,255L480,165L240,255L240,444Q240,565 308,664Q376,763 480,796ZM480,480Q480,480 480,480Q480,480 480,480L480,480L480,480L480,480L480,480Q480,480 480,480Q480,480 480,480Z"/>
-</vector>
diff --git a/res/drawable/ic_encrypted_with_background.xml b/res/drawable/ic_encrypted_with_background.xml
new file mode 100644
index 0000000..155e2be
--- /dev/null
+++ b/res/drawable/ic_encrypted_with_background.xml
@@ -0,0 +1,26 @@
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"
+ android:viewportWidth="48"
+ android:viewportHeight="48"
+ android:width="48dp"
+ android:height="48dp">
+ <path
+ android:pathData="M48 24A24 24 0 0 1 0 24A24 24 0 0 1 48 24Z"
+ android:fillColor="?attr/materialColorSurfaceBright" />
+ <path
+ android:pathData="M24.0002 10.667L13.3335 14.667V22.787C13.3335 29.5203 17.8802 35.8003 24.0002 37.3337C30.1202 35.8003 34.6668 29.5203 34.6668 22.787V14.667L24.0002 10.667ZM32.0002 22.787C32.0002 28.1203 28.6002 33.0537 24.0002 34.5603C19.4002 33.0537 16.0002 28.1337 16.0002 22.787V16.5203L24.0002 13.5203L32.0002 16.5203V22.787ZM25.2402 23.6937L26.0002 28.0003H22.0002L22.7602 23.6937C21.9068 23.2537 21.3335 22.3603 21.3335 21.3337C21.3335 19.867 22.5335 18.667 24.0002 18.667C25.4668 18.667 26.6668 19.867 26.6668 21.3337C26.6668 22.3603 26.0935 23.2537 25.2402 23.6937Z"
+ android:fillColor="?attr/materialColorOnSurface" />
+</vector>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 5efe940..b9fb024 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -447,8 +447,10 @@
<string name="remote_action_failed">Failed: <xliff:g id="what" example="Pause">%1$s</xliff:g></string>
<!-- Strings for Private Space -->
- <!-- Private space label -->
+ <!-- Private space tile label -->
<string name="private_space_label">Private space</string>
+ <!-- Private space tile secondary label -->
+ <string name="private_space_secondary_label">Keep private apps locked and hidden</string>
<!-- Title for Private Space Container shown at the bottom of all apps drawer -->
<string name="ps_container_title">Private</string>
<!-- Description for Private Space Settings button -->
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index 79b831e..4a277f0 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -191,14 +191,12 @@
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
- if (Utilities.ATLEAST_Q) {
- for (int i = 0; i < HANDLE_COUNT; i++) {
- View dragHandle = mDragHandles[i];
- mSystemGestureExclusionRects.get(i).set(dragHandle.getLeft(), dragHandle.getTop(),
- dragHandle.getRight(), dragHandle.getBottom());
- }
- setSystemGestureExclusionRects(mSystemGestureExclusionRects);
+ for (int i = 0; i < HANDLE_COUNT; i++) {
+ View dragHandle = mDragHandles[i];
+ mSystemGestureExclusionRects.get(i).set(dragHandle.getLeft(), dragHandle.getTop(),
+ dragHandle.getRight(), dragHandle.getBottom());
}
+ setSystemGestureExclusionRects(mSystemGestureExclusionRects);
}
public static void showForWidget(LauncherAppWidgetHostView widget, CellLayout cellLayout) {
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index b6f6615..1c2ed43 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -20,11 +20,8 @@
import android.content.Context;
import android.content.res.Configuration;
-import android.graphics.Point;
-import android.graphics.Rect;
import android.os.Bundle;
import android.view.ActionMode;
-import android.view.Display;
import android.view.View;
import androidx.annotation.MainThread;
@@ -165,15 +162,7 @@
protected abstract void reapplyUi();
protected WindowBounds getMultiWindowDisplaySize() {
- if (Utilities.ATLEAST_R) {
- return WindowBounds.fromWindowMetrics(getWindowManager().getCurrentWindowMetrics());
- }
- // Note: Calls to getSize() can't rely on our cached DefaultDisplay since it can return
- // the app window size
- Display display = getWindowManager().getDefaultDisplay();
- Point mwSize = new Point();
- display.getSize(mwSize);
- return new WindowBounds(new Rect(0, 0, mwSize.x, mwSize.y), new Rect());
+ return WindowBounds.fromWindowMetrics(getWindowManager().getCurrentWindowMetrics());
}
@Override
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 5a51d8e..1b4edf8 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -16,18 +16,13 @@
package com.android.launcher3;
-import static android.animation.ValueAnimator.areAnimatorsEnabled;
-
-import static com.android.app.animation.Interpolators.DECELERATE_1_5;
import static com.android.launcher3.LauncherState.EDIT_MODE;
import static com.android.launcher3.dragndrop.DraggableView.DRAGGABLE_ICON;
import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR;
-import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_REORDER_BOUNCE_OFFSET;
import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_REORDER_PREVIEW_OFFSET;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
@@ -48,7 +43,6 @@
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.util.Log;
-import android.util.Property;
import android.util.SparseArray;
import android.view.MotionEvent;
import android.view.View;
@@ -71,6 +65,7 @@
import com.android.launcher3.celllayout.ItemConfiguration;
import com.android.launcher3.celllayout.ReorderAlgorithm;
import com.android.launcher3.celllayout.ReorderParameters;
+import com.android.launcher3.celllayout.ReorderPreviewAnimation;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.folder.PreviewBackground;
@@ -189,7 +184,7 @@
@ContainerType private final int mContainerType;
- private final float mChildScale = 1f;
+ public static final float DEFAULT_SCALE = 1f;
public static final int MODE_SHOW_REORDER_HINT = 0;
public static final int MODE_DRAG_OVER = 1;
@@ -199,8 +194,8 @@
private static final boolean DESTRUCTIVE_REORDER = false;
private static final boolean DEBUG_VISUALIZE_OCCUPIED = false;
- private static final float REORDER_PREVIEW_MAGNITUDE = 0.12f;
- private static final int REORDER_ANIMATION_DURATION = 150;
+ public static final float REORDER_PREVIEW_MAGNITUDE = 0.12f;
+ public static final int REORDER_ANIMATION_DURATION = 150;
@Thunk final float mReorderPreviewAnimationMagnitude;
private final ArrayList<View> mIntersectingViews = new ArrayList<>();
@@ -762,8 +757,8 @@
bubbleChild.setTextVisibility(mContainerType != HOTSEAT);
}
- child.setScaleX(mChildScale);
- child.setScaleY(mChildScale);
+ child.setScaleX(DEFAULT_SCALE);
+ child.setScaleY(DEFAULT_SCALE);
// Generate an id for each view, this assumes we have at most 256x256 cells
// per workspace screen
@@ -1439,174 +1434,14 @@
CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams();
if (c != null && !skip && (child instanceof Reorderable)) {
- ReorderPreviewAnimation rha = new ReorderPreviewAnimation(child,
- mode, lp.getCellX(), lp.getCellY(), c.cellX, c.cellY, c.spanX, c.spanY);
+ ReorderPreviewAnimation rha = new ReorderPreviewAnimation(child, mode,
+ lp.getCellX(), lp.getCellY(), c.cellX, c.cellY, c.spanX, c.spanY,
+ mReorderPreviewAnimationMagnitude, this, mShakeAnimators);
rha.animate();
}
}
}
- private static final Property<ReorderPreviewAnimation, Float> ANIMATION_PROGRESS =
- new Property<ReorderPreviewAnimation, Float>(float.class, "animationProgress") {
- @Override
- public Float get(ReorderPreviewAnimation anim) {
- return anim.animationProgress;
- }
-
- @Override
- public void set(ReorderPreviewAnimation anim, Float progress) {
- anim.setAnimationProgress(progress);
- }
- };
-
- // Class which represents the reorder preview animations. These animations show that an item is
- // in a temporary state, and hint at where the item will return to.
- class ReorderPreviewAnimation<T extends View & Reorderable> {
- final T child;
- float finalDeltaX;
- float finalDeltaY;
- float initDeltaX;
- float initDeltaY;
- final float finalScale;
- float initScale;
- final int mode;
- boolean repeating = false;
- private static final int PREVIEW_DURATION = 300;
- private static final int HINT_DURATION = Workspace.REORDER_TIMEOUT;
-
- private static final float CHILD_DIVIDEND = 4.0f;
-
- public static final int MODE_HINT = 0;
- public static final int MODE_PREVIEW = 1;
-
- float animationProgress = 0;
- ValueAnimator a;
-
- ReorderPreviewAnimation(View childView, int mode, int cellX0, int cellY0,
- int cellX1, int cellY1, int spanX, int spanY) {
- regionToCenterPoint(cellX0, cellY0, spanX, spanY, mTmpPoint);
- final int x0 = mTmpPoint[0];
- final int y0 = mTmpPoint[1];
- regionToCenterPoint(cellX1, cellY1, spanX, spanY, mTmpPoint);
- final int x1 = mTmpPoint[0];
- final int y1 = mTmpPoint[1];
- final int dX = x1 - x0;
- final int dY = y1 - y0;
-
- this.child = (T) childView;
- this.mode = mode;
- finalDeltaX = 0;
- finalDeltaY = 0;
-
- MultiTranslateDelegate mtd = child.getTranslateDelegate();
- initDeltaX = mtd.getTranslationX(INDEX_REORDER_BOUNCE_OFFSET).getValue();
- initDeltaY = mtd.getTranslationY(INDEX_REORDER_BOUNCE_OFFSET).getValue();
- initScale = child.getReorderBounceScale();
- finalScale = mChildScale - (CHILD_DIVIDEND / child.getWidth()) * initScale;
-
- int dir = mode == MODE_HINT ? -1 : 1;
- if (dX == dY && dX == 0) {
- } else {
- if (dY == 0) {
- finalDeltaX = -dir * Math.signum(dX) * mReorderPreviewAnimationMagnitude;
- } else if (dX == 0) {
- finalDeltaY = -dir * Math.signum(dY) * mReorderPreviewAnimationMagnitude;
- } else {
- double angle = Math.atan( (float) (dY) / dX);
- finalDeltaX = (int) (-dir * Math.signum(dX)
- * Math.abs(Math.cos(angle) * mReorderPreviewAnimationMagnitude));
- finalDeltaY = (int) (-dir * Math.signum(dY)
- * Math.abs(Math.sin(angle) * mReorderPreviewAnimationMagnitude));
- }
- }
- }
-
- void setInitialAnimationValuesToBaseline() {
- initScale = mChildScale;
- initDeltaX = 0;
- initDeltaY = 0;
- }
-
- void animate() {
- boolean noMovement = (finalDeltaX == 0) && (finalDeltaY == 0);
-
- if (mShakeAnimators.containsKey(child)) {
- ReorderPreviewAnimation oldAnimation = mShakeAnimators.get(child);
- mShakeAnimators.remove(child);
-
- if (noMovement) {
- // A previous animation for this item exists, and no new animation will exist.
- // Finish the old animation smoothly.
- oldAnimation.finishAnimation();
- return;
- } else {
- // A previous animation for this item exists, and a new one will exist. Stop
- // the old animation in its tracks, and proceed with the new one.
- oldAnimation.cancel();
- }
- }
- if (noMovement) {
- return;
- }
-
- ValueAnimator va = ObjectAnimator.ofFloat(this, ANIMATION_PROGRESS, 0, 1);
- a = va;
-
- // Animations are disabled in power save mode, causing the repeated animation to jump
- // spastically between beginning and end states. Since this looks bad, we don't repeat
- // the animation in power save mode.
- if (areAnimatorsEnabled()) {
- va.setRepeatMode(ValueAnimator.REVERSE);
- va.setRepeatCount(ValueAnimator.INFINITE);
- }
-
- va.setDuration(mode == MODE_HINT ? HINT_DURATION : PREVIEW_DURATION);
- va.setStartDelay((int) (Math.random() * 60));
- va.addListener(new AnimatorListenerAdapter() {
- public void onAnimationRepeat(Animator animation) {
- // We make sure to end only after a full period
- setInitialAnimationValuesToBaseline();
- repeating = true;
- }
- });
- mShakeAnimators.put(child, this);
- va.start();
- }
-
- private void setAnimationProgress(float progress) {
- animationProgress = progress;
- float r1 = (mode == MODE_HINT && repeating) ? 1.0f : animationProgress;
- float x = r1 * finalDeltaX + (1 - r1) * initDeltaX;
- float y = r1 * finalDeltaY + (1 - r1) * initDeltaY;
- child.getTranslateDelegate().setTranslation(INDEX_REORDER_BOUNCE_OFFSET, x, y);
- float s = animationProgress * finalScale + (1 - animationProgress) * initScale;
- child.setReorderBounceScale(s);
- }
-
- private void cancel() {
- if (a != null) {
- a.cancel();
- }
- }
-
- /**
- * Smoothly returns the item to its baseline position / scale
- */
- @Thunk void finishAnimation() {
- if (a != null) {
- a.cancel();
- }
-
- setInitialAnimationValuesToBaseline();
- ValueAnimator va = ObjectAnimator.ofFloat(this, ANIMATION_PROGRESS,
- animationProgress, 0);
- a = va;
- a.setInterpolator(DECELERATE_1_5);
- a.setDuration(REORDER_ANIMATION_DURATION);
- a.start();
- }
- }
-
private void completeAndClearReorderPreviewAnimations() {
for (ReorderPreviewAnimation a: mShakeAnimators.values()) {
a.finishAnimation();
diff --git a/src/com/android/launcher3/ExtendedEditText.java b/src/com/android/launcher3/ExtendedEditText.java
index ec26f58..fe9348c 100644
--- a/src/com/android/launcher3/ExtendedEditText.java
+++ b/src/com/android/launcher3/ExtendedEditText.java
@@ -15,8 +15,6 @@
*/
package com.android.launcher3;
-import static com.android.launcher3.logging.KeyboardStateManager.KeyboardState.SHOW;
-
import android.content.Context;
import android.graphics.Rect;
import android.text.TextUtils;
@@ -93,7 +91,6 @@
* @return true if the keyboard is shown correctly and focus is given to this view.
*/
public boolean showKeyboard() {
- onKeyboardShown();
return requestFocus() && showSoftInputInternal();
}
@@ -120,11 +117,6 @@
}
}
- protected void onKeyboardShown() {
- ActivityContext.lookupContext(getContext()).getStatsLogManager()
- .keyboardStateManager().setKeyboardState(SHOW);
- }
-
private boolean showSoftInputInternal() {
boolean result = false;
InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
diff --git a/src/com/android/launcher3/FastScrollRecyclerView.java b/src/com/android/launcher3/FastScrollRecyclerView.java
index a13dcc1..7ec0a89 100644
--- a/src/com/android/launcher3/FastScrollRecyclerView.java
+++ b/src/com/android/launcher3/FastScrollRecyclerView.java
@@ -197,11 +197,11 @@
/**
* Scrolls this recycler view to the bottom with easing and duration.
*/
- public void scrollToBottomWithMotion() {
+ public void scrollToBottomWithMotion(int duration) {
if (mScrollbar != null) {
mScrollbar.reattachThumbToScroll();
}
// Emphasized interpolators with 500ms duration
- smoothScrollBy(0, getAvailableScrollHeight(), Interpolators.EMPHASIZED, 500);
+ smoothScrollBy(0, getAvailableScrollHeight(), Interpolators.EMPHASIZED, duration);
}
}
diff --git a/src/com/android/launcher3/GestureNavContract.java b/src/com/android/launcher3/GestureNavContract.java
index c782dca..9ef6edc 100644
--- a/src/com/android/launcher3/GestureNavContract.java
+++ b/src/com/android/launcher3/GestureNavContract.java
@@ -20,11 +20,9 @@
import static com.android.launcher3.AbstractFloatingView.TYPE_ICON_SURFACE;
-import android.annotation.TargetApi;
import android.content.ComponentName;
import android.content.Intent;
import android.graphics.RectF;
-import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -69,7 +67,6 @@
/**
* Sends the position information to the receiver
*/
- @TargetApi(Build.VERSION_CODES.R)
public void sendEndPosition(RectF position, ActivityContext context,
@Nullable SurfaceControl surfaceControl) {
Bundle result = new Bundle();
@@ -95,9 +92,6 @@
* Clears and returns the GestureNavContract if it was present in the intent.
*/
public static GestureNavContract fromIntent(Intent intent) {
- if (!Utilities.ATLEAST_R) {
- return null;
- }
Bundle extras = intent.getBundleExtra(EXTRA_GESTURE_CONTRACT);
if (extras == null) {
return null;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 39b8de1..44a1bf0 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -19,6 +19,7 @@
import static android.app.PendingIntent.FLAG_IMMUTABLE;
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
import static android.content.pm.ActivityInfo.CONFIG_UI_MODE;
+import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_CONTINUE_ON_SUBTREE;
import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
import static com.android.app.animation.Interpolators.EMPHASIZED;
@@ -54,7 +55,6 @@
import static com.android.launcher3.LauncherConstants.TraceEvents.ON_START_EVT;
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;
@@ -67,6 +67,8 @@
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;
+import static com.android.launcher3.logging.KeyboardStateManager.KeyboardState.HIDE;
+import static com.android.launcher3.logging.KeyboardStateManager.KeyboardState.SHOW;
import static com.android.launcher3.logging.StatsLogManager.EventEnum;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
@@ -139,6 +141,8 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver.OnPreDrawListener;
+import android.view.WindowInsets;
+import android.view.WindowInsetsAnimation;
import android.view.WindowManager.LayoutParams;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.OvershootInterpolator;
@@ -219,6 +223,7 @@
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
+import com.android.launcher3.util.ItemInflater;
import com.android.launcher3.util.KeyboardShortcutsDelegate;
import com.android.launcher3.util.LockedUserState;
import com.android.launcher3.util.PackageUserKey;
@@ -246,8 +251,6 @@
import com.android.launcher3.widget.PendingAddWidgetInfo;
import com.android.launcher3.widget.PendingAppWidgetHostView;
import com.android.launcher3.widget.WidgetAddFlowHandler;
-import com.android.launcher3.widget.WidgetInflater;
-import com.android.launcher3.widget.WidgetInflater.InflationResult;
import com.android.launcher3.widget.WidgetManagerHelper;
import com.android.launcher3.widget.custom.CustomWidgetManager;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
@@ -329,7 +332,7 @@
private WidgetManagerHelper mAppWidgetManager;
private LauncherWidgetHolder mAppWidgetHolder;
- private WidgetInflater mWidgetInflater;
+ private ItemInflater<Launcher> mItemInflater;
private final int[] mTmpAddItemCellCoordinates = new int[2];
@@ -515,10 +518,11 @@
updateDisallowBack();
mAppWidgetManager = new WidgetManagerHelper(this);
- mWidgetInflater = new WidgetInflater(this);
mAppWidgetHolder = createAppWidgetHolder();
mAppWidgetHolder.startListening();
mAppWidgetHolder.addProviderChangeListener(() -> refreshAndBindWidgetsForPackageUser(null));
+ mItemInflater = new ItemInflater<>(this, mAppWidgetHolder, getItemOnClickListener(),
+ mFocusHandler, new CellLayout(mWorkspace.getContext()));
mPopupDataProvider = new PopupDataProvider(this::updateNotificationDots);
@@ -576,9 +580,7 @@
mRotationHelper.initialize();
TraceHelper.INSTANCE.endSection();
- if (Utilities.ATLEAST_R) {
- getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
- }
+ getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
setTitle(R.string.home_screen);
mStartupLatencyLogger.logEnd(LAUNCHER_LATENCY_STARTUP_ACTIVITY_ON_CREATE);
@@ -1084,6 +1086,25 @@
DiscoveryBounce.showForHomeIfNeeded(this);
mAppWidgetHolder.setActivityResumed(true);
+
+ // Listen for IME changes to keep state up to date.
+ getRootView().setWindowInsetsAnimationCallback(
+ new WindowInsetsAnimation.Callback(DISPATCH_MODE_CONTINUE_ON_SUBTREE) {
+ @Override
+ public WindowInsets onProgress(WindowInsets windowInsets,
+ List<WindowInsetsAnimation> windowInsetsAnimations) {
+ return windowInsets;
+ }
+
+ @Override
+ public void onEnd(WindowInsetsAnimation animation) {
+ WindowInsets insets = getRootView().getRootWindowInsets();
+ boolean isImeVisible =
+ insets != null && insets.isVisible(WindowInsets.Type.ime());
+ getStatsLogManager().keyboardStateManager().setKeyboardState(
+ isImeVisible ? SHOW : HIDE);
+ }
+ });
}
private void logStopAndResume(boolean isResume) {
@@ -1354,35 +1375,6 @@
}
/**
- * Creates a view representing a shortcut.
- *
- * @param info The data structure describing the shortcut.
- */
- View createShortcut(WorkspaceItemInfo info) {
- // This can be called before PagedView#pageScrollsInitialized returns true, so use the
- // first page, which we always assume to be present.
- return createShortcut((ViewGroup) mWorkspace.getChildAt(0), info);
- }
-
- /**
- * Creates a view representing a shortcut inflated from the specified resource.
- *
- * @param parent The group the shortcut belongs to. This is not necessarily the group where
- * the shortcut should be added.
- * @param info The data structure describing the shortcut.
- * @return A View inflated from layoutResId.
- */
- public View createShortcut(@Nullable ViewGroup parent, WorkspaceItemInfo info) {
- BubbleTextView favorite =
- (BubbleTextView) LayoutInflater.from(parent != null ? parent.getContext() : this)
- .inflate(R.layout.app_icon, parent, false);
- favorite.applyFromWorkspaceItem(info);
- favorite.setOnClickListener(getItemOnClickListener());
- favorite.setOnFocusChangeListener(mFocusHandler);
- return favorite;
- }
-
- /**
* Add a shortcut to the workspace or to a Folder.
*
* @param data The intent describing the shortcut.
@@ -1405,7 +1397,7 @@
if (container < 0) {
// Adding a shortcut to the Workspace.
- final View view = createShortcut(info);
+ final View view = mItemInflater.inflateItem(info, getModelWriter());
boolean foundCellSpan = false;
// First we check if we already know the exact location where we want to add this item.
if (cellX >= 0 && cellY >= 0) {
@@ -1491,7 +1483,7 @@
itemInfo.container, presenterPos.screenId, presenterPos.cellX, presenterPos.cellY);
hostView.setVisibility(View.VISIBLE);
- prepareAppWidget(hostView, launcherInfo);
+ mItemInflater.prepareAppWidget(hostView, launcherInfo);
mWorkspace.addInScreen(hostView, launcherInfo);
announceForAccessibility(R.string.item_added_to_workspace);
@@ -1516,12 +1508,6 @@
}
}
- private void prepareAppWidget(AppWidgetHostView hostView, LauncherAppWidgetInfo item) {
- hostView.setTag(item);
- hostView.setFocusable(true);
- hostView.setOnFocusChangeListener(mFocusHandler);
- }
-
private final ScreenOnListener mScreenOnListener = this::onScreenOnChanged;
private void updateNotificationDots(Predicate<PackageUserKey> updatedDots) {
@@ -2157,63 +2143,19 @@
final boolean focusFirstItemForAccessibility) {
// Get the list of added items and intersect them with the set of items here
final Collection<Animator> bounceAnims = new ArrayList<>();
- boolean canAnimatePageChange = canAnimatePageChange();
Workspace<?> workspace = mWorkspace;
int newItemsScreenId = -1;
int end = items.size();
View newView = null;
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) {
- continue;
- }
- final View view;
- switch (item.itemType) {
- case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
- case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT: {
- WorkspaceItemInfo info = (WorkspaceItemInfo) item;
- view = createShortcut(info);
- break;
- }
- case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: {
- view = FolderIcon.inflateFolderAndIcon(R.layout.folder_icon, this,
- (ViewGroup) workspace.getChildAt(workspace.getCurrentPage()),
- (FolderInfo) item);
- break;
- }
- case LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR: {
- view = AppPairIcon.inflateIcon(R.layout.app_pair_icon, this,
- (ViewGroup) workspace.getChildAt(workspace.getCurrentPage()),
- (FolderInfo) item);
- break;
- }
- case ITEM_TYPE_APPWIDGET:
- case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET: {
- view = inflateAppWidget((LauncherAppWidgetInfo) item);
- if (view == null) {
- continue;
- }
- break;
- }
- default:
- throw new RuntimeException("Invalid Item Type");
- }
-
- /*
- * Remove colliding items.
- */
+ // Remove colliding items.
CellPos presenterPos = getCellPosMapper().mapModelToPresenter(item);
if (item.container == CONTAINER_DESKTOP) {
CellLayout cl = mWorkspace.getScreenWithId(presenterPos.screenId);
if (cl != null && cl.isOccupied(presenterPos.cellX, presenterPos.cellY)) {
- View v = cl.getChildAt(presenterPos.cellX, presenterPos.cellY);
- if (v == null) {
- Log.e(TAG, "bindItems failed when removing colliding item=" + item);
- }
- Object tag = v.getTag();
+ Object tag = cl.getChildAt(presenterPos.cellX, presenterPos.cellY).getTag();
String desc = "Collision while binding workspace item: " + item
+ ". Collides with " + tag;
if (FeatureFlags.IS_STUDIO_BUILD) {
@@ -2224,6 +2166,11 @@
}
}
}
+
+ final View view = mItemInflater.inflateItem(item, getModelWriter());
+ if (view == null) {
+ continue;
+ }
workspace.addInScreenFromBind(view, item);
if (forceAnimateIcons) {
// Animate all the applications up now
@@ -2240,7 +2187,7 @@
}
View viewToFocus = newView;
- // Animate to the correct pager
+ // Animate to the correct page
if (forceAnimateIcons && newItemsScreenId > -1) {
AnimatorSet anim = new AnimatorSet();
anim.playTogether(bounceAnims);
@@ -2257,19 +2204,13 @@
final int newScreenIndex = mWorkspace.getPageIndexForScreenId(newItemsScreenId);
final Runnable startBounceAnimRunnable = anim::start;
- if (canAnimatePageChange && newItemsScreenId != currentScreenId) {
+ if (canAnimatePageChange() && newItemsScreenId != currentScreenId) {
// We post the animation slightly delayed to prevent slowdowns
// when we are loading right after we return to launcher.
- mWorkspace.postDelayed(new Runnable() {
- public void run() {
- if (mWorkspace != null) {
- closeOpenViews(false);
-
- mWorkspace.snapToPage(newScreenIndex);
- mWorkspace.postDelayed(startBounceAnimRunnable,
- NEW_APPS_ANIMATION_DELAY);
- }
- }
+ mWorkspace.postDelayed(() -> {
+ closeOpenViews(false);
+ mWorkspace.snapToPage(newScreenIndex);
+ mWorkspace.postDelayed(startBounceAnimRunnable, NEW_APPS_ANIMATION_DELAY);
}, NEW_APPS_PAGE_MOVE_DELAY);
} else {
mWorkspace.postDelayed(startBounceAnimRunnable, NEW_APPS_ANIMATION_DELAY);
@@ -2284,36 +2225,13 @@
* Add the views for a widget to the workspace.
*/
public void bindAppWidget(LauncherAppWidgetInfo item) {
- View view = inflateAppWidget(item);
+ View view = mItemInflater.inflateItem(item, getModelWriter());
if (view != null) {
mWorkspace.addInScreen(view, item);
mWorkspace.requestLayout();
}
}
- private View inflateAppWidget(LauncherAppWidgetInfo item) {
- TraceHelper.INSTANCE.beginSection("BIND_WIDGET_id=" + item.appWidgetId);
- try {
- InflationResult inflationResult = mWidgetInflater.inflateAppWidget(item);
- if (inflationResult.getType() == WidgetInflater.TYPE_DELETE) {
- getModelWriter().deleteItemFromDatabase(item, inflationResult.getReason());
- return null;
- }
-
- if (inflationResult.isUpdate()) {
- getModelWriter().updateItemInDatabase(item);
- }
- AppWidgetHostView view = inflationResult.getType() == WidgetInflater.TYPE_PENDING
- ? new PendingAppWidgetHostView(this, item, inflationResult.getWidgetInfo())
- : mAppWidgetHolder.createView(
- item.appWidgetId, inflationResult.getWidgetInfo());
- prepareAppWidget(view, item);
- return view;
- } finally {
- TraceHelper.INSTANCE.endSection();
- }
- }
-
/**
* Restores a pending widget.
*
@@ -2760,7 +2678,7 @@
}
LauncherRootView rv = getRootView();
if (rv != null) {
- boolean isSplitSelectionEnabled = isSplitSelectionEnabled();
+ boolean isSplitSelectionEnabled = isSplitSelectionActive();
boolean disableBack = getStateManager().getState() == NORMAL
&& AbstractFloatingView.getTopOpenView(this) == null
&& !isSplitSelectionEnabled;
@@ -2769,7 +2687,7 @@
}
/** To be overridden by subclasses */
- public boolean isSplitSelectionEnabled() {
+ public boolean isSplitSelectionActive() {
// Overridden
return false;
}
@@ -3096,6 +3014,10 @@
return super.getStatsLogManager().withDefaultInstanceId(mAllAppsSessionLogId);
}
+ public ItemInflater<Launcher> getItemInflater() {
+ return mItemInflater;
+ }
+
/**
* Returns the current popup for testing, if any.
*/
diff --git a/src/com/android/launcher3/LauncherRootView.java b/src/com/android/launcher3/LauncherRootView.java
index 1592154..7176733 100644
--- a/src/com/android/launcher3/LauncherRootView.java
+++ b/src/com/android/launcher3/LauncherRootView.java
@@ -2,11 +2,9 @@
import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVITY;
-import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
-import android.os.Build;
import android.util.AttributeSet;
import android.view.ViewDebug;
import android.view.WindowInsets;
@@ -112,15 +110,13 @@
mSysUiScrim.setSize(r - l, b - t);
}
- @TargetApi(Build.VERSION_CODES.Q)
public void setForceHideBackArrow(boolean forceHideBackArrow) {
this.mForceHideBackArrow = forceHideBackArrow;
setDisallowBackGesture(mDisallowBackGesture);
}
- @TargetApi(Build.VERSION_CODES.Q)
public void setDisallowBackGesture(boolean disallowBackGesture) {
- if (!Utilities.ATLEAST_Q || SEPARATE_RECENTS_ACTIVITY.get()) {
+ if (SEPARATE_RECENTS_ACTIVITY.get()) {
return;
}
mDisallowBackGesture = disallowBackGesture;
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index e0f6101..2b886e4 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -121,15 +121,6 @@
public static final String[] EMPTY_STRING_ARRAY = new String[0];
public static final Person[] EMPTY_PERSON_ARRAY = new Person[0];
- @ChecksSdkIntAtLeast(api = VERSION_CODES.P)
- public static final boolean ATLEAST_P = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;
-
- @ChecksSdkIntAtLeast(api = VERSION_CODES.Q)
- public static final boolean ATLEAST_Q = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q;
-
- @ChecksSdkIntAtLeast(api = VERSION_CODES.R)
- public static final boolean ATLEAST_R = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R;
-
@ChecksSdkIntAtLeast(api = VERSION_CODES.S)
public static final boolean ATLEAST_S = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index be4168d..2eff8aa 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -73,7 +73,6 @@
import com.android.launcher3.accessibility.AccessibleDragListenerAdapter;
import com.android.launcher3.accessibility.WorkspaceAccessibilityHelper;
import com.android.launcher3.anim.PendingAnimation;
-import com.android.launcher3.apppairs.AppPairIcon;
import com.android.launcher3.celllayout.CellInfo;
import com.android.launcher3.celllayout.CellLayoutLayoutParams;
import com.android.launcher3.celllayout.CellPosMapper;
@@ -99,7 +98,6 @@
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
-import com.android.launcher3.model.data.WorkspaceItemFactory;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pageindicators.PageIndicator;
import com.android.launcher3.statemanager.StateManager;
@@ -2339,10 +2337,6 @@
}
}
- public CellLayout getCurrentDragOverlappingLayout() {
- return mDragOverlappingLayout;
- }
-
void setCurrentDropOverCell(int x, int y) {
if (x != mDragOverX || y != mDragOverY) {
mDragOverX = x;
@@ -2854,36 +2848,9 @@
} else {
// This is for other drag/drop cases, like dragging from All Apps
mLauncher.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
- View view;
-
- switch (info.itemType) {
- case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
- case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
- case LauncherSettings.Favorites.ITEM_TYPE_SEARCH_ACTION:
- if (info instanceof WorkspaceItemFactory) {
- // Came from all apps -- make a copy
- info = ((WorkspaceItemFactory) info).makeWorkspaceItem(mLauncher);
- d.dragInfo = info;
- }
- if (info instanceof WorkspaceItemInfo
- && info.container == LauncherSettings.Favorites.CONTAINER_PREDICTION) {
- // Came from all apps prediction row -- make a copy
- info = new WorkspaceItemInfo((WorkspaceItemInfo) info);
- d.dragInfo = info;
- }
- view = mLauncher.createShortcut(cellLayout, (WorkspaceItemInfo) info);
- break;
- case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
- view = FolderIcon.inflateFolderAndIcon(R.layout.folder_icon, mLauncher, cellLayout,
- (FolderInfo) info);
- break;
- case LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR:
- view = AppPairIcon.inflateIcon(R.layout.app_pair_icon, mLauncher, cellLayout,
- (FolderInfo) info);
- break;
- default:
- throw new IllegalStateException("Unknown item type: " + info.itemType);
- }
+ View view = mLauncher.getItemInflater()
+ .inflateItem(info, mLauncher.getModelWriter(), cellLayout);
+ d.dragInfo = info = (ItemInfo) view.getTag();
// First we find the cell nearest to point at which the item is
// dropped, without any consideration to whether there is an item there.
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index ac5b528..0844275 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -32,6 +32,7 @@
import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.keyboard.KeyboardDragAndDropView;
+import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -126,7 +127,8 @@
}
private boolean supportAddToWorkSpace(ItemInfo item) {
- return (item instanceof WorkspaceItemFactory)
+ return ((item instanceof AppInfo)
+ && (((AppInfo) item).runtimeStatusFlags & FLAG_NOT_PINNABLE) == 0)
|| ((item instanceof WorkspaceItemInfo)
&& (((WorkspaceItemInfo) item).runtimeStatusFlags & FLAG_NOT_PINNABLE) == 0)
|| ((item instanceof PendingAddItemInfo)
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index 55438fe..930196d 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -126,6 +126,7 @@
public static final float PULL_MULTIPLIER = .02f;
public static final float FLING_VELOCITY_MULTIPLIER = 1200f;
protected static final String BUNDLE_KEY_CURRENT_PAGE = "launcher.allapps.current_page";
+ private static final int SCROLL_TO_BOTTOM_DURATION = 500;
private static final long DEFAULT_SEARCH_TRANSITION_DURATION_MS = 300;
// Render the header protection at all times to debug clipping issues.
private static final boolean DEBUG_HEADER_PROTECTION = false;
@@ -515,7 +516,7 @@
// Switch to the main tab
switchToTab(ActivityAllAppsContainerView.AdapterHolder.MAIN);
// Scroll to bottom
- getActiveRecyclerView().scrollToBottomWithMotion();
+ getActiveRecyclerView().scrollToBottomWithMotion(SCROLL_TO_BOTTOM_DURATION);
});
}
diff --git a/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
index 5e48177..63a168e 100644
--- a/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
@@ -21,7 +21,6 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.Utilities;
import com.android.launcher3.statemanager.StateManager;
/**
@@ -43,11 +42,7 @@
@Override
protected int computeNavBarScrimHeight(WindowInsets insets) {
- if (Utilities.ATLEAST_Q) {
- return insets.getTappableElementInsets().bottom;
- } else {
- return insets.getStableInsetBottom();
- }
+ return insets.getTappableElementInsets().bottom;
}
@Override
diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java
index e3c56d3..557ec48 100644
--- a/src/com/android/launcher3/allapps/PrivateProfileManager.java
+++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java
@@ -22,6 +22,7 @@
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_SYS_APPS_DIVIDER;
import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_NOTHING;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED;
+import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_PRIVATE_SPACE_INSTALL_APP;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.SettingsCache.PRIVATE_SPACE_HIDE_WHEN_LOCKED_URI;
@@ -108,6 +109,7 @@
itemInfo.bitmap = bitmapInfo;
itemInfo.contentDescription = context.getResources().getString(
com.android.launcher3.R.string.ps_add_button_content_description);
+ itemInfo.runtimeStatusFlags |= FLAG_PRIVATE_SPACE_INSTALL_APP;
BaseAllAppsAdapter.AdapterItem item = new BaseAllAppsAdapter.AdapterItem(VIEW_TYPE_ICON);
item.itemInfo = itemInfo;
diff --git a/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewController.java b/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewController.java
index bc3269d..bc55597 100644
--- a/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewController.java
+++ b/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewController.java
@@ -120,11 +120,7 @@
(ActivityAllAppsContainerView<?>.AdapterHolder) mAllApps.mAH.get(MAIN);
if (Flags.enablePrivateSpace() && Flags.privateSpaceAnimation()
&& mAllApps.getActiveRecyclerView() == mainAdapterHolder.mRecyclerView) {
- RecyclerViewAnimationController recyclerViewAnimationController =
- new RecyclerViewAnimationController(mAllApps);
- recyclerViewAnimationController.animateToState(true /* expand */,
- ANIMATION_DURATION, () -> {});
- mAllApps.getActiveRecyclerView().scrollToBottomWithMotion();
+ mAllApps.getActiveRecyclerView().scrollToBottomWithMotion(ANIMATION_DURATION);
}
}
diff --git a/src/com/android/launcher3/allapps/UserProfileManager.java b/src/com/android/launcher3/allapps/UserProfileManager.java
index 8894f45..6a1f37a 100644
--- a/src/com/android/launcher3/allapps/UserProfileManager.java
+++ b/src/com/android/launcher3/allapps/UserProfileManager.java
@@ -23,7 +23,6 @@
import androidx.annotation.IntDef;
-import com.android.launcher3.Utilities;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.pm.UserCache;
@@ -70,16 +69,13 @@
/** Sets quiet mode as enabled/disabled for the profile type. */
protected void setQuietMode(boolean enabled) {
- if (Utilities.ATLEAST_P) {
- UI_HELPER_EXECUTOR.post(() -> {
+ UI_HELPER_EXECUTOR.post(() ->
mUserCache.getUserProfiles()
.stream()
.filter(getUserMatcher())
.findFirst()
.ifPresent(userHandle ->
- mUserManager.requestQuietModeEnabled(enabled, userHandle));
- });
- }
+ mUserManager.requestQuietModeEnabled(enabled, userHandle)));
}
/** Sets current state for the profile type. */
diff --git a/src/com/android/launcher3/allapps/WorkModeSwitch.java b/src/com/android/launcher3/allapps/WorkModeSwitch.java
index 48400b2..eb7d429 100644
--- a/src/com/android/launcher3/allapps/WorkModeSwitch.java
+++ b/src/com/android/launcher3/allapps/WorkModeSwitch.java
@@ -83,11 +83,9 @@
mIcon = findViewById(R.id.work_icon);
mTextView = findViewById(R.id.pause_text);
setSelected(true);
- if (Utilities.ATLEAST_R) {
- KeyboardInsetAnimationCallback keyboardInsetAnimationCallback =
- new KeyboardInsetAnimationCallback(this);
- setWindowInsetsAnimationCallback(keyboardInsetAnimationCallback);
- }
+ KeyboardInsetAnimationCallback keyboardInsetAnimationCallback =
+ new KeyboardInsetAnimationCallback(this);
+ setWindowInsetsAnimationCallback(keyboardInsetAnimationCallback);
setInsets(mActivityContext.getDeviceProfile().getInsets());
updateStringFromCache();
diff --git a/src/com/android/launcher3/allapps/WorkPausedCard.java b/src/com/android/launcher3/allapps/WorkPausedCard.java
index 1882667..e1eeabe 100644
--- a/src/com/android/launcher3/allapps/WorkPausedCard.java
+++ b/src/com/android/launcher3/allapps/WorkPausedCard.java
@@ -26,7 +26,6 @@
import android.widget.TextView;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import com.android.launcher3.model.StringCache;
import com.android.launcher3.views.ActivityContext;
@@ -80,11 +79,9 @@
@Override
public void onClick(View view) {
- if (Utilities.ATLEAST_P) {
- setEnabled(false);
- mActivityContext.getAppsView().getWorkManager().setWorkProfileEnabled(true);
- mActivityContext.getStatsLogManager().logger().log(LAUNCHER_TURN_ON_WORK_APPS_TAP);
- }
+ setEnabled(false);
+ mActivityContext.getAppsView().getWorkManager().setWorkProfileEnabled(true);
+ mActivityContext.getStatsLogManager().logger().log(LAUNCHER_TURN_ON_WORK_APPS_TAP);
}
@Override
diff --git a/src/com/android/launcher3/allapps/WorkProfileManager.java b/src/com/android/launcher3/allapps/WorkProfileManager.java
index c430a36..a54e52c 100644
--- a/src/com/android/launcher3/allapps/WorkProfileManager.java
+++ b/src/com/android/launcher3/allapps/WorkProfileManager.java
@@ -199,8 +199,7 @@
}
private void onWorkFabClicked(View view) {
- if (Utilities.ATLEAST_P && getCurrentState() == STATE_ENABLED
- && mWorkModeSwitch.isEnabled()) {
+ if (getCurrentState() == STATE_ENABLED && mWorkModeSwitch.isEnabled()) {
logEvents(LAUNCHER_TURN_OFF_WORK_APPS_TAP);
setWorkProfileEnabled(false);
}
diff --git a/src/com/android/launcher3/anim/PendingAnimation.java b/src/com/android/launcher3/anim/PendingAnimation.java
index fd731f4..586beb2 100644
--- a/src/com/android/launcher3/anim/PendingAnimation.java
+++ b/src/com/android/launcher3/anim/PendingAnimation.java
@@ -25,7 +25,6 @@
import android.os.Trace;
import android.util.FloatProperty;
-import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorPlaybackController.Holder;
import java.util.ArrayList;
@@ -86,7 +85,7 @@
/** If trace is enabled, add counter to trace animation progress. */
public void logAnimationProgressToTrace(String counterName) {
- if (Utilities.ATLEAST_Q && Trace.isEnabled()) {
+ if (Trace.isEnabled()) {
super.addOnFrameListener(
animation -> Trace.setCounter(
counterName, (long) (animation.getAnimatedFraction() * 100)));
diff --git a/src/com/android/launcher3/celllayout/ReorderPreviewAnimation.kt b/src/com/android/launcher3/celllayout/ReorderPreviewAnimation.kt
new file mode 100644
index 0000000..62b19d4
--- /dev/null
+++ b/src/com/android/launcher3/celllayout/ReorderPreviewAnimation.kt
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.celllayout
+
+import android.animation.ObjectAnimator
+import android.animation.ValueAnimator
+import android.animation.ValueAnimator.areAnimatorsEnabled
+import android.util.ArrayMap
+import android.view.View
+import com.android.app.animation.Interpolators.DECELERATE_1_5
+import com.android.launcher3.CellLayout
+import com.android.launcher3.CellLayout.REORDER_ANIMATION_DURATION
+import com.android.launcher3.Reorderable
+import com.android.launcher3.Workspace
+import com.android.launcher3.util.MultiTranslateDelegate.INDEX_REORDER_BOUNCE_OFFSET
+import com.android.launcher3.util.Thunk
+import kotlin.math.abs
+import kotlin.math.atan
+import kotlin.math.cos
+import kotlin.math.sign
+import kotlin.math.sin
+
+/**
+ * Class which represents the reorder preview animations. These animations show that an item is in a
+ * temporary state, and hint at where the item will return to.
+ */
+class ReorderPreviewAnimation<T>(
+ val child: T,
+ // If the mode is MODE_HINT it will only move one period and stop, it then will be going
+ // backwards to the initial position, otherwise it will oscillate.
+ val mode: Int,
+ cellX0: Int,
+ cellY0: Int,
+ cellX1: Int,
+ cellY1: Int,
+ spanX: Int,
+ spanY: Int,
+ reorderMagnitude: Float,
+ cellLayout: CellLayout,
+ private val shakeAnimators: ArrayMap<Reorderable, ReorderPreviewAnimation<T>>
+) : ValueAnimator.AnimatorUpdateListener where T : View, T : Reorderable {
+
+ private var finalDeltaX = 0f
+ private var finalDeltaY = 0f
+ private var initDeltaX =
+ child.getTranslateDelegate().getTranslationX(INDEX_REORDER_BOUNCE_OFFSET).value
+ private var initDeltaY =
+ child.getTranslateDelegate().getTranslationY(INDEX_REORDER_BOUNCE_OFFSET).value
+ private var initScale = child.getReorderBounceScale()
+ private val finalScale = CellLayout.DEFAULT_SCALE - CHILD_DIVIDEND / child.width * initScale
+
+ private val dir = if (mode == MODE_HINT) -1 else 1
+ var animator: ValueAnimator =
+ ObjectAnimator.ofFloat(0f, 1f).also {
+ it.addUpdateListener(this)
+ it.setDuration((if (mode == MODE_HINT) HINT_DURATION else PREVIEW_DURATION).toLong())
+ it.startDelay = (Math.random() * 60).toLong()
+ // Animations are disabled in power save mode, causing the repeated animation to jump
+ // spastically between beginning and end states. Since this looks bad, we don't repeat
+ // the animation in power save mode.
+ if (areAnimatorsEnabled() && mode == MODE_PREVIEW) {
+ it.repeatCount = ValueAnimator.INFINITE
+ it.repeatMode = ValueAnimator.REVERSE
+ }
+ }
+
+ init {
+ val tmpRes = intArrayOf(0, 0)
+ cellLayout.regionToCenterPoint(cellX0, cellY0, spanX, spanY, tmpRes)
+ val (x0, y0) = tmpRes
+ cellLayout.regionToCenterPoint(cellX1, cellY1, spanX, spanY, tmpRes)
+ val (x1, y1) = tmpRes
+ val dX = x1 - x0
+ val dY = y1 - y0
+
+ if (dX != 0 || dY != 0) {
+ if (dY == 0) {
+ finalDeltaX = -dir * sign(dX.toFloat()) * reorderMagnitude
+ } else if (dX == 0) {
+ finalDeltaY = -dir * sign(dY.toFloat()) * reorderMagnitude
+ } else {
+ val angle = atan((dY.toFloat() / dX))
+ finalDeltaX = (-dir * sign(dX.toFloat()) * abs(cos(angle) * reorderMagnitude))
+ finalDeltaY = (-dir * sign(dY.toFloat()) * abs(sin(angle) * reorderMagnitude))
+ }
+ }
+ }
+
+ private fun setInitialAnimationValuesToBaseline() {
+ initScale = CellLayout.DEFAULT_SCALE
+ initDeltaX = 0f
+ initDeltaY = 0f
+ }
+
+ fun animate() {
+ val noMovement = finalDeltaX == 0f && finalDeltaY == 0f
+ if (shakeAnimators.containsKey(child)) {
+ val oldAnimation: ReorderPreviewAnimation<T>? = shakeAnimators.remove(child)
+ if (noMovement) {
+ // A previous animation for this item exists, and no new animation will exist.
+ // Finish the old animation smoothly.
+ oldAnimation!!.finishAnimation()
+ return
+ } else {
+ // A previous animation for this item exists, and a new one will exist. Stop
+ // the old animation in its tracks, and proceed with the new one.
+ oldAnimation!!.cancel()
+ }
+ }
+ if (noMovement) {
+ return
+ }
+ shakeAnimators[child] = this
+ animator.start()
+ }
+
+ override fun onAnimationUpdate(updatedAnimation: ValueAnimator) {
+ val progress = updatedAnimation.animatedValue as Float
+ child
+ .getTranslateDelegate()
+ .setTranslation(
+ INDEX_REORDER_BOUNCE_OFFSET,
+ /* x = */ progress * finalDeltaX + (1 - progress) * initDeltaX,
+ /* y = */ progress * finalDeltaY + (1 - progress) * initDeltaY
+ )
+ child.setReorderBounceScale(progress * finalScale + (1 - progress) * initScale)
+ }
+
+ private fun cancel() {
+ animator.cancel()
+ }
+
+ /** Smoothly returns the item to its baseline position / scale */
+ @Thunk
+ fun finishAnimation() {
+ animator.cancel()
+ setInitialAnimationValuesToBaseline()
+ animator = ObjectAnimator.ofFloat((animator.animatedValue as Float), 0f)
+ animator.addUpdateListener(this)
+ animator.interpolator = DECELERATE_1_5
+ animator.setDuration(REORDER_ANIMATION_DURATION.toLong())
+ animator.start()
+ }
+
+ companion object {
+ const val PREVIEW_DURATION = 300
+ const val HINT_DURATION = Workspace.REORDER_TIMEOUT
+ private const val CHILD_DIVIDEND = 4.0f
+ const val MODE_HINT = 0
+ const val MODE_PREVIEW = 1
+ }
+}
diff --git a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
index d37b1f0..5f786a4 100644
--- a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
+++ b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
@@ -110,9 +110,6 @@
}
public static int getRecommendedTimeoutMillis(Context context, int originalTimeout, int flags) {
- if (Utilities.ATLEAST_Q) {
- return getManager(context).getRecommendedTimeoutMillis(originalTimeout, flags);
- }
- return originalTimeout;
+ return getManager(context).getRecommendedTimeoutMillis(originalTimeout, flags);
}
}
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index aa5329b..3ccde0a 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -16,8 +16,6 @@
package com.android.launcher3.dragndrop;
-import static com.android.launcher3.Utilities.ATLEAST_Q;
-
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@@ -404,9 +402,7 @@
mMotionDown.set(dragLayerPos.x, dragLayerPos.y);
}
- if (ATLEAST_Q) {
- mLastTouchClassification = ev.getClassification();
- }
+ mLastTouchClassification = ev.getClassification();
return mDragDriver != null && mDragDriver.onInterceptTouchEvent(ev);
}
@@ -441,7 +437,7 @@
mLastTouch.set(x, y);
int distanceDragged = mDistanceSinceScroll;
- if (ATLEAST_Q && mLastTouchClassification == MotionEvent.CLASSIFICATION_DEEP_PRESS) {
+ if (mLastTouchClassification == MotionEvent.CLASSIFICATION_DEEP_PRESS) {
distanceDragged /= DEEP_PRESS_DISTANCE_FACTOR;
}
if (mIsInPreDrag && mOptions.preDragCondition != null
diff --git a/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java b/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
index 6f295e6..6a43b24 100644
--- a/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
+++ b/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
@@ -37,7 +37,6 @@
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
-import com.android.launcher3.Utilities;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.folder.PreviewBackground;
import com.android.launcher3.icons.BitmapRenderer;
@@ -74,13 +73,9 @@
return mBadge;
}
- @TargetApi(Build.VERSION_CODES.P)
public static @Nullable FolderAdaptiveIcon createFolderAdaptiveIcon(
ActivityContext activity, int folderId, Point size) {
Preconditions.assertNonUiThread();
- if (!Utilities.ATLEAST_P) {
- return null;
- }
// assume square
if (size.x != size.y) {
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 084f829..7ae70e0 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -297,10 +297,8 @@
mFooter = findViewById(R.id.folder_footer);
mFooterHeight = dp.folderFooterHeightPx;
- if (Utilities.ATLEAST_R) {
- mKeyboardInsetAnimationCallback = new KeyboardInsetAnimationCallback(this);
- setWindowInsetsAnimationCallback(mKeyboardInsetAnimationCallback);
- }
+ mKeyboardInsetAnimationCallback = new KeyboardInsetAnimationCallback(this);
+ setWindowInsetsAnimationCallback(mKeyboardInsetAnimationCallback);
}
public boolean onLongClick(View v) {
@@ -422,18 +420,16 @@
@Override
public WindowInsets onApplyWindowInsets(WindowInsets windowInsets) {
- if (Utilities.ATLEAST_R) {
- this.setTranslationY(0);
+ this.setTranslationY(0);
- if (windowInsets.isVisible(WindowInsets.Type.ime())) {
- Insets keyboardInsets = windowInsets.getInsets(WindowInsets.Type.ime());
- int folderHeightFromBottom = getHeightFromBottom();
+ if (windowInsets.isVisible(WindowInsets.Type.ime())) {
+ Insets keyboardInsets = windowInsets.getInsets(WindowInsets.Type.ime());
+ int folderHeightFromBottom = getHeightFromBottom();
- if (keyboardInsets.bottom > folderHeightFromBottom) {
- // Translate this folder above the keyboard, then add the folder name's padding
- this.setTranslationY(folderHeightFromBottom - keyboardInsets.bottom
- - mFolderName.getPaddingBottom());
- }
+ if (keyboardInsets.bottom > folderHeightFromBottom) {
+ // Translate this folder above the keyboard, then add the folder name's padding
+ this.setTranslationY(folderHeightFromBottom - keyboardInsets.bottom
+ - mFolderName.getPaddingBottom());
}
}
@@ -812,15 +808,13 @@
a.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
- if (Utilities.ATLEAST_R) {
- setWindowInsetsAnimationCallback(null);
- }
+ setWindowInsetsAnimationCallback(null);
mIsAnimatingClosed = true;
}
@Override
public void onAnimationEnd(Animator animation) {
- if (Utilities.ATLEAST_R && mKeyboardInsetAnimationCallback != null) {
+ if (mKeyboardInsetAnimationCallback != null) {
setWindowInsetsAnimationCallback(mKeyboardInsetAnimationCallback);
}
closeComplete(true);
diff --git a/src/com/android/launcher3/folder/LauncherDelegate.java b/src/com/android/launcher3/folder/LauncherDelegate.java
index 66c9109..78298b3 100644
--- a/src/com/android/launcher3/folder/LauncherDelegate.java
+++ b/src/com/android/launcher3/folder/LauncherDelegate.java
@@ -94,7 +94,8 @@
CellLayout cellLayout = mLauncher.getCellLayout(info.container,
mLauncher.getCellPosMapper().mapModelToPresenter(info).screenId);
finalItem = info.contents.remove(0);
- newIcon = mLauncher.createShortcut(cellLayout, finalItem);
+ newIcon = mLauncher.getItemInflater().inflateItem(
+ finalItem, mLauncher.getModelWriter(), cellLayout);
mLauncher.getModelWriter().addOrMoveItemInDatabase(finalItem,
info.container, info.screenId, info.cellX, info.cellY);
}
diff --git a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
index 18200f6..dc8694d 100644
--- a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
+++ b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
@@ -19,7 +19,6 @@
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.Themes.isThemedIconEnabled;
-import android.annotation.TargetApi;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.pm.PackageManager;
@@ -27,7 +26,6 @@
import android.database.MatrixCursor;
import android.net.Uri;
import android.os.Binder;
-import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -41,7 +39,6 @@
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.InvariantDeviceProfile.GridOption;
import com.android.launcher3.LauncherPrefs;
-import com.android.launcher3.Utilities;
import com.android.launcher3.util.Executors;
/**
@@ -184,13 +181,12 @@
return null;
}
- if (!Utilities.ATLEAST_R || !METHOD_GET_PREVIEW.equals(method)) {
+ if (!METHOD_GET_PREVIEW.equals(method)) {
return null;
}
return getPreview(extras);
}
- @TargetApi(Build.VERSION_CODES.R)
private synchronized Bundle getPreview(Bundle request) {
PreviewLifecycleObserver observer = null;
try {
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 7dcc8a8..e0a6627 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -26,7 +26,6 @@
import static com.android.launcher3.model.ModelUtils.filterCurrentWorkspaceItems;
import static com.android.launcher3.model.ModelUtils.getMissingHotseatRanks;
-import android.annotation.TargetApi;
import android.app.Fragment;
import android.app.WallpaperColors;
import android.app.WallpaperManager;
@@ -39,7 +38,6 @@
import android.content.res.TypedArray;
import android.graphics.PointF;
import android.graphics.Rect;
-import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
@@ -121,7 +119,6 @@
* 3) Place appropriate elements like icons and first-page qsb
* 4) Measure and draw the view on a canvas
*/
-@TargetApi(Build.VERSION_CODES.R)
public class LauncherPreviewRenderer extends ContextWrapper
implements ActivityContext, WorkspaceLayoutManager, LayoutInflater.Factory2 {
diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
index ec6b94d..051fb6f 100644
--- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
+++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
@@ -49,7 +49,6 @@
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
import com.android.launcher3.graphics.LauncherPreviewRenderer.PreviewContext;
import com.android.launcher3.model.BgDataModel;
@@ -211,10 +210,7 @@
return new ContextThemeWrapper(context,
Themes.getActivityThemeRes(context));
}
- if (Utilities.ATLEAST_R) {
- context = context.createWindowContext(
- LayoutParams.TYPE_APPLICATION_OVERLAY, null);
- }
+ context = context.createWindowContext(LayoutParams.TYPE_APPLICATION_OVERLAY, null);
LocalColorExtractor.newInstance(context)
.applyColorsOverride(context, mWallpaperColors);
return new ContextThemeWrapper(context,
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 45ff33b..f9b7495 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -713,6 +713,9 @@
@UiEvent(doc = "User tapped on install to private space system shortcut.")
LAUNCHER_PRIVATE_SPACE_INSTALL_SYSTEM_SHORTCUT_TAP(1565),
+ @UiEvent(doc = "User tapped private space install app button.")
+ LAUNCHER_PRIVATE_SPACE_INSTALL_APP_BUTTON_TAP(1605),
+
@UiEvent(doc = "User attempted to create split screen with a widget")
LAUNCHER_SPLIT_WIDGET_ATTEMPT(1604)
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index 1044dfb..2f678a8 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -50,11 +50,13 @@
import com.android.launcher3.model.data.IconRequestInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.pm.UserCache;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.ContentWriter;
import com.android.launcher3.util.GridOccupancy;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSparseArrayMap;
+import com.android.launcher3.util.UserIconInfo;
import java.net.URISyntaxException;
import java.security.InvalidParameterException;
@@ -353,6 +355,8 @@
final WorkspaceItemInfo info = new WorkspaceItemInfo();
info.user = user;
info.intent = newIntent;
+ UserCache userCache = UserCache.getInstance(mContext);
+ UserIconInfo userIconInfo = userCache.getUserInfo(user);
if (loadIcon) {
mIconCache.getTitleAndIcon(info, mActivityInfo, useLowResIcon);
@@ -362,7 +366,7 @@
}
if (mActivityInfo != null) {
- AppInfo.updateRuntimeFlagsForActivityTarget(info, mActivityInfo);
+ AppInfo.updateRuntimeFlagsForActivityTarget(info, mActivityInfo, userIconInfo);
}
// from the db
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index d0a1f10..736b80a 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -655,7 +655,7 @@
// Create the ApplicationInfos
for (int i = 0; i < apps.size(); i++) {
LauncherActivityInfo app = apps.get(i);
- AppInfo appInfo = new AppInfo(app, user, quietMode);
+ AppInfo appInfo = new AppInfo(app, mUserCache.getUserInfo(user), quietMode);
if (enableSupportForArchiving() && app.getApplicationInfo().isArchived) {
// For archived apps, include progress info in case there is a pending
// install session post restart of device.
diff --git a/src/com/android/launcher3/model/ModelDbController.java b/src/com/android/launcher3/model/ModelDbController.java
index 6c64713..ba2b64d 100644
--- a/src/com/android/launcher3/model/ModelDbController.java
+++ b/src/com/android/launcher3/model/ModelDbController.java
@@ -458,7 +458,7 @@
LauncherWidgetHolder widgetHolder) {
ContentResolver cr = mContext.getContentResolver();
String blobHandlerDigest = Settings.Secure.getString(cr, LAYOUT_DIGEST_KEY);
- if (Utilities.ATLEAST_R && !TextUtils.isEmpty(blobHandlerDigest)) {
+ if (!TextUtils.isEmpty(blobHandlerDigest)) {
BlobStoreManager blobManager = mContext.getSystemService(BlobStoreManager.class);
try (InputStream in = new ParcelFileDescriptor.AutoCloseInputStream(
blobManager.openBlob(BlobHandle.createWithSha256(
diff --git a/src/com/android/launcher3/model/data/AppInfo.java b/src/com/android/launcher3/model/data/AppInfo.java
index ea8a7a1..72eda6c 100644
--- a/src/com/android/launcher3/model/data/AppInfo.java
+++ b/src/com/android/launcher3/model/data/AppInfo.java
@@ -31,10 +31,13 @@
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
+import com.android.launcher3.Flags;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.Utilities;
import com.android.launcher3.pm.PackageInstallInfo;
+import com.android.launcher3.pm.UserCache;
import com.android.launcher3.util.PackageManagerHelper;
+import com.android.launcher3.util.UserIconInfo;
import java.util.Comparator;
@@ -83,20 +86,21 @@
* Must not hold the Context.
*/
public AppInfo(Context context, LauncherActivityInfo info, UserHandle user) {
- this(info, user, context.getSystemService(UserManager.class).isQuietModeEnabled(user));
+ this(info, UserCache.INSTANCE.get(context).getUserInfo(user),
+ context.getSystemService(UserManager.class).isQuietModeEnabled(user));
}
- public AppInfo(LauncherActivityInfo info, UserHandle user, boolean quietModeEnabled) {
+ public AppInfo(LauncherActivityInfo info, UserIconInfo userIconInfo, boolean quietModeEnabled) {
this.componentName = info.getComponentName();
this.container = CONTAINER_ALL_APPS;
- this.user = user;
+ this.user = userIconInfo.user;
intent = makeLaunchIntent(info);
if (quietModeEnabled) {
runtimeStatusFlags |= FLAG_DISABLED_QUIET_USER;
}
uid = info.getApplicationInfo().uid;
- updateRuntimeFlagsForActivityTarget(this, info);
+ updateRuntimeFlagsForActivityTarget(this, info, userIconInfo);
}
public AppInfo(AppInfo info) {
@@ -170,7 +174,7 @@
}
public static void updateRuntimeFlagsForActivityTarget(
- ItemInfoWithIcon info, LauncherActivityInfo lai) {
+ ItemInfoWithIcon info, LauncherActivityInfo lai, UserIconInfo userIconInfo) {
ApplicationInfo appInfo = lai.getApplicationInfo();
if (PackageManagerHelper.isAppSuspended(appInfo)) {
info.runtimeStatusFlags |= FLAG_DISABLED_SUSPENDED;
@@ -181,6 +185,12 @@
info.runtimeStatusFlags |= (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0
? FLAG_SYSTEM_NO : FLAG_SYSTEM_YES;
+ if (Flags.privateSpaceRestrictAccessibilityDrag()) {
+ if (userIconInfo.isPrivate()) {
+ info.runtimeStatusFlags |= FLAG_NOT_PINNABLE;
+ }
+ }
+
// Sets the progress level, installation and incremental download flags.
info.setProgressLevel(
PackageManagerHelper.getLoadingProgress(lai),
diff --git a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
index 58b12b1..c8ab09c 100644
--- a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
+++ b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
@@ -122,6 +122,11 @@
public static final int FLAG_ARCHIVED = 1 << 14;
/**
+ * Flag indicating it's the Private Space Install App icon.
+ */
+ public static final int FLAG_PRIVATE_SPACE_INSTALL_APP = 1 << 15;
+
+ /**
* Status associated with the system state of the underlying item. This is calculated every
* time a new info is created and not persisted on the disk.
*/
diff --git a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
index c67ec5a..435d223 100644
--- a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
+++ b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
@@ -25,10 +25,12 @@
import androidx.annotation.NonNull;
+import com.android.launcher3.Flags;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.Utilities;
import com.android.launcher3.icons.IconCache;
+import com.android.launcher3.pm.UserCache;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.uioverrides.ApiWrapper;
import com.android.launcher3.util.ContentWriter;
@@ -120,6 +122,11 @@
public WorkspaceItemInfo(ShortcutInfo shortcutInfo, Context context) {
user = shortcutInfo.getUserHandle();
itemType = Favorites.ITEM_TYPE_DEEP_SHORTCUT;
+ if (Flags.privateSpaceRestrictAccessibilityDrag()) {
+ if (UserCache.INSTANCE.get(context).getUserInfo(user).isPrivate()) {
+ runtimeStatusFlags |= FLAG_NOT_PINNABLE;
+ }
+ }
updateFromDeepShortcutInfo(shortcutInfo, context);
}
@@ -182,8 +189,7 @@
runtimeStatusFlags |= FLAG_DISABLED_BY_PUBLISHER;
}
disabledMessage = shortcutInfo.getDisabledMessage();
- if (Utilities.ATLEAST_P
- && shortcutInfo.getDisabledReason() == ShortcutInfo.DISABLED_REASON_VERSION_LOWER) {
+ if (shortcutInfo.getDisabledReason() == ShortcutInfo.DISABLED_REASON_VERSION_LOWER) {
runtimeStatusFlags |= FLAG_DISABLED_VERSION_LOWER;
} else {
runtimeStatusFlags &= ~FLAG_DISABLED_VERSION_LOWER;
diff --git a/src/com/android/launcher3/pm/InstallSessionHelper.java b/src/com/android/launcher3/pm/InstallSessionHelper.java
index ca27eb2..0d47462 100644
--- a/src/com/android/launcher3/pm/InstallSessionHelper.java
+++ b/src/com/android/launcher3/pm/InstallSessionHelper.java
@@ -24,7 +24,6 @@
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionInfo;
import android.content.pm.PackageManager;
-import android.os.Process;
import android.os.UserHandle;
import android.text.TextUtils;
@@ -34,7 +33,6 @@
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.SessionCommitReceiver;
-import com.android.launcher3.Utilities;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.ItemInstallQueue;
import com.android.launcher3.util.IntArray;
@@ -132,7 +130,7 @@
public SessionInfo getActiveSessionInfo(UserHandle user, String pkg) {
for (SessionInfo info : getAllVerifiedSessions()) {
boolean match = pkg.equals(info.getAppPackageName());
- if (Utilities.ATLEAST_Q && !user.equals(getUserHandle(info))) {
+ if (!user.equals(getUserHandle(info))) {
match = false;
}
if (match) {
@@ -180,9 +178,8 @@
@NonNull
public List<SessionInfo> getAllVerifiedSessions() {
- List<SessionInfo> list = new ArrayList<>(Utilities.ATLEAST_Q
- ? Objects.requireNonNull(mLauncherApps).getAllPackageInstallerSessions()
- : mInstaller.getAllSessions());
+ List<SessionInfo> list = new ArrayList<>(
+ Objects.requireNonNull(mLauncherApps).getAllPackageInstallerSessions());
Iterator<SessionInfo> it = list.iterator();
while (it.hasNext()) {
if (verify(it.next()) == null) {
@@ -252,6 +249,6 @@
}
public static UserHandle getUserHandle(@NonNull final SessionInfo info) {
- return Utilities.ATLEAST_Q ? info.getUser() : Process.myUserHandle();
+ return info.getUser();
}
}
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 934d43b..c9c5fd3 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -17,7 +17,6 @@
package com.android.launcher3.popup;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SHORTCUTS;
-import static com.android.launcher3.Utilities.ATLEAST_P;
import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.Utilities.squaredTouchSlop;
import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS;
@@ -248,10 +247,7 @@
* Animates and loads shortcuts on background thread for this popup container
*/
private void loadAppShortcuts(ItemInfo originalItemInfo) {
-
- if (ATLEAST_P) {
- setAccessibilityPaneTitle(getTitleForAccessibility());
- }
+ setAccessibilityPaneTitle(getTitleForAccessibility());
mOriginalIcon.setForceHideDot(true);
// All views are added. Animate layout from now on.
setLayoutTransition(new LayoutTransition());
diff --git a/src/com/android/launcher3/popup/RemoteActionShortcut.java b/src/com/android/launcher3/popup/RemoteActionShortcut.java
index 8df58d2..688da49 100644
--- a/src/com/android/launcher3/popup/RemoteActionShortcut.java
+++ b/src/com/android/launcher3/popup/RemoteActionShortcut.java
@@ -20,13 +20,11 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_PAUSE_TAP;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-import android.annotation.TargetApi;
import android.app.ActivityOptions;
import android.app.PendingIntent;
import android.app.RemoteAction;
import android.content.Context;
import android.content.Intent;
-import android.os.Build;
import android.util.Log;
import android.view.View;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -42,7 +40,6 @@
import java.lang.ref.WeakReference;
-@TargetApi(Build.VERSION_CODES.Q)
public class RemoteActionShortcut extends SystemShortcut<BaseDraggingActivity> {
private static final String TAG = "RemoteActionShortcut";
private static final boolean DEBUG = Utilities.IS_DEBUG_DEVICE;
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index 1c53855..22bc13b 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -326,9 +326,6 @@
*/
private UserHandle getUserForAncestralSerialNumber(BackupManager backupManager,
long ancestralSerialNumber) {
- if (!Utilities.ATLEAST_Q) {
- return null;
- }
return backupManager.getUserForAncestralSerialNumber(ancestralSerialNumber);
}
diff --git a/src/com/android/launcher3/settings/SettingsActivity.java b/src/com/android/launcher3/settings/SettingsActivity.java
index 8cb15a5..a5f9c2a 100644
--- a/src/com/android/launcher3/settings/SettingsActivity.java
+++ b/src/com/android/launcher3/settings/SettingsActivity.java
@@ -52,7 +52,6 @@
import com.android.launcher3.BuildConfig;
import com.android.launcher3.LauncherFiles;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import com.android.launcher3.model.WidgetsModel;
import com.android.launcher3.states.RotationHelper;
import com.android.launcher3.uioverrides.flags.DeveloperOptionsUI;
@@ -120,7 +119,7 @@
}
private boolean startPreference(String fragment, Bundle args, String key) {
- if (Utilities.ATLEAST_P && getSupportFragmentManager().isStateSaved()) {
+ if (getSupportFragmentManager().isStateSaved()) {
// Sometimes onClick can come after onPause because of being posted on the handler.
// Skip starting new preferences in that case.
return false;
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index ccff095..315b5e3 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -15,19 +15,17 @@
*/
package com.android.launcher3.testing;
-import static com.android.launcher3.allapps.AllAppsStore.DEFER_UPDATES_TEST;
import static com.android.launcher3.Flags.enableGridOnlyOverview;
+import static com.android.launcher3.allapps.AllAppsStore.DEFER_UPDATES_TEST;
import static com.android.launcher3.config.FeatureFlags.FOLDABLE_SINGLE_PAGE;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Insets;
import android.graphics.Point;
import android.graphics.Rect;
-import android.os.Build;
import android.os.Bundle;
import android.view.WindowInsets;
@@ -60,7 +58,6 @@
/**
* Class to handle requests from tests
*/
-@TargetApi(Build.VERSION_CODES.Q)
public class TestInformationHandler implements ResourceBasedOverride {
public static TestInformationHandler newInstance(Context context) {
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index ff8b381..9d50e6a 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -19,6 +19,7 @@
import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_BIND_PENDING_APPWIDGET;
import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_RECONFIGURE_APPWIDGET;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_INSTALL_APP_BUTTON_TAP;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_BY_PUBLISHER;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_QUIET_USER;
@@ -189,16 +190,12 @@
boolean downloadStarted) {
ItemInfo item = (ItemInfo) v.getTag();
CompletableFuture<SessionInfo> siFuture;
- if (Utilities.ATLEAST_Q) {
- siFuture = CompletableFuture.supplyAsync(() ->
- InstallSessionHelper.INSTANCE.get(launcher)
- .getActiveSessionInfo(item.user, packageName),
- UI_HELPER_EXECUTOR);
- } else {
- siFuture = CompletableFuture.completedFuture(null);
- }
+ siFuture = CompletableFuture.supplyAsync(() ->
+ InstallSessionHelper.INSTANCE.get(launcher)
+ .getActiveSessionInfo(item.user, packageName),
+ UI_HELPER_EXECUTOR);
Consumer<SessionInfo> marketLaunchAction = sessionInfo -> {
- if (sessionInfo != null && Utilities.ATLEAST_Q) {
+ if (sessionInfo != null) {
LauncherApps launcherApps = launcher.getSystemService(LauncherApps.class);
try {
launcherApps.startPackageInstallerSessionDetailsActivity(sessionInfo, null,
@@ -352,6 +349,12 @@
appInfo.getTargetComponent().getPackageName(), Process.myUserHandle());
} else {
intent = item.getIntent();
+ if (item instanceof AppInfo
+ && (((ItemInfoWithIcon) item).runtimeStatusFlags
+ & ItemInfoWithIcon.FLAG_PRIVATE_SPACE_INSTALL_APP) != 0) {
+ launcher.getStatsLogManager().logger().log(
+ LAUNCHER_PRIVATE_SPACE_INSTALL_APP_BUTTON_TAP);
+ }
}
if (intent == null) {
throw new IllegalArgumentException("Input must have a valid intent");
diff --git a/src/com/android/launcher3/touch/ItemLongClickListener.java b/src/com/android/launcher3/touch/ItemLongClickListener.java
index 9e7d4dc..116f13a 100644
--- a/src/com/android/launcher3/touch/ItemLongClickListener.java
+++ b/src/com/android/launcher3/touch/ItemLongClickListener.java
@@ -184,7 +184,7 @@
// Return early if an item is already being dragged (e.g. when long-pressing two shortcuts)
if (launcher.getDragController().isDragging()) return false;
// Return early if user is in the middle of selecting split-screen apps
- if (FeatureFlags.enableSplitContextually() && launcher.isSplitSelectionEnabled()) {
+ if (FeatureFlags.enableSplitContextually() && launcher.isSplitSelectionActive()) {
return false;
}
diff --git a/src/com/android/launcher3/touch/WorkspaceTouchListener.java b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
index 5b6c9e0..8c43f75 100644
--- a/src/com/android/launcher3/touch/WorkspaceTouchListener.java
+++ b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
@@ -206,7 +206,7 @@
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
mLauncher.getStatsLogManager().logger().log(LAUNCHER_WORKSPACE_LONGPRESS);
mLauncher.showDefaultOptions(mTouchDownPoint.x, mTouchDownPoint.y);
- if (FeatureFlags.enableSplitContextually() && mLauncher.isSplitSelectionEnabled()) {
+ if (FeatureFlags.enableSplitContextually() && mLauncher.isSplitSelectionActive()) {
mLauncher.dismissSplitSelection();
}
} else {
diff --git a/src/com/android/launcher3/util/IOUtils.java b/src/com/android/launcher3/util/IOUtils.java
index 1cec0ec..296efe9 100644
--- a/src/com/android/launcher3/util/IOUtils.java
+++ b/src/com/android/launcher3/util/IOUtils.java
@@ -19,7 +19,6 @@
import android.os.FileUtils;
import android.util.Log;
-import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import java.io.ByteArrayOutputStream;
@@ -51,17 +50,7 @@
}
public static long copy(InputStream from, OutputStream to) throws IOException {
- if (Utilities.ATLEAST_Q) {
- return FileUtils.copy(from, to);
- }
- byte[] buf = new byte[BUF_SIZE];
- long total = 0;
- int r;
- while ((r = from.read(buf)) != -1) {
- to.write(buf, 0, r);
- total += r;
- }
- return total;
+ return FileUtils.copy(from, to);
}
public static void closeSilently(Closeable c) {
diff --git a/src/com/android/launcher3/util/ItemInflater.kt b/src/com/android/launcher3/util/ItemInflater.kt
new file mode 100644
index 0000000..79091ca
--- /dev/null
+++ b/src/com/android/launcher3/util/ItemInflater.kt
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util
+
+import android.appwidget.AppWidgetHostView
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.View
+import android.view.View.OnClickListener
+import android.view.View.OnFocusChangeListener
+import android.view.ViewGroup
+import com.android.launcher3.BubbleTextView
+import com.android.launcher3.LauncherSettings.Favorites
+import com.android.launcher3.R
+import com.android.launcher3.apppairs.AppPairIcon
+import com.android.launcher3.folder.FolderIcon
+import com.android.launcher3.model.ModelWriter
+import com.android.launcher3.model.data.FolderInfo
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.model.data.LauncherAppWidgetInfo
+import com.android.launcher3.model.data.WorkspaceItemFactory
+import com.android.launcher3.model.data.WorkspaceItemInfo
+import com.android.launcher3.views.ActivityContext
+import com.android.launcher3.widget.LauncherWidgetHolder
+import com.android.launcher3.widget.PendingAppWidgetHostView
+import com.android.launcher3.widget.WidgetInflater
+
+/** Utility class to inflate View for a model item */
+class ItemInflater<T>(
+ private val context: T,
+ private val widgetHolder: LauncherWidgetHolder,
+ private val clickListener: OnClickListener,
+ private val focusListener: OnFocusChangeListener,
+ private val defaultParent: ViewGroup
+) where T : Context, T : ActivityContext {
+
+ private val widgetInflater = WidgetInflater(context)
+
+ @JvmOverloads
+ fun inflateItem(item: ItemInfo, writer: ModelWriter, nullableParent: ViewGroup? = null): View? {
+ val parent = nullableParent ?: defaultParent
+ when (item.itemType) {
+ Favorites.ITEM_TYPE_APPLICATION,
+ Favorites.ITEM_TYPE_DEEP_SHORTCUT,
+ Favorites.ITEM_TYPE_SEARCH_ACTION -> {
+ var info =
+ if (item is WorkspaceItemFactory) {
+ (item as WorkspaceItemFactory).makeWorkspaceItem(context)
+ } else {
+ item as WorkspaceItemInfo
+ }
+ if (info.container == Favorites.CONTAINER_PREDICTION) {
+ // Came from all apps prediction row -- make a copy
+ info = WorkspaceItemInfo(info)
+ }
+ return createShortcut(info, parent)
+ }
+ Favorites.ITEM_TYPE_FOLDER ->
+ return FolderIcon.inflateFolderAndIcon(
+ R.layout.folder_icon,
+ context,
+ parent,
+ item as FolderInfo
+ )
+ Favorites.ITEM_TYPE_APP_PAIR ->
+ return AppPairIcon.inflateIcon(
+ R.layout.app_pair_icon,
+ context,
+ parent,
+ item as FolderInfo
+ )
+ Favorites.ITEM_TYPE_APPWIDGET,
+ Favorites.ITEM_TYPE_CUSTOM_APPWIDGET ->
+ return inflateAppWidget(item as LauncherAppWidgetInfo, writer)
+ else -> throw RuntimeException("Invalid Item Type")
+ }
+ }
+
+ /**
+ * Creates a view representing a shortcut inflated from the specified resource.
+ *
+ * @param parent The group the shortcut belongs to. This is not necessarily the group where the
+ * shortcut should be added.
+ * @param info The data structure describing the shortcut.
+ * @return A View inflated from layoutResId.
+ */
+ private fun createShortcut(info: WorkspaceItemInfo, parent: ViewGroup): View {
+ val favorite =
+ LayoutInflater.from(parent.context).inflate(R.layout.app_icon, parent, false)
+ as BubbleTextView
+ favorite.applyFromWorkspaceItem(info)
+ favorite.setOnClickListener(clickListener)
+ favorite.onFocusChangeListener = focusListener
+ return favorite
+ }
+
+ private fun inflateAppWidget(item: LauncherAppWidgetInfo, writer: ModelWriter): View? {
+ TraceHelper.INSTANCE.beginSection("BIND_WIDGET_id=" + item.appWidgetId)
+ try {
+ val (type, reason, _, isUpdate, widgetInfo) = widgetInflater.inflateAppWidget(item)
+ if (type == WidgetInflater.TYPE_DELETE) {
+ writer.deleteItemFromDatabase(item, reason)
+ return null
+ }
+ if (isUpdate) {
+ writer.updateItemInDatabase(item)
+ }
+ val view =
+ if (type == WidgetInflater.TYPE_PENDING || widgetInfo == null)
+ PendingAppWidgetHostView(context, item, widgetInfo)
+ else widgetHolder.createView(item.appWidgetId, widgetInfo)
+ prepareAppWidget(view, item)
+ return view
+ } finally {
+ TraceHelper.INSTANCE.endSection()
+ }
+ }
+
+ fun prepareAppWidget(hostView: AppWidgetHostView, item: LauncherAppWidgetInfo) {
+ hostView.tag = item
+ hostView.isFocusable = true
+ hostView.onFocusChangeListener = focusListener
+ }
+}
diff --git a/src/com/android/launcher3/util/StartActivityParams.java b/src/com/android/launcher3/util/StartActivityParams.java
index b48562f..d66b0a0 100644
--- a/src/com/android/launcher3/util/StartActivityParams.java
+++ b/src/com/android/launcher3/util/StartActivityParams.java
@@ -52,6 +52,7 @@
public int flagsValues;
public int extraFlags;
public Bundle options;
+ public boolean requireActivityResult = true;
public StartActivityParams(Activity activity, int requestCode) {
this(activity.createPendingResult(requestCode, new Intent(),
@@ -74,6 +75,7 @@
flagsValues = parcel.readInt();
extraFlags = parcel.readInt();
options = parcel.readBundle();
+ requireActivityResult = parcel.readInt() != 0;
}
@@ -94,6 +96,7 @@
parcel.writeInt(flagsValues);
parcel.writeInt(extraFlags);
parcel.writeBundle(options);
+ parcel.writeInt(requireActivityResult ? 1 : 0);
}
/** Perform the operation on the pendingIntent. */
diff --git a/src/com/android/launcher3/util/TraceHelper.java b/src/com/android/launcher3/util/TraceHelper.java
index 138cc4a..edcd3f6 100644
--- a/src/com/android/launcher3/util/TraceHelper.java
+++ b/src/com/android/launcher3/util/TraceHelper.java
@@ -20,12 +20,10 @@
import androidx.annotation.MainThread;
-import com.android.launcher3.Utilities;
+import kotlin.random.Random;
import java.util.function.Supplier;
-import kotlin.random.Random;
-
/**
* A wrapper around {@link Trace} to allow better testing.
*
@@ -67,9 +65,6 @@
@SuppressWarnings("NewApi")
@SuppressLint("NewApi")
public SafeCloseable beginAsyncSection(String sectionName) {
- if (!Utilities.ATLEAST_Q) {
- return () -> { };
- }
int cookie = Random.Default.nextInt();
Trace.beginAsyncSection(sectionName, cookie);
return () -> Trace.endAsyncSection(sectionName, cookie);
@@ -81,9 +76,6 @@
@SuppressWarnings("NewApi")
@SuppressLint("NewApi")
public SafeCloseable allowIpcs(String rpcName) {
- if (!Utilities.ATLEAST_Q) {
- return () -> { };
- }
int cookie = Random.Default.nextInt();
Trace.beginAsyncSection(rpcName, cookie);
return () -> Trace.endAsyncSection(rpcName, cookie);
diff --git a/src/com/android/launcher3/util/VibratorWrapper.java b/src/com/android/launcher3/util/VibratorWrapper.java
index 4f20bbc..fef1c72 100644
--- a/src/com/android/launcher3/util/VibratorWrapper.java
+++ b/src/com/android/launcher3/util/VibratorWrapper.java
@@ -28,12 +28,10 @@
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import android.annotation.SuppressLint;
-import android.annotation.TargetApi;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.media.AudioAttributes;
-import android.os.Build;
import android.os.SystemClock;
import android.os.VibrationEffect;
import android.os.Vibrator;
@@ -48,7 +46,6 @@
/**
* Wrapper around {@link Vibrator} to easily perform haptic feedback where necessary.
*/
-@TargetApi(Build.VERSION_CODES.Q)
public class VibratorWrapper {
public static final MainThreadInitializedObject<VibratorWrapper> INSTANCE =
@@ -138,7 +135,7 @@
mThresholdUntilNextDragCallMillis = 0;
}
- if (Utilities.ATLEAST_R && mVibrator.areAllPrimitivesSupported(
+ if (mVibrator.areAllPrimitivesSupported(
VibrationEffect.Composition.PRIMITIVE_QUICK_RISE,
VibrationEffect.Composition.PRIMITIVE_TICK)) {
if (FeatureFlags.ENABLE_SEARCH_HAPTIC_HINT.get()) {
@@ -226,8 +223,7 @@
public void vibrate(int primitiveId, float primitiveScale, VibrationEffect fallbackEffect) {
if (mHasVibrator && mIsHapticFeedbackEnabled) {
UI_HELPER_EXECUTOR.execute(() -> {
- if (Utilities.ATLEAST_R && primitiveId >= 0
- && mVibrator.areAllPrimitivesSupported(primitiveId)) {
+ if (primitiveId >= 0 && mVibrator.areAllPrimitivesSupported(primitiveId)) {
mVibrator.vibrate(VibrationEffect.startComposition()
.addPrimitive(primitiveId, primitiveScale)
.compose(), VIBRATION_ATTRS);
diff --git a/src/com/android/launcher3/util/window/WindowManagerProxy.java b/src/com/android/launcher3/util/window/WindowManagerProxy.java
index 51a96c4..209a3dc 100644
--- a/src/com/android/launcher3/util/window/WindowManagerProxy.java
+++ b/src/com/android/launcher3/util/window/WindowManagerProxy.java
@@ -105,24 +105,7 @@
/**
* Returns the real bounds for the provided display after applying any insets normalization
*/
- @TargetApi(Build.VERSION_CODES.R)
public WindowBounds getRealBounds(Context displayInfoContext, CachedDisplayInfo info) {
- if (!Utilities.ATLEAST_R) {
- Point smallestSize = new Point();
- Point largestSize = new Point();
- getDisplay(displayInfoContext).getCurrentSizeRange(smallestSize, largestSize);
-
- if (info.size.y > info.size.x) {
- // Portrait
- return new WindowBounds(info.size.x, info.size.y, smallestSize.x, largestSize.y,
- info.rotation);
- } else {
- // Landscape
- return new WindowBounds(info.size.x, info.size.y, largestSize.x, smallestSize.y,
- info.rotation);
- }
- }
-
WindowMetrics windowMetrics = displayInfoContext.getSystemService(WindowManager.class)
.getMaximumWindowMetrics();
Rect insets = new Rect();
@@ -133,10 +116,9 @@
/**
* Returns an updated insets, accounting for various Launcher UI specific overrides like taskbar
*/
- @TargetApi(Build.VERSION_CODES.R)
public WindowInsets normalizeWindowInsets(Context context, WindowInsets oldInsets,
Rect outInsets) {
- if (!Utilities.ATLEAST_R || !mTaskbarDrawnInProcess) {
+ if (!mTaskbarDrawnInProcess) {
outInsets.set(oldInsets.getSystemWindowInsetLeft(), oldInsets.getSystemWindowInsetTop(),
oldInsets.getSystemWindowInsetRight(), oldInsets.getSystemWindowInsetBottom());
return oldInsets;
@@ -220,8 +202,7 @@
}
boolean isTablet = swDp >= MIN_TABLET_WIDTH;
- boolean isTabletOrGesture = isTablet
- || (Utilities.ATLEAST_R && isGestureNav(context));
+ boolean isTabletOrGesture = isTablet || isGestureNav(context);
// Use the status bar height resources because current system API to get the status bar
// height doesn't allow to do this for an arbitrary display, it returns value only
@@ -360,17 +341,14 @@
}
/**
- *
* Returns the display associated with the context, or DEFAULT_DISPLAY if the context isn't
* associated with a display.
*/
protected Display getDisplay(Context displayInfoContext) {
- if (Utilities.ATLEAST_R) {
- try {
- return displayInfoContext.getDisplay();
- } catch (UnsupportedOperationException e) {
- // Ignore
- }
+ try {
+ return displayInfoContext.getDisplay();
+ } catch (UnsupportedOperationException e) {
+ // Ignore
}
return displayInfoContext.getSystemService(DisplayManager.class).getDisplay(
DEFAULT_DISPLAY);
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index bef84f7..c5317e3 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -19,7 +19,6 @@
import static com.android.launcher3.LauncherSettings.Animation.DEFAULT_NO_ICON;
import static com.android.launcher3.Utilities.allowBGLaunch;
-import static com.android.launcher3.logging.KeyboardStateManager.KeyboardState.HIDE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_KEYBOARD_CLOSED;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_PENDING_INTENT;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
@@ -150,7 +149,7 @@
* @return {@code true} if user has selected the first split app and is in the process of
* selecting the second
*/
- default boolean isSplitSelectionEnabled() {
+ default boolean isSplitSelectionActive() {
// Overridden
return false;
}
@@ -266,32 +265,26 @@
if (root == null) {
return;
}
- if (Utilities.ATLEAST_R) {
- Preconditions.assertUIThread();
- // Hide keyboard with WindowInsetsController if could. In case
- // hideSoftInputFromWindow may get ignored by input connection being finished
- // when the screen is off.
- //
- // In addition, inside IMF, the keyboards are closed asynchronously that launcher no
- // longer need to post to the message queue.
- final WindowInsetsController wic = root.getWindowInsetsController();
- WindowInsets insets = root.getRootWindowInsets();
- boolean isImeShown = insets != null && insets.isVisible(WindowInsets.Type.ime());
- if (wic != null) {
- // Only hide the keyboard if it is actually showing.
- if (isImeShown) {
- StatsLogManager slm = getStatsLogManager();
- slm.keyboardStateManager().setKeyboardState(HIDE);
-
- // this method cannot be called cross threads
- wic.hide(WindowInsets.Type.ime());
- slm.logger().log(LAUNCHER_ALLAPPS_KEYBOARD_CLOSED);
- }
-
- // If the WindowInsetsController is not null, we end here regardless of whether we
- // hid the keyboard or not.
- return;
+ Preconditions.assertUIThread();
+ // Hide keyboard with WindowInsetsController if could. In case hideSoftInputFromWindow may
+ // get ignored by input connection being finished when the screen is off.
+ //
+ // In addition, inside IMF, the keyboards are closed asynchronously that launcher no longer
+ // need to post to the message queue.
+ final WindowInsetsController wic = root.getWindowInsetsController();
+ WindowInsets insets = root.getRootWindowInsets();
+ boolean isImeShown = insets != null && insets.isVisible(WindowInsets.Type.ime());
+ if (wic != null) {
+ // Only hide the keyboard if it is actually showing.
+ if (isImeShown) {
+ // this method cannot be called cross threads
+ wic.hide(WindowInsets.Type.ime());
+ getStatsLogManager().logger().log(LAUNCHER_ALLAPPS_KEYBOARD_CLOSED);
}
+
+ // If the WindowInsetsController is not null, we end here regardless of whether we hid
+ // the keyboard or not.
+ return;
}
InputMethodManager imm = root.getContext().getSystemService(InputMethodManager.class);
diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java
index a1cd697..abc5ef8 100644
--- a/src/com/android/launcher3/views/BaseDragLayer.java
+++ b/src/com/android/launcher3/views/BaseDragLayer.java
@@ -551,25 +551,21 @@
@Override
public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
- if (Utilities.ATLEAST_Q) {
- Insets gestureInsets = insets.getMandatorySystemGestureInsets();
- int gestureInsetBottom = gestureInsets.bottom;
- Insets imeInset = Utilities.ATLEAST_R
- ? insets.getInsets(WindowInsets.Type.ime())
- : Insets.NONE;
- DeviceProfile dp = mActivity.getDeviceProfile();
- if (dp.isTaskbarPresent) {
- // Ignore taskbar gesture insets to avoid interfering with TouchControllers.
- gestureInsetBottom = ResourceUtils.getNavbarSize(
- ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, getResources());
- }
- mSystemGestureRegion.set(
- Math.max(gestureInsets.left, imeInset.left),
- Math.max(gestureInsets.top, imeInset.top),
- Math.max(gestureInsets.right, imeInset.right),
- Math.max(gestureInsetBottom, imeInset.bottom)
- );
+ Insets gestureInsets = insets.getMandatorySystemGestureInsets();
+ int gestureInsetBottom = gestureInsets.bottom;
+ Insets imeInset = insets.getInsets(WindowInsets.Type.ime());
+ DeviceProfile dp = mActivity.getDeviceProfile();
+ if (dp.isTaskbarPresent) {
+ // Ignore taskbar gesture insets to avoid interfering with TouchControllers.
+ gestureInsetBottom = ResourceUtils.getNavbarSize(
+ ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, getResources());
}
+ mSystemGestureRegion.set(
+ Math.max(gestureInsets.left, imeInset.left),
+ Math.max(gestureInsets.top, imeInset.top),
+ Math.max(gestureInsets.right, imeInset.right),
+ Math.max(gestureInsetBottom, imeInset.bottom)
+ );
return super.dispatchApplyWindowInsets(insets);
}
}
diff --git a/src/com/android/launcher3/views/ClipIconView.java b/src/com/android/launcher3/views/ClipIconView.java
index 7737adb..5d3fa9b 100644
--- a/src/com/android/launcher3/views/ClipIconView.java
+++ b/src/com/android/launcher3/views/ClipIconView.java
@@ -25,7 +25,6 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
-import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -36,7 +35,6 @@
import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
-import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup.MarginLayoutParams;
@@ -55,7 +53,6 @@
* Supports springing just the foreground layer.
* Supports clipping the icon to/from its icon shape.
*/
-@TargetApi(Build.VERSION_CODES.Q)
public class ClipIconView extends View implements ClipPathView {
private static final Rect sTmpRect = new Rect();
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 32c70a3..f76b53b 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -24,14 +24,12 @@
import static com.android.launcher3.views.IconLabelDotView.setIconAndDotVisible;
import android.animation.Animator;
-import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.Drawable;
-import android.os.Build;
import android.os.CancellationSignal;
import android.util.AttributeSet;
import android.util.Log;
@@ -67,7 +65,6 @@
/**
* A view that is created to look like another view with the purpose of creating fluid animations.
*/
-@TargetApi(Build.VERSION_CODES.Q)
public class FloatingIconView extends FrameLayout implements
Animator.AnimatorListener, OnGlobalLayoutListener, FloatingView {
diff --git a/src/com/android/launcher3/views/FloatingSurfaceView.java b/src/com/android/launcher3/views/FloatingSurfaceView.java
index bfb75f0..76b6fde 100644
--- a/src/com/android/launcher3/views/FloatingSurfaceView.java
+++ b/src/com/android/launcher3/views/FloatingSurfaceView.java
@@ -18,14 +18,12 @@
import static com.android.launcher3.views.FloatingIconView.getLocationBoundsForView;
import static com.android.launcher3.views.IconLabelDotView.setIconAndDotVisible;
-import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Picture;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
-import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
@@ -47,7 +45,6 @@
* Similar to {@link FloatingIconView} but displays a surface with the targetIcon. It then passes
* the surfaceHandle to the {@link GestureNavContract}.
*/
-@TargetApi(Build.VERSION_CODES.R)
public class FloatingSurfaceView extends AbstractFloatingView implements
OnGlobalLayoutListener, Insettable, SurfaceHolder.Callback2 {
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index c0b24fa..8408cc7 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -30,7 +30,6 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
-import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Property;
@@ -40,7 +39,6 @@
import android.view.WindowInsets;
import android.widget.TextView;
-import androidx.annotation.RequiresApi;
import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.FastScrollRecyclerView;
@@ -352,26 +350,21 @@
float r = getScrollThumbRadius();
mThumbBounds.set(-halfW, 0, halfW, mThumbHeight);
canvas.drawRoundRect(mThumbBounds, r, r, mThumbPaint);
- if (Utilities.ATLEAST_Q) {
- mThumbBounds.roundOut(SYSTEM_GESTURE_EXCLUSION_RECT.get(0));
- // swiping very close to the thumb area (not just within it's bound)
- // will also prevent back gesture
- SYSTEM_GESTURE_EXCLUSION_RECT.get(0).offset(mThumbDrawOffset.x, mThumbDrawOffset.y);
- if (Utilities.ATLEAST_Q && mSystemGestureInsets != null) {
- SYSTEM_GESTURE_EXCLUSION_RECT.get(0).left =
- SYSTEM_GESTURE_EXCLUSION_RECT.get(0).right - mSystemGestureInsets.right;
- }
- setSystemGestureExclusionRects(SYSTEM_GESTURE_EXCLUSION_RECT);
+ mThumbBounds.roundOut(SYSTEM_GESTURE_EXCLUSION_RECT.get(0));
+ // swiping very close to the thumb area (not just within it's bound)
+ // will also prevent back gesture
+ SYSTEM_GESTURE_EXCLUSION_RECT.get(0).offset(mThumbDrawOffset.x, mThumbDrawOffset.y);
+ if (mSystemGestureInsets != null) {
+ SYSTEM_GESTURE_EXCLUSION_RECT.get(0).left =
+ SYSTEM_GESTURE_EXCLUSION_RECT.get(0).right - mSystemGestureInsets.right;
}
+ setSystemGestureExclusionRects(SYSTEM_GESTURE_EXCLUSION_RECT);
canvas.restoreToCount(saveCount);
}
@Override
- @RequiresApi(Build.VERSION_CODES.Q)
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
- if (Utilities.ATLEAST_Q) {
- mSystemGestureInsets = insets.getSystemGestureInsets();
- }
+ mSystemGestureInsets = insets.getSystemGestureInsets();
return super.onApplyWindowInsets(insets);
}
diff --git a/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java b/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java
index 80b1cdd..4f5d311 100644
--- a/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java
@@ -16,8 +16,6 @@
package com.android.launcher3.widget;
-import static com.android.launcher3.Utilities.ATLEAST_R;
-
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Insets;
@@ -153,17 +151,10 @@
@SuppressLint("NewApi") // Already added API check.
@Override
public WindowInsets onApplyWindowInsets(View view, WindowInsets windowInsets) {
- if (ATLEAST_R) {
- Insets insets = windowInsets.getInsets(WindowInsets.Type.systemBars());
- mInsets.set(insets.left, insets.top, insets.right, insets.bottom);
- } else {
- mInsets.set(windowInsets.getSystemWindowInsetLeft(),
- windowInsets.getSystemWindowInsetTop(),
- windowInsets.getSystemWindowInsetRight(),
- windowInsets.getSystemWindowInsetBottom());
- }
- mContent.setPadding(mContent.getPaddingStart(),
- mContent.getPaddingTop(), mContent.getPaddingEnd(), mInsets.bottom);
+ Insets insets = windowInsets.getInsets(WindowInsets.Type.systemBars());
+ mInsets.set(insets.left, insets.top, insets.right, insets.bottom);
+ mContent.setPadding(mContent.getPaddingStart(), mContent.getPaddingTop(),
+ mContent.getPaddingEnd(), mInsets.bottom);
int contentHorizontalMarginInPx = getResources().getDimensionPixelSize(
R.dimen.widget_list_horizontal_margin);
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index 5171fa2..9de7f62 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -158,10 +158,8 @@
private int getNavBarScrimHeight(WindowInsets insets) {
if (mDisableNavBarScrim) {
return 0;
- } else if (Utilities.ATLEAST_Q) {
- return insets.getTappableElementInsets().bottom;
} else {
- return insets.getStableInsetBottom();
+ return insets.getTappableElementInsets().bottom;
}
}
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
index e0de269..e77ec12 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
@@ -16,11 +16,9 @@
package com.android.launcher3.widget;
-import android.annotation.TargetApi;
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
import android.graphics.Rect;
-import android.os.Build;
import android.os.Handler;
import android.os.Parcelable;
import android.os.SystemClock;
@@ -44,7 +42,6 @@
import com.android.launcher3.Flags;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -105,7 +102,7 @@
setDefaultFocusHighlightEnabled(false);
}
- if (Utilities.ATLEAST_Q && Themes.getAttrBoolean(mLauncher, R.attr.isWorkspaceDarkText)) {
+ if (Themes.getAttrBoolean(mLauncher, R.attr.isWorkspaceDarkText)) {
setOnLightBackground(true);
}
mColorExtractor = new LocalColorExtractor(); // no-op
@@ -131,10 +128,9 @@
}
@Override
- @TargetApi(Build.VERSION_CODES.Q)
public void setAppWidget(int appWidgetId, AppWidgetProviderInfo info) {
super.setAppWidget(appWidgetId, info);
- if (!mTrackingWidgetUpdate && Utilities.ATLEAST_Q) {
+ if (!mTrackingWidgetUpdate) {
mTrackingWidgetUpdate = true;
Trace.beginAsyncSection(TRACE_METHOD_NAME + info.provider, appWidgetId);
Log.i(TAG, "App widget created with id: " + appWidgetId);
@@ -142,9 +138,8 @@
}
@Override
- @TargetApi(Build.VERSION_CODES.Q)
public void updateAppWidget(RemoteViews remoteViews) {
- if (mTrackingWidgetUpdate && remoteViews != null && Utilities.ATLEAST_Q) {
+ if (mTrackingWidgetUpdate && remoteViews != null) {
Log.i(TAG, "App widget with id: " + getAppWidgetId() + " loaded");
Trace.endAsyncSection(
TRACE_METHOD_NAME + getAppWidgetInfo().provider, getAppWidgetId());
@@ -288,8 +283,7 @@
super.onLayout(changed, left, top, right, bottom);
mIsScrollable = checkScrollableRecursively(this);
- if (!mIsInDragMode && getTag() instanceof LauncherAppWidgetInfo) {
- LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) getTag();
+ if (!mIsInDragMode && getTag() instanceof LauncherAppWidgetInfo info) {
mTempRect.set(left, top, right, bottom);
mColorExtractor.setWorkspaceLocation(mTempRect, (View) getParent(), info.screenId);
}
@@ -425,8 +419,7 @@
@Override
protected boolean shouldAllowDirectClick() {
- if (getTag() instanceof ItemInfo) {
- ItemInfo item = (ItemInfo) getTag();
+ if (getTag() instanceof ItemInfo item) {
return item.spanX == 1 && item.spanY == 1;
}
return false;
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java b/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java
index ef51d15..3e4fd8c 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java
@@ -15,7 +15,6 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.Utilities;
import com.android.launcher3.icons.ComponentWithLabelAndIcon;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -206,11 +205,7 @@
}
public int getWidgetFeatures() {
- if (Utilities.ATLEAST_P) {
- return widgetFeatures;
- } else {
- return 0;
- }
+ return widgetFeatures;
}
public boolean isReconfigurable() {
diff --git a/tests/Android.bp b/tests/Android.bp
index a236954..310e418 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -21,13 +21,13 @@
filegroup {
name: "launcher-tests-src",
srcs: [
- "src/**/*.java",
- "src/**/*.kt",
- "multivalentTests/src/**/*.java",
- "multivalentTests/src/**/*.kt",
+ "src/**/*.java",
+ "src/**/*.kt",
+ "multivalentTests/src/**/*.java",
+ "multivalentTests/src/**/*.kt",
],
exclude_srcs: [
- ":launcher-non-quickstep-tests-src"
+ ":launcher-non-quickstep-tests-src",
],
}
@@ -35,25 +35,25 @@
filegroup {
name: "launcher-image-tests-helpers",
srcs: [
- "multivalentTests/src/com/android/launcher3/celllayout/board/*.java",
- "multivalentTests/src/com/android/launcher3/celllayout/board/*.kt",
- "multivalentTests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java",
- "multivalentTests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java",
- "multivalentTests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java",
- "multivalentTests/src/com/android/launcher3/ui/TestViewHelpers.java",
- "multivalentTests/src/com/android/launcher3/util/LauncherLayoutBuilder.java",
- "multivalentTests/src/com/android/launcher3/util/ModelTestExtensions.kt",
- "multivalentTests/src/com/android/launcher3/util/TestConstants.java",
- "multivalentTests/src/com/android/launcher3/util/TestUtil.java",
- "multivalentTests/src/com/android/launcher3/util/Wait.java",
- "multivalentTests/src/com/android/launcher3/util/WidgetUtils.java",
- "multivalentTests/src/com/android/launcher3/util/rule/*.java",
- "multivalentTests/src/com/android/launcher3/util/rule/*.kt",
- "multivalentTests/src/com/android/launcher3/util/rule/*.java",
- "multivalentTests/src/com/android/launcher3/util/rule/*.kt",
- "multivalentTests/src/com/android/launcher3/util/viewcapture_analysis/*.java",
- "multivalentTests/src/com/android/launcher3/testcomponent/*.java",
- "multivalentTests/src/com/android/launcher3/testcomponent/*.kt",
+ "multivalentTests/src/com/android/launcher3/celllayout/board/*.java",
+ "multivalentTests/src/com/android/launcher3/celllayout/board/*.kt",
+ "multivalentTests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java",
+ "multivalentTests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java",
+ "multivalentTests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java",
+ "multivalentTests/src/com/android/launcher3/ui/TestViewHelpers.java",
+ "multivalentTests/src/com/android/launcher3/util/LauncherLayoutBuilder.java",
+ "multivalentTests/src/com/android/launcher3/util/ModelTestExtensions.kt",
+ "multivalentTests/src/com/android/launcher3/util/TestConstants.java",
+ "multivalentTests/src/com/android/launcher3/util/TestUtil.java",
+ "multivalentTests/src/com/android/launcher3/util/Wait.java",
+ "multivalentTests/src/com/android/launcher3/util/WidgetUtils.java",
+ "multivalentTests/src/com/android/launcher3/util/rule/*.java",
+ "multivalentTests/src/com/android/launcher3/util/rule/*.kt",
+ "multivalentTests/src/com/android/launcher3/util/rule/*.java",
+ "multivalentTests/src/com/android/launcher3/util/rule/*.kt",
+ "multivalentTests/src/com/android/launcher3/util/viewcapture_analysis/*.java",
+ "multivalentTests/src/com/android/launcher3/testcomponent/*.java",
+ "multivalentTests/src/com/android/launcher3/testcomponent/*.kt",
],
}
@@ -61,8 +61,8 @@
filegroup {
name: "launcher-non-quickstep-tests-src",
srcs: [
- "src/com/android/launcher3/nonquickstep/**/*.java",
- "src/com/android/launcher3/nonquickstep/**/*.kt",
+ "src/com/android/launcher3/nonquickstep/**/*.java",
+ "src/com/android/launcher3/nonquickstep/**/*.kt",
],
}
@@ -70,42 +70,42 @@
filegroup {
name: "launcher-oop-tests-src",
srcs: [
- "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/TaplUninstallRemoveTest.java",
- "multivalentTests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java",
- "multivalentTests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java",
- "src/com/android/launcher3/ui/TaplTestsLauncher3Test.java",
- "src/com/android/launcher3/ui/widget/TaplWidgetPickerTest.java",
- "src/com/android/launcher3/ui/workspace/TaplWorkspaceTest.java",
- "multivalentTests/src/com/android/launcher3/util/LauncherLayoutBuilder.java",
- "multivalentTests/src/com/android/launcher3/util/TestConstants.java",
- "multivalentTests/src/com/android/launcher3/util/TestUtil.java",
- "multivalentTests/src/com/android/launcher3/util/Wait.java",
- "multivalentTests/src/com/android/launcher3/util/WidgetUtils.java",
- "multivalentTests/src/com/android/launcher3/util/rule/FailureWatcher.java",
- "multivalentTests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt",
- "multivalentTests/src/com/android/launcher3/util/rule/SamplerRule.java",
- "multivalentTests/src/com/android/launcher3/util/rule/ScreenRecordRule.java",
- "multivalentTests/src/com/android/launcher3/util/rule/ShellCommandRule.java",
- "multivalentTests/src/com/android/launcher3/util/rule/TestIsolationRule.java",
- "multivalentTests/src/com/android/launcher3/util/rule/TestStabilityRule.java",
- "multivalentTests/src/com/android/launcher3/util/viewcapture_analysis/*.java",
- "multivalentTests/src/com/android/launcher3/testcomponent/BaseTestingActivity.java",
- "multivalentTests/src/com/android/launcher3/testcomponent/OtherBaseTestingActivity.java",
- "multivalentTests/src/com/android/launcher3/testcomponent/CustomShortcutConfigActivity.java",
- "multivalentTests/src/com/android/launcher3/testcomponent/TestCommandReceiver.java",
- "multivalentTests/src/com/android/launcher3/testcomponent/TestLauncherActivity.java",
- "multivalentTests/src/com/android/launcher3/testcomponent/ImeTestActivity.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/TaplUninstallRemoveTest.java",
+ "multivalentTests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java",
+ "multivalentTests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java",
+ "src/com/android/launcher3/ui/TaplTestsLauncher3Test.java",
+ "src/com/android/launcher3/ui/widget/TaplWidgetPickerTest.java",
+ "src/com/android/launcher3/ui/workspace/TaplWorkspaceTest.java",
+ "multivalentTests/src/com/android/launcher3/util/LauncherLayoutBuilder.java",
+ "multivalentTests/src/com/android/launcher3/util/TestConstants.java",
+ "multivalentTests/src/com/android/launcher3/util/TestUtil.java",
+ "multivalentTests/src/com/android/launcher3/util/Wait.java",
+ "multivalentTests/src/com/android/launcher3/util/WidgetUtils.java",
+ "multivalentTests/src/com/android/launcher3/util/rule/FailureWatcher.java",
+ "multivalentTests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt",
+ "multivalentTests/src/com/android/launcher3/util/rule/SamplerRule.java",
+ "multivalentTests/src/com/android/launcher3/util/rule/ScreenRecordRule.java",
+ "multivalentTests/src/com/android/launcher3/util/rule/ShellCommandRule.java",
+ "multivalentTests/src/com/android/launcher3/util/rule/TestIsolationRule.java",
+ "multivalentTests/src/com/android/launcher3/util/rule/TestStabilityRule.java",
+ "multivalentTests/src/com/android/launcher3/util/viewcapture_analysis/*.java",
+ "multivalentTests/src/com/android/launcher3/testcomponent/BaseTestingActivity.java",
+ "multivalentTests/src/com/android/launcher3/testcomponent/OtherBaseTestingActivity.java",
+ "multivalentTests/src/com/android/launcher3/testcomponent/CustomShortcutConfigActivity.java",
+ "multivalentTests/src/com/android/launcher3/testcomponent/TestCommandReceiver.java",
+ "multivalentTests/src/com/android/launcher3/testcomponent/TestLauncherActivity.java",
+ "multivalentTests/src/com/android/launcher3/testcomponent/ImeTestActivity.java",
],
}
// Library with all the dependencies for building quickstep
android_library {
name: "Launcher3TestLib",
- srcs: [ ],
+ srcs: [],
asset_dirs: ["assets"],
resource_dirs: ["res"],
static_libs: [
@@ -130,11 +130,15 @@
],
manifest: "AndroidManifest-common.xml",
platform_apis: true,
+ // TODO(b/319712088): re-enable use_resource_processor
+ use_resource_processor: false,
}
android_library {
name: "Launcher3TestResources",
resource_dirs: ["res"],
+ // TODO(b/319712088): re-enable use_resource_processor
+ use_resource_processor: false,
}
android_test {
@@ -171,24 +175,24 @@
android_library {
name: "launcher-testing-shared",
srcs: [
- "multivalentTests/shared/com/android/launcher3/testing/shared/**/*.java"
+ "multivalentTests/shared/com/android/launcher3/testing/shared/**/*.java",
],
- resource_dirs: [ ],
+ resource_dirs: [],
manifest: "multivalentTests/shared/AndroidManifest.xml",
sdk_version: "current",
min_sdk_version: min_launcher3_sdk_version,
- }
+}
filegroup {
name: "launcher-testing-helpers",
srcs: [
- "src/**/*.java",
- "src/**/*.kt",
- "multivalentTests/src/**/*.java",
- "multivalentTests/src/**/*.kt",
- "multivalentTests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java",
- "multivalentTests/tapl/com/android/launcher3/tapl/*.java",
- "multivalentTests/tapl/com/android/launcher3/tapl/*.kt",
+ "src/**/*.java",
+ "src/**/*.kt",
+ "multivalentTests/src/**/*.java",
+ "multivalentTests/src/**/*.kt",
+ "multivalentTests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java",
+ "multivalentTests/tapl/com/android/launcher3/tapl/*.java",
+ "multivalentTests/tapl/com/android/launcher3/tapl/*.kt",
],
exclude_srcs: [
// Test classes
@@ -209,6 +213,8 @@
static_libs: [
"Launcher3CommonDepsLib",
],
+ // TODO(b/319712088): re-enable use_resource_processor
+ use_resource_processor: false,
}
android_robolectric_test {
diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml
index e5e3354..7059268 100644
--- a/tests/AndroidManifest-common.xml
+++ b/tests/AndroidManifest-common.xml
@@ -88,6 +88,14 @@
android:resource="@xml/appwidget_dynamic_colors"/>
</receiver>
+ <receiver android:name="com.android.launcher3.testcomponent.UnarchiveBroadcastReceiver"
+ android:enabled="true"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.UNARCHIVE_PACKAGE"/>
+ </intent-filter>
+ </receiver>
+
<activity
android:name="com.android.launcher3.testcomponent.WidgetConfigActivity"
android:exported="true">
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index 2596b75..5cf96c8 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -23,14 +23,6 @@
<application android:debuggable="true">
<uses-library android:name="android.test.runner" />
-
- <receiver android:name="com.android.launcher3.compat.PromiseIconUiTest$UnarchiveBroadcastReceiver"
- android:enabled="true"
- android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.UNARCHIVE_PACKAGE"/>
- </intent-filter>
- </receiver>
</application>
<instrumentation
diff --git a/tests/multivalentTests/src/com/android/launcher3/testcomponent/UnarchiveBroadcastReceiver.java b/tests/multivalentTests/src/com/android/launcher3/testcomponent/UnarchiveBroadcastReceiver.java
new file mode 100644
index 0000000..0f5117b
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/testcomponent/UnarchiveBroadcastReceiver.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.testcomponent;
+
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * Broadcast Receiver to receive app unarchival broadcast. It is used to fulfill archiving
+ * platform requirements.
+ */
+public class UnarchiveBroadcastReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ }
+}
diff --git a/tests/multivalentTests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/multivalentTests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index f68e12c..fef93b7 100644
--- a/tests/multivalentTests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/multivalentTests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -1771,6 +1771,7 @@
}
endTime = movePointer(
start, end, steps, false, downTime, downTime, slowDown, gestureScope);
+ } finally {
if (mTrackpadGestureType != TrackpadGestureType.NONE) {
for (int i = mPointerCount; i >= 2; i--) {
sendPointer(downTime, downTime,
@@ -1778,7 +1779,6 @@
start, gestureScope);
}
}
- } finally {
sendPointer(downTime, endTime, MotionEvent.ACTION_UP, end, gestureScope);
}
}
@@ -2055,11 +2055,14 @@
final long downTime = SystemClock.uptimeMillis();
sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, targetCenter,
GestureScope.DONT_EXPECT_PILFER);
- expectEvent(TestProtocol.SEQUENCE_MAIN, longClickEvent);
- final UiObject2 result = waitForLauncherObject(resName);
- sendPointer(downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, targetCenter,
- GestureScope.DONT_EXPECT_PILFER);
- return result;
+ try {
+ expectEvent(TestProtocol.SEQUENCE_MAIN, longClickEvent);
+ final UiObject2 result = waitForLauncherObject(resName);
+ return result;
+ } finally {
+ sendPointer(downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, targetCenter,
+ GestureScope.DONT_EXPECT_PILFER);
+ }
}
@NonNull
@@ -2070,12 +2073,15 @@
sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, targetCenter,
GestureScope.DONT_EXPECT_PILFER, InputDevice.SOURCE_MOUSE,
/* isRightClick= */ true);
- expectEvent(TestProtocol.SEQUENCE_MAIN, rightClickEvent);
- final UiObject2 result = waitForLauncherObject(resName);
- sendPointer(downTime, SystemClock.uptimeMillis(), ACTION_UP, targetCenter,
- GestureScope.DONT_EXPECT_PILFER, InputDevice.SOURCE_MOUSE,
- /* isRightClick= */ true);
- return result;
+ try {
+ expectEvent(TestProtocol.SEQUENCE_MAIN, rightClickEvent);
+ final UiObject2 result = waitForLauncherObject(resName);
+ return result;
+ } finally {
+ sendPointer(downTime, SystemClock.uptimeMillis(), ACTION_UP, targetCenter,
+ GestureScope.DONT_EXPECT_PILFER, InputDevice.SOURCE_MOUSE,
+ /* isRightClick= */ true);
+ }
}
private static int getSystemIntegerRes(Context context, String resName) {
diff --git a/tests/multivalentTests/tapl/com/android/launcher3/tapl/WidgetResizeFrame.java b/tests/multivalentTests/tapl/com/android/launcher3/tapl/WidgetResizeFrame.java
index ec1cbd8..d0573e0 100644
--- a/tests/multivalentTests/tapl/com/android/launcher3/tapl/WidgetResizeFrame.java
+++ b/tests/multivalentTests/tapl/com/android/launcher3/tapl/WidgetResizeFrame.java
@@ -16,6 +16,7 @@
package com.android.launcher3.tapl;
import static com.android.launcher3.tapl.Launchable.DEFAULT_DRAG_STEPS;
+
import static org.junit.Assert.assertTrue;
import android.graphics.Point;
@@ -61,11 +62,14 @@
final long downTime = SystemClock.uptimeMillis();
mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, targetStart,
LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
- mLauncher.movePointer(targetStart, targetDest, DEFAULT_DRAG_STEPS,
- true, downTime, downTime, true,
- LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
- mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_UP, targetDest,
- LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
+ try {
+ mLauncher.movePointer(targetStart, targetDest, DEFAULT_DRAG_STEPS,
+ true, downTime, downTime, true,
+ LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
+ } finally {
+ mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_UP, targetDest,
+ LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
+ }
try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer(
"want to return resized widget resize frame")) {
diff --git a/tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java b/tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
index e1af774..0ff7c20 100644
--- a/tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
+++ b/tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
@@ -29,8 +29,6 @@
import androidx.test.filters.SmallTest;
import com.android.launcher3.CellLayout;
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.MultipageCellLayout;
import com.android.launcher3.celllayout.board.CellLayoutBoard;
import com.android.launcher3.celllayout.board.IconPoint;
@@ -41,8 +39,7 @@
import com.android.launcher3.util.ActivityContextWrapper;
import com.android.launcher3.views.DoubleShadowBubbleTextView;
-import org.junit.After;
-import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -70,7 +67,8 @@
private static final int TOTAL_OF_CASES_GENERATED = 300;
private Context mApplicationContext;
- private int mPrevNumColumns, mPrevNumRows;
+ @Rule
+ public UnitTestCellLayoutBuilderRule mCellLayoutBuilder = new UnitTestCellLayoutBuilderRule();
/**
* This test reads existing test cases and makes sure the CellLayout produces the same
@@ -144,34 +142,10 @@
(CellLayoutLayoutParams) cell.getLayoutParams(), true);
}
- public CellLayout createCellLayout(int width, int height, boolean isMulti) {
- Context c = mApplicationContext;
- DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(c).getDeviceProfile(c).copy(c);
- // modify the device profile.
- dp.inv.numColumns = isMulti ? width / 2 : width;
- dp.inv.numRows = height;
- dp.cellLayoutBorderSpacePx = new Point(0, 0);
-
- CellLayout cl = isMulti ? new MultipageCellLayout(getWrappedContext(c, dp))
- : new CellLayout(getWrappedContext(c, dp));
- // I put a very large number for width and height so that all the items can fit, it doesn't
- // need to be exact, just bigger than the sum of cell border
- cl.measure(View.MeasureSpec.makeMeasureSpec(10000, View.MeasureSpec.EXACTLY),
- View.MeasureSpec.makeMeasureSpec(10000, View.MeasureSpec.EXACTLY));
- return cl;
- }
-
- private Context getWrappedContext(Context context, DeviceProfile dp) {
- return new ActivityContextWrapper(context) {
- public DeviceProfile getDeviceProfile() {
- return dp;
- }
- };
- }
-
public ItemConfiguration solve(CellLayoutBoard board, int x, int y, int spanX,
int spanY, int minSpanX, int minSpanY, boolean isMulti) {
- CellLayout cl = createCellLayout(board.getWidth(), board.getHeight(), isMulti);
+ CellLayout cl = mCellLayoutBuilder.createCellLayout(board.getWidth(), board.getHeight(),
+ isMulti);
// The views have to be sorted or the result can vary
board.getIcons()
@@ -249,22 +223,6 @@
}
}
- @Before
- public void storePreviousValues() {
- Context c = new ActivityContextWrapper(getApplicationContext());
- DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(c).getDeviceProfile(c).copy(c);
- mPrevNumColumns = dp.inv.numColumns;
- mPrevNumRows = dp.inv.numRows;
- }
-
- @After
- public void restorePreviousValues() {
- Context c = new ActivityContextWrapper(getApplicationContext());
- DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(c).getDeviceProfile(c).copy(c);
- dp.inv.numColumns = mPrevNumColumns;
- dp.inv.numRows = mPrevNumRows;
- }
-
private ReorderAlgorithmUnitTestCase generateRandomTestCase(
RandomBoardGenerator boardGenerator) {
ReorderAlgorithmUnitTestCase testCase = new ReorderAlgorithmUnitTestCase();
diff --git a/tests/src/com/android/launcher3/celllayout/ReorderPreviewAnimationTest.kt b/tests/src/com/android/launcher3/celllayout/ReorderPreviewAnimationTest.kt
new file mode 100644
index 0000000..0bec1b2
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/ReorderPreviewAnimationTest.kt
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.celllayout
+
+import android.content.Context
+import android.util.ArrayMap
+import android.view.View
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.CellLayout
+import com.android.launcher3.Reorderable
+import com.android.launcher3.celllayout.ReorderPreviewAnimation.Companion.HINT_DURATION
+import com.android.launcher3.celllayout.ReorderPreviewAnimation.Companion.PREVIEW_DURATION
+import com.android.launcher3.util.ActivityContextWrapper
+import com.android.launcher3.util.MultiTranslateDelegate
+import com.android.launcher3.util.MultiTranslateDelegate.INDEX_REORDER_BOUNCE_OFFSET
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+class Mock(context: Context) : Reorderable, View(context) {
+
+ init {
+ mLeft = 0
+ mRight = 100
+ }
+
+ private val translateDelegate = MultiTranslateDelegate(this)
+
+ private var scaleForReorderBounce = 1f
+ override fun getTranslateDelegate(): MultiTranslateDelegate {
+ return translateDelegate
+ }
+
+ override fun setReorderBounceScale(scale: Float) {
+ scaleForReorderBounce = scale
+ }
+
+ override fun getReorderBounceScale(): Float {
+ return scaleForReorderBounce
+ }
+
+ fun toAnimationValues(): AnimationValues {
+ return AnimationValues(
+ (translateDelegate.getTranslationX(INDEX_REORDER_BOUNCE_OFFSET).value * 100).toInt(),
+ (translateDelegate.getTranslationY(INDEX_REORDER_BOUNCE_OFFSET).value * 100).toInt(),
+ (scaleForReorderBounce * 100).toInt()
+ )
+ }
+}
+
+data class AnimationValues(val dx: Int, val dy: Int, val scale: Int)
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ReorderPreviewAnimationTest {
+
+ @JvmField @Rule var cellLayoutBuilder = UnitTestCellLayoutBuilderRule()
+
+ private val applicationContext =
+ ActivityContextWrapper(ApplicationProvider.getApplicationContext())
+
+ /**
+ * @param animationTime the time of the animation we will check the state against.
+ * @param mode the mode either PREVIEW_DURATION or HINT_DURATION.
+ * @param valueToMatch the state of the animation we expect to see at animationTime.
+ * @param isAfterReverse if the animation is finish and we are returning to the beginning.
+ */
+ private fun testAnimationAtGivenProgress(
+ animationTime: Int,
+ mode: Int,
+ valueToMatch: AnimationValues
+ ) {
+ val view = Mock(applicationContext)
+ val cellLayout = cellLayoutBuilder.createCellLayout(100, 100, false)
+ val map = ArrayMap<Reorderable, ReorderPreviewAnimation<Mock>>()
+ val animation =
+ ReorderPreviewAnimation(
+ view,
+ mode,
+ 3,
+ 3,
+ 1,
+ 7,
+ 1,
+ 1,
+ CellLayout.REORDER_PREVIEW_MAGNITUDE,
+ cellLayout,
+ map
+ )
+ // Remove delay because it's randomly generated and it can slightly change the results.
+ animation.animator.startDelay = 0
+ animation.animator.currentPlayTime = animationTime.toLong()
+ val currentValue = view.toAnimationValues()
+ assert(currentValue == valueToMatch) {
+ "The value of the animation $currentValue at $animationTime time (milliseconds) doesn't match the given value $valueToMatch"
+ }
+ }
+
+ @Test
+ fun testAnimationModePreview() {
+ testAnimationAtGivenProgress(
+ PREVIEW_DURATION * 0,
+ ReorderPreviewAnimation.MODE_PREVIEW,
+ AnimationValues(dx = 0, dy = 0, scale = 100)
+ )
+ testAnimationAtGivenProgress(
+ PREVIEW_DURATION / 2,
+ ReorderPreviewAnimation.MODE_PREVIEW,
+ AnimationValues(dx = 2, dy = -5, scale = 98)
+ )
+ testAnimationAtGivenProgress(
+ PREVIEW_DURATION / 3,
+ ReorderPreviewAnimation.MODE_PREVIEW,
+ AnimationValues(dx = 1, dy = -2, scale = 99)
+ )
+ testAnimationAtGivenProgress(
+ PREVIEW_DURATION,
+ ReorderPreviewAnimation.MODE_PREVIEW,
+ AnimationValues(dx = 5, dy = -10, scale = 96)
+ )
+
+ // MODE_PREVIEW oscillates and goes back to 0,0
+ testAnimationAtGivenProgress(
+ PREVIEW_DURATION * 2,
+ ReorderPreviewAnimation.MODE_PREVIEW,
+ AnimationValues(dx = 0, dy = 0, scale = 100)
+ )
+ testAnimationAtGivenProgress(
+ PREVIEW_DURATION * 99,
+ ReorderPreviewAnimation.MODE_PREVIEW,
+ AnimationValues(dx = 5, dy = -10, scale = 96)
+ )
+ testAnimationAtGivenProgress(
+ PREVIEW_DURATION * 98,
+ ReorderPreviewAnimation.MODE_PREVIEW,
+ AnimationValues(dx = 0, dy = 0, scale = 100)
+ )
+ testAnimationAtGivenProgress(
+ (PREVIEW_DURATION * 1.5).toInt(),
+ ReorderPreviewAnimation.MODE_PREVIEW,
+ AnimationValues(dx = 2, dy = -5, scale = 98)
+ )
+ }
+
+ @Test
+ fun testAnimationModeHint() {
+ testAnimationAtGivenProgress(
+ HINT_DURATION * 0,
+ ReorderPreviewAnimation.MODE_HINT,
+ AnimationValues(dx = 0, dy = 0, scale = 100)
+ )
+ testAnimationAtGivenProgress(
+ HINT_DURATION,
+ ReorderPreviewAnimation.MODE_HINT,
+ AnimationValues(dx = -5, dy = 10, scale = 96)
+ )
+ testAnimationAtGivenProgress(
+ HINT_DURATION / 2,
+ ReorderPreviewAnimation.MODE_HINT,
+ AnimationValues(dx = -2, dy = 5, scale = 98)
+ )
+ testAnimationAtGivenProgress(
+ HINT_DURATION / 3,
+ ReorderPreviewAnimation.MODE_HINT,
+ AnimationValues(dx = -1, dy = 2, scale = 99)
+ )
+ testAnimationAtGivenProgress(
+ HINT_DURATION,
+ ReorderPreviewAnimation.MODE_HINT,
+ AnimationValues(dx = -5, dy = 10, scale = 96)
+ )
+
+ // After one cycle the animationValues should always be the top values and don't cycle.
+ testAnimationAtGivenProgress(
+ HINT_DURATION * 2,
+ ReorderPreviewAnimation.MODE_HINT,
+ AnimationValues(dx = -5, dy = 10, scale = 96)
+ )
+ testAnimationAtGivenProgress(
+ HINT_DURATION * 99,
+ ReorderPreviewAnimation.MODE_HINT,
+ AnimationValues(dx = -5, dy = 10, scale = 96)
+ )
+ }
+}
diff --git a/tests/src/com/android/launcher3/celllayout/UnitTestCellLayoutBuilderRule.kt b/tests/src/com/android/launcher3/celllayout/UnitTestCellLayoutBuilderRule.kt
new file mode 100644
index 0000000..0f0dd65
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/UnitTestCellLayoutBuilderRule.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.celllayout
+
+import android.content.Context
+import android.graphics.Point
+import android.view.View
+import androidx.test.core.app.ApplicationProvider
+import com.android.launcher3.CellLayout
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.InvariantDeviceProfile
+import com.android.launcher3.MultipageCellLayout
+import com.android.launcher3.util.ActivityContextWrapper
+import org.junit.rules.TestWatcher
+import org.junit.runner.Description
+
+/**
+ * Create CellLayouts to be used in Unit testing and make sure to set the DeviceProfile back to
+ * normal.
+ */
+class UnitTestCellLayoutBuilderRule : TestWatcher() {
+
+ private var prevNumColumns = 0
+ private var prevNumRows = 0
+
+ private val applicationContext =
+ ActivityContextWrapper(ApplicationProvider.getApplicationContext())
+
+ override fun starting(description: Description?) {
+ val dp = getDeviceProfile()
+ prevNumColumns = dp.inv.numColumns
+ prevNumRows = dp.inv.numRows
+ }
+
+ override fun finished(description: Description?) {
+ val dp = getDeviceProfile()
+ dp.inv.numColumns = prevNumColumns
+ dp.inv.numRows = prevNumRows
+ }
+
+ fun createCellLayout(width: Int, height: Int, isMulti: Boolean): CellLayout {
+ val dp = getDeviceProfile()
+ // modify the device profile.
+ dp.inv.numColumns = if (isMulti) width / 2 else width
+ dp.inv.numRows = height
+ dp.cellLayoutBorderSpacePx = Point(0, 0)
+ val cl =
+ if (isMulti) MultipageCellLayout(getWrappedContext(applicationContext, dp))
+ else CellLayout(getWrappedContext(applicationContext, dp))
+ // I put a very large number for width and height so that all the items can fit, it doesn't
+ // need to be exact, just bigger than the sum of cell border
+ cl.measure(
+ View.MeasureSpec.makeMeasureSpec(10000, View.MeasureSpec.EXACTLY),
+ View.MeasureSpec.makeMeasureSpec(10000, View.MeasureSpec.EXACTLY)
+ )
+ return cl
+ }
+
+ private fun getDeviceProfile(): DeviceProfile =
+ InvariantDeviceProfile.INSTANCE[applicationContext].getDeviceProfile(applicationContext)
+ .copy(applicationContext)
+
+ private fun getWrappedContext(context: Context, dp: DeviceProfile): Context {
+ return object : ActivityContextWrapper(context) {
+ override fun getDeviceProfile(): DeviceProfile {
+ return dp
+ }
+ }
+ }
+}
diff --git a/tests/src/com/android/launcher3/compat/TaplPromiseIconUiTest.java b/tests/src/com/android/launcher3/compat/TaplPromiseIconUiTest.java
index f1b0441..7ed0fa5 100644
--- a/tests/src/com/android/launcher3/compat/TaplPromiseIconUiTest.java
+++ b/tests/src/com/android/launcher3/compat/TaplPromiseIconUiTest.java
@@ -19,9 +19,6 @@
import static com.google.common.truth.Truth.assertThat;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
import android.content.pm.PackageInstaller.SessionParams;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
@@ -170,13 +167,6 @@
mSessionId = -1;
}
- // Dummy receiver to fulfill archiving platform requirements, unused in reality.
- public static class UnarchiveBroadcastReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- }
- }
-
private void installDummyAppAndWaitForUIUpdate() throws IOException {
TestUtil.installDummyApp();
mLauncher.waitForModelQueueCleared();
diff --git a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
index cb57918..e2ca31f 100644
--- a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
+++ b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
@@ -95,6 +95,10 @@
@Test
fun loadsDataProperly() =
with(BgDataModel()) {
+ val MAIN_HANDLE = UserHandle.of(0)
+ val mockUserHandles = arrayListOf<UserHandle>(MAIN_HANDLE)
+ `when`(userCache.userProfiles).thenReturn(mockUserHandles)
+ `when`(userCache.getUserInfo(MAIN_HANDLE)).thenReturn(UserIconInfo(MAIN_HANDLE, 1))
LoaderTask(app, bgAllAppsList, this, modelDelegate, launcherBinder)
.runSyncOnBackgroundThread()
Truth.assertThat(workspaceItems.size).isAtLeast(25)