Snap for 12129055 from 72054af897 to 24Q4-release
Change-Id: Ia49f83819d4568729ba35092805013548c937a31
This commit is contained in:
@@ -19,10 +19,9 @@ import static android.view.View.VISIBLE;
|
||||
|
||||
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.window.flags.Flags.enableDesktopWindowingWallpaperActivity;
|
||||
import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.WALLPAPER_ACTIVITY;
|
||||
|
||||
import android.os.Debug;
|
||||
import android.os.SystemProperties;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
@@ -145,7 +144,7 @@ public class DesktopVisibilityController {
|
||||
notifyDesktopVisibilityListeners(areDesktopTasksVisibleNow);
|
||||
}
|
||||
|
||||
if (!enableDesktopWindowingWallpaperActivity() && wasVisible != isVisible) {
|
||||
if (!WALLPAPER_ACTIVITY.isEnabled(mLauncher) && wasVisible != isVisible) {
|
||||
// TODO: b/333533253 - Remove after flag rollout
|
||||
if (mVisibleDesktopTasksCount > 0) {
|
||||
setLauncherViewsVisibility(View.INVISIBLE);
|
||||
@@ -189,7 +188,7 @@ public class DesktopVisibilityController {
|
||||
notifyDesktopVisibilityListeners(areDesktopTasksVisibleNow);
|
||||
}
|
||||
|
||||
if (enableDesktopWindowingWallpaperActivity()) {
|
||||
if (WALLPAPER_ACTIVITY.isEnabled(mLauncher)) {
|
||||
return;
|
||||
}
|
||||
// TODO: b/333533253 - Clean up after flag rollout
|
||||
@@ -289,7 +288,7 @@ public class DesktopVisibilityController {
|
||||
* TODO: b/333533253 - Remove after flag rollout
|
||||
*/
|
||||
private void setLauncherViewsVisibility(int visibility) {
|
||||
if (enableDesktopWindowingWallpaperActivity()) {
|
||||
if (WALLPAPER_ACTIVITY.isEnabled(mLauncher)) {
|
||||
return;
|
||||
}
|
||||
if (DEBUG) {
|
||||
@@ -314,7 +313,7 @@ public class DesktopVisibilityController {
|
||||
* TODO: b/333533253 - Remove after flag rollout
|
||||
*/
|
||||
private void markLauncherPaused() {
|
||||
if (enableDesktopWindowingWallpaperActivity()) {
|
||||
if (WALLPAPER_ACTIVITY.isEnabled(mLauncher)) {
|
||||
return;
|
||||
}
|
||||
if (DEBUG) {
|
||||
@@ -331,7 +330,7 @@ public class DesktopVisibilityController {
|
||||
* TODO: b/333533253 - Remove after flag rollout
|
||||
*/
|
||||
private void markLauncherResumed() {
|
||||
if (enableDesktopWindowingWallpaperActivity()) {
|
||||
if (WALLPAPER_ACTIVITY.isEnabled(mLauncher)) {
|
||||
return;
|
||||
}
|
||||
if (DEBUG) {
|
||||
|
||||
@@ -21,7 +21,7 @@ import static com.android.launcher3.taskbar.TaskbarEduTooltipControllerKt.TOOLTI
|
||||
import static com.android.launcher3.taskbar.TaskbarLauncherStateController.FLAG_VISIBLE;
|
||||
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IGNORE_IN_APP;
|
||||
import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
|
||||
import static com.android.window.flags.Flags.enableDesktopWindowingWallpaperActivity;
|
||||
import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.WALLPAPER_ACTIVITY;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
@@ -214,7 +214,7 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
|
||||
|
||||
DesktopVisibilityController desktopController =
|
||||
LauncherActivityInterface.INSTANCE.getDesktopVisibilityController();
|
||||
if (!enableDesktopWindowingWallpaperActivity()
|
||||
if (!WALLPAPER_ACTIVITY.isEnabled(mLauncher)
|
||||
&& desktopController != null
|
||||
&& desktopController.areDesktopTasksVisible()) {
|
||||
// TODO: b/333533253 - Remove after flag rollout
|
||||
|
||||
@@ -315,6 +315,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
|
||||
new TaskbarTranslationController(this),
|
||||
new TaskbarSpringOnStashController(this),
|
||||
new TaskbarRecentAppsController(
|
||||
this,
|
||||
RecentsModel.INSTANCE.get(this),
|
||||
LauncherActivityInterface.INSTANCE::getDesktopVisibilityController),
|
||||
TaskbarEduTooltipController.newInstance(this),
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.android.launcher3.taskbar
|
||||
|
||||
import android.content.Context
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import com.android.launcher3.Flags.enableRecentsInTaskbar
|
||||
import com.android.launcher3.model.data.ItemInfo
|
||||
@@ -26,8 +27,8 @@ import com.android.launcher3.util.CancellableTask
|
||||
import com.android.quickstep.RecentsModel
|
||||
import com.android.quickstep.util.DesktopTask
|
||||
import com.android.quickstep.util.GroupTask
|
||||
import com.android.window.flags.Flags.enableDesktopWindowingMode
|
||||
import com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps
|
||||
import com.android.wm.shell.shared.desktopmode.DesktopModeFlags.DESKTOP_WINDOWING_MODE
|
||||
import java.io.PrintWriter
|
||||
|
||||
/**
|
||||
@@ -36,6 +37,7 @@ import java.io.PrintWriter
|
||||
* - When in Desktop Mode: show the currently running (open) Tasks
|
||||
*/
|
||||
class TaskbarRecentAppsController(
|
||||
context: Context,
|
||||
private val recentsModel: RecentsModel,
|
||||
// Pass a provider here instead of the actual DesktopVisibilityController instance since that
|
||||
// instance might not be available when this constructor is called.
|
||||
@@ -44,7 +46,7 @@ class TaskbarRecentAppsController(
|
||||
|
||||
// TODO(b/335401172): unify DesktopMode checks in Launcher.
|
||||
var canShowRunningApps =
|
||||
enableDesktopWindowingMode() && enableDesktopWindowingTaskbarRunningApps()
|
||||
DESKTOP_WINDOWING_MODE.isEnabled(context) && enableDesktopWindowingTaskbarRunningApps()
|
||||
@VisibleForTesting
|
||||
set(isEnabledFromTest) {
|
||||
field = isEnabledFromTest
|
||||
|
||||
@@ -64,10 +64,10 @@ import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent
|
||||
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.QUICK_SWITCH_FROM_HOME_FALLBACK;
|
||||
import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback;
|
||||
import static com.android.quickstep.util.SplitAnimationTimings.TABLET_HOME_TO_SPLIT;
|
||||
import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.WALLPAPER_ACTIVITY;
|
||||
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
|
||||
import static com.android.window.flags.Flags.enableDesktopWindowingMode;
|
||||
import static com.android.window.flags.Flags.enableDesktopWindowingWallpaperActivity;
|
||||
import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50;
|
||||
import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.DESKTOP_WINDOWING_MODE;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
@@ -201,6 +201,8 @@ import com.android.systemui.unfold.dagger.UnfoldMain;
|
||||
import com.android.systemui.unfold.progress.RemoteUnfoldTransitionReceiver;
|
||||
import com.android.systemui.unfold.updates.RotationChangeProvider;
|
||||
|
||||
import kotlin.Unit;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
@@ -213,8 +215,6 @@ import java.util.function.BiConsumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import kotlin.Unit;
|
||||
|
||||
public class QuickstepLauncher extends Launcher implements RecentsViewContainer {
|
||||
private static final boolean TRACE_LAYOUTS =
|
||||
SystemProperties.getBoolean("persist.debug.trace_layouts", false);
|
||||
@@ -276,7 +276,7 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer
|
||||
// TODO(b/337863494): Explore use of the same OverviewComponentObserver across launcher
|
||||
OverviewComponentObserver overviewComponentObserver = new OverviewComponentObserver(
|
||||
asContext(), deviceState);
|
||||
if (enableDesktopWindowingMode()) {
|
||||
if (DESKTOP_WINDOWING_MODE.isEnabled(this)) {
|
||||
mDesktopRecentsTransitionController = new DesktopRecentsTransitionController(
|
||||
getStateManager(), systemUiProxy, getIApplicationThread(),
|
||||
getDepthController());
|
||||
@@ -296,7 +296,7 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer
|
||||
|
||||
mTISBindHelper = new TISBindHelper(this, this::onTISConnected);
|
||||
mDepthController = new DepthController(this);
|
||||
if (enableDesktopWindowingMode()) {
|
||||
if (DESKTOP_WINDOWING_MODE.isEnabled(this)) {
|
||||
mDesktopVisibilityController = new DesktopVisibilityController(this);
|
||||
mDesktopVisibilityController.registerSystemUiListener();
|
||||
mSplitSelectStateController.initSplitFromDesktopController(this,
|
||||
@@ -1004,7 +1004,7 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer
|
||||
|
||||
@Override
|
||||
public void setResumed() {
|
||||
if (!enableDesktopWindowingWallpaperActivity()
|
||||
if (!WALLPAPER_ACTIVITY.isEnabled(this)
|
||||
&& mDesktopVisibilityController != null
|
||||
&& mDesktopVisibilityController.areDesktopTasksVisible()
|
||||
&& !mDesktopVisibilityController.isRecentsGestureInProgress()) {
|
||||
|
||||
@@ -62,6 +62,8 @@ import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent
|
||||
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.ON_SETTLED_ON_END_TARGET;
|
||||
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
|
||||
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
|
||||
import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.DESKTOP_WINDOWING_MODE;
|
||||
import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.WALLPAPER_ACTIVITY;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
@@ -152,6 +154,8 @@ import com.android.window.flags.Flags;
|
||||
import com.android.wm.shell.common.TransactionPool;
|
||||
import com.android.wm.shell.startingsurface.SplashScreenExitAnimationUtils;
|
||||
|
||||
import kotlin.Unit;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
@@ -161,8 +165,6 @@ import java.util.Optional;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import kotlin.Unit;
|
||||
|
||||
/**
|
||||
* Handles the navigation gestures when Launcher is the default home activity.
|
||||
*/
|
||||
@@ -952,7 +954,7 @@ public abstract class AbsSwipeUpHandler<T extends RecentsViewContainer,
|
||||
public void onRecentsAnimationStart(RecentsAnimationController controller,
|
||||
RecentsAnimationTargets targets) {
|
||||
super.onRecentsAnimationStart(controller, targets);
|
||||
if (targets.hasDesktopTasks()) {
|
||||
if (targets.hasDesktopTasks(mContext)) {
|
||||
mRemoteTargetHandles = mTargetGluer.assignTargetsForDesktop(targets);
|
||||
} else {
|
||||
int untrimmedAppCount = mRemoteTargetHandles.length;
|
||||
@@ -1272,8 +1274,8 @@ public abstract class AbsSwipeUpHandler<T extends RecentsViewContainer,
|
||||
TaskView currentPageTaskView = mRecentsView != null
|
||||
? mRecentsView.getCurrentPageTaskView() : null;
|
||||
|
||||
if (Flags.enableDesktopWindowingMode()
|
||||
&& !(Flags.enableDesktopWindowingWallpaperActivity()
|
||||
if (DESKTOP_WINDOWING_MODE.isEnabled(mContext)
|
||||
&& !(WALLPAPER_ACTIVITY.isEnabled(mContext)
|
||||
&& Flags.enableDesktopWindowingQuickSwitch())) {
|
||||
if ((nextPageTaskView instanceof DesktopTaskView
|
||||
|| currentPageTaskView instanceof DesktopTaskView)
|
||||
@@ -1445,8 +1447,8 @@ public abstract class AbsSwipeUpHandler<T extends RecentsViewContainer,
|
||||
setClampScrollOffset(false);
|
||||
};
|
||||
|
||||
if (Flags.enableDesktopWindowingMode()
|
||||
&& !(Flags.enableDesktopWindowingWallpaperActivity()
|
||||
if (DESKTOP_WINDOWING_MODE.isEnabled(mContext)
|
||||
&& !(WALLPAPER_ACTIVITY.isEnabled(mContext)
|
||||
&& Flags.enableDesktopWindowingQuickSwitch())) {
|
||||
if (mRecentsView != null && (mRecentsView.getCurrentPageTaskView() != null
|
||||
&& !(mRecentsView.getCurrentPageTaskView() instanceof DesktopTaskView))) {
|
||||
@@ -2293,8 +2295,8 @@ public abstract class AbsSwipeUpHandler<T extends RecentsViewContainer,
|
||||
mRecentsAnimationController, mRecentsAnimationTargets);
|
||||
});
|
||||
|
||||
if (Flags.enableDesktopWindowingMode()
|
||||
&& !(Flags.enableDesktopWindowingWallpaperActivity()
|
||||
if (DESKTOP_WINDOWING_MODE.isEnabled(mContext)
|
||||
&& !(WALLPAPER_ACTIVITY.isEnabled(mContext)
|
||||
&& Flags.enableDesktopWindowingQuickSwitch())) {
|
||||
if (mRecentsView.getNextPageTaskView() instanceof DesktopTaskView
|
||||
|| mRecentsView.getCurrentPageTaskView() instanceof DesktopTaskView) {
|
||||
|
||||
@@ -20,13 +20,14 @@ import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
|
||||
|
||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||
import static com.android.quickstep.util.SplitScreenUtils.convertShellSplitBoundsToLauncher;
|
||||
import static com.android.window.flags.Flags.enableDesktopWindowingMode;
|
||||
import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.DESKTOP_WINDOWING_MODE;
|
||||
import static com.android.wm.shell.util.GroupedRecentTaskInfo.TYPE_FREEFORM;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.KeyguardManager;
|
||||
import android.app.TaskInfo;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.util.SparseBooleanArray;
|
||||
@@ -58,6 +59,7 @@ public class RecentTasksList {
|
||||
|
||||
private static final TaskLoadResult INVALID_RESULT = new TaskLoadResult(-1, false, 0);
|
||||
|
||||
private final Context mContext;
|
||||
private final KeyguardManager mKeyguardManager;
|
||||
private final LooperExecutor mMainThreadExecutor;
|
||||
private final SystemUiProxy mSysUiProxy;
|
||||
@@ -76,8 +78,10 @@ public class RecentTasksList {
|
||||
// Tasks are stored in order of least recently launched to most recently launched.
|
||||
private ArrayList<ActivityManager.RunningTaskInfo> mRunningTasks;
|
||||
|
||||
public RecentTasksList(LooperExecutor mainThreadExecutor, KeyguardManager keyguardManager,
|
||||
SystemUiProxy sysUiProxy, TopTaskTracker topTaskTracker) {
|
||||
public RecentTasksList(Context context, LooperExecutor mainThreadExecutor,
|
||||
KeyguardManager keyguardManager, SystemUiProxy sysUiProxy,
|
||||
TopTaskTracker topTaskTracker) {
|
||||
mContext = context;
|
||||
mMainThreadExecutor = mainThreadExecutor;
|
||||
mKeyguardManager = keyguardManager;
|
||||
mChangeId = 1;
|
||||
@@ -325,9 +329,9 @@ public class RecentTasksList {
|
||||
int numVisibleTasks = 0;
|
||||
for (GroupedRecentTaskInfo rawTask : rawTasks) {
|
||||
if (rawTask.getType() == TYPE_FREEFORM) {
|
||||
// TYPE_FREEFORM tasks is only created when enableDesktopWindowingMode() is true,
|
||||
// TYPE_FREEFORM tasks is only created whenDESKTOP_WINDOWING_MODE.isEnabled is true,
|
||||
// leftover TYPE_FREEFORM tasks created when flag was on should be ignored.
|
||||
if (enableDesktopWindowingMode()) {
|
||||
if (DESKTOP_WINDOWING_MODE.isEnabled(mContext)) {
|
||||
GroupTask desktopTask = createDesktopTask(rawTask);
|
||||
if (desktopTask != null) {
|
||||
allTasks.add(desktopTask);
|
||||
|
||||
@@ -27,7 +27,7 @@ import static com.android.launcher3.testing.shared.TestProtocol.OVERVIEW_STATE_O
|
||||
import static com.android.quickstep.OverviewComponentObserver.startHomeIntentSafely;
|
||||
import static com.android.quickstep.TaskUtils.taskIsATargetWithMode;
|
||||
import static com.android.quickstep.TaskViewUtils.createRecentsWindowAnimator;
|
||||
import static com.android.window.flags.Flags.enableDesktopWindowingMode;
|
||||
import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.DESKTOP_WINDOWING_MODE;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
@@ -147,7 +147,7 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> implem
|
||||
mActionsView = findViewById(R.id.overview_actions_view);
|
||||
getRootView().getSysUiScrim().getSysUIProgress().updateValue(0);
|
||||
mDragLayer.recreateControllers();
|
||||
if (enableDesktopWindowingMode()) {
|
||||
if (DESKTOP_WINDOWING_MODE.isEnabled(this)) {
|
||||
mDesktopRecentsTransitionController = new DesktopRecentsTransitionController(
|
||||
getStateManager(), systemUiProxy, getIApplicationThread(),
|
||||
null /* depthController */
|
||||
|
||||
@@ -18,9 +18,10 @@ package com.android.quickstep;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
|
||||
import static android.view.RemoteAnimationTarget.MODE_CLOSING;
|
||||
|
||||
import static com.android.window.flags.Flags.enableDesktopWindowingMode;
|
||||
import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.DESKTOP_WINDOWING_MODE;
|
||||
|
||||
import android.app.WindowConfiguration;
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Bundle;
|
||||
import android.view.RemoteAnimationTarget;
|
||||
@@ -54,8 +55,8 @@ public class RecentsAnimationTargets extends RemoteAnimationTargets {
|
||||
*
|
||||
* @return {@code true} if at least one target app is a desktop task
|
||||
*/
|
||||
public boolean hasDesktopTasks() {
|
||||
if (!enableDesktopWindowingMode()) {
|
||||
public boolean hasDesktopTasks(Context context) {
|
||||
if (!DESKTOP_WINDOWING_MODE.isEnabled(context)) {
|
||||
return false;
|
||||
}
|
||||
for (RemoteAnimationTarget target : apps) {
|
||||
|
||||
@@ -90,7 +90,9 @@ public class RecentsModel implements RecentTasksDataSource, IconChangeListener,
|
||||
|
||||
private RecentsModel(Context context, IconProvider iconProvider) {
|
||||
this(context,
|
||||
new RecentTasksList(MAIN_EXECUTOR,
|
||||
new RecentTasksList(
|
||||
context,
|
||||
MAIN_EXECUTOR,
|
||||
context.getSystemService(KeyguardManager.class),
|
||||
SystemUiProxy.INSTANCE.get(context),
|
||||
TopTaskTracker.INSTANCE.get(context)),
|
||||
|
||||
@@ -23,8 +23,8 @@ import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||
import static com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
|
||||
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.RECENT_TASKS_MISSING;
|
||||
import static com.android.quickstep.util.LogUtils.splitFailureMessage;
|
||||
import static com.android.window.flags.Flags.enableDesktopWindowingMode;
|
||||
import static com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps;
|
||||
import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.DESKTOP_WINDOWING_MODE;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityOptions;
|
||||
@@ -1444,7 +1444,8 @@ public class SystemUiProxy implements ISystemUiProxy, NavHandle, SafeCloseable {
|
||||
|
||||
private boolean shouldEnableRunningTasksForDesktopMode() {
|
||||
// TODO(b/335401172): unify DesktopMode checks in Launcher
|
||||
return enableDesktopWindowingMode() && enableDesktopWindowingTaskbarRunningApps();
|
||||
return DESKTOP_WINDOWING_MODE.isEnabled(mContext)
|
||||
&& enableDesktopWindowingTaskbarRunningApps();
|
||||
}
|
||||
|
||||
private boolean handleMessageAsync(Message msg) {
|
||||
|
||||
@@ -17,18 +17,28 @@
|
||||
package com.android.quickstep.util;
|
||||
|
||||
import static com.android.app.animation.Interpolators.clampToProgress;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
|
||||
import android.animation.AnimatorSet;
|
||||
import android.annotation.NonNull;
|
||||
import android.os.Bundle;
|
||||
import android.os.IRemoteCallback;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.android.launcher3.logging.StatsLogManager;
|
||||
import com.android.launcher3.statemanager.BaseState;
|
||||
import com.android.launcher3.statemanager.StateManager;
|
||||
import com.android.launcher3.states.StateAnimationConfig;
|
||||
import com.android.launcher3.util.RunnableList;
|
||||
import com.android.quickstep.views.RecentsViewContainer;
|
||||
|
||||
/**
|
||||
* Utility class containing methods to help manage animations, interpolators, and timings.
|
||||
*/
|
||||
public class AnimUtils {
|
||||
private static final int DURATION_DEFAULT_SPLIT_DISMISS = 350;
|
||||
|
||||
/**
|
||||
* Fetches device-specific timings for the Overview > Split animation
|
||||
* (splitscreen initiated from Overview).
|
||||
@@ -58,6 +68,33 @@ public class AnimUtils {
|
||||
: SplitAnimationTimings.PHONE_APP_PAIR_LAUNCH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronizes the timing for the split dismiss animation to the current transition to
|
||||
* NORMAL (launcher home/workspace)
|
||||
*/
|
||||
public static void goToNormalStateWithSplitDismissal(@NonNull StateManager stateManager,
|
||||
@NonNull RecentsViewContainer container,
|
||||
@NonNull StatsLogManager.LauncherEvent exitReason,
|
||||
@NonNull SplitAnimationController animationController) {
|
||||
StateAnimationConfig config = new StateAnimationConfig();
|
||||
BaseState startState = stateManager.getState();
|
||||
long duration = startState.getTransitionDuration(container.asContext(),
|
||||
false /*isToState*/);
|
||||
if (duration == 0) {
|
||||
// Case where we're in contextual on workspace (NORMAL), which by default has 0
|
||||
// transition duration
|
||||
duration = DURATION_DEFAULT_SPLIT_DISMISS;
|
||||
}
|
||||
config.duration = duration;
|
||||
AnimatorSet stateAnim = stateManager.createAtomicAnimation(
|
||||
startState, NORMAL, config);
|
||||
AnimatorSet dismissAnim = animationController
|
||||
.createPlaceholderDismissAnim(container, exitReason, duration);
|
||||
stateAnim.play(dismissAnim);
|
||||
stateManager.setCurrentAnimation(stateAnim, NORMAL);
|
||||
stateAnim.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a IRemoteCallback which completes the provided list as a result
|
||||
*/
|
||||
|
||||
@@ -26,7 +26,7 @@ import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
|
||||
import static com.android.launcher3.LauncherState.SPRING_LOADED;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_HOME;
|
||||
import static com.android.window.flags.Flags.enableDesktopWindowingWallpaperActivity;
|
||||
import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.WALLPAPER_ACTIVITY;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
@@ -54,6 +54,7 @@ import com.android.quickstep.GestureState;
|
||||
import com.android.quickstep.LauncherActivityInterface;
|
||||
import com.android.quickstep.RotationTouchHelper;
|
||||
import com.android.quickstep.SystemUiProxy;
|
||||
import com.android.quickstep.util.AnimUtils;
|
||||
import com.android.quickstep.util.SplitSelectStateController;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
|
||||
@@ -91,10 +92,12 @@ public class LauncherRecentsView extends RecentsView<QuickstepLauncher, Launcher
|
||||
protected void handleStartHome(boolean animated) {
|
||||
StateManager stateManager = getStateManager();
|
||||
animated &= stateManager.shouldAnimateStateChange();
|
||||
stateManager.goToState(NORMAL, animated);
|
||||
if (FeatureFlags.enableSplitContextually()) {
|
||||
mSplitSelectStateController.getSplitAnimationController()
|
||||
.playPlaceholderDismissAnim(mContainer, LAUNCHER_SPLIT_SELECTION_EXIT_HOME);
|
||||
if (mSplitSelectStateController.isSplitSelectActive()) {
|
||||
AnimUtils.goToNormalStateWithSplitDismissal(stateManager, mContainer,
|
||||
LAUNCHER_SPLIT_SELECTION_EXIT_HOME,
|
||||
mSplitSelectStateController.getSplitAnimationController());
|
||||
} else {
|
||||
stateManager.goToState(NORMAL, animated);
|
||||
}
|
||||
AbstractFloatingView.closeAllOpenViews(mContainer, animated);
|
||||
}
|
||||
@@ -265,7 +268,7 @@ public class LauncherRecentsView extends RecentsView<QuickstepLauncher, Launcher
|
||||
super.onGestureAnimationStart(runningTasks, rotationTouchHelper);
|
||||
DesktopVisibilityController desktopVisibilityController =
|
||||
mContainer.getDesktopVisibilityController();
|
||||
if (!enableDesktopWindowingWallpaperActivity() && desktopVisibilityController != null) {
|
||||
if (!WALLPAPER_ACTIVITY.isEnabled(mContext) && desktopVisibilityController != null) {
|
||||
// TODO: b/333533253 - Remove after flag rollout
|
||||
desktopVisibilityController.setRecentsGestureStart();
|
||||
}
|
||||
@@ -288,7 +291,7 @@ public class LauncherRecentsView extends RecentsView<QuickstepLauncher, Launcher
|
||||
}
|
||||
}
|
||||
super.onGestureAnimationEnd();
|
||||
if (!enableDesktopWindowingWallpaperActivity() && desktopVisibilityController != null) {
|
||||
if (!WALLPAPER_ACTIVITY.isEnabled(mContext) && desktopVisibilityController != null) {
|
||||
// TODO: b/333533253 - Remove after flag rollout
|
||||
desktopVisibilityController.setRecentsGestureEnd(endTarget);
|
||||
}
|
||||
|
||||
@@ -5498,7 +5498,7 @@ public abstract class RecentsView<CONTAINER_TYPE extends Context & RecentsViewCo
|
||||
}
|
||||
|
||||
RemoteTargetGluer gluer;
|
||||
if (recentsAnimationTargets.hasDesktopTasks()) {
|
||||
if (recentsAnimationTargets.hasDesktopTasks(mContext)) {
|
||||
gluer = new RemoteTargetGluer(getContext(), getSizeStrategy(), recentsAnimationTargets,
|
||||
true /* forDesktop */);
|
||||
mRemoteTargetHandles = gluer.assignTargetsForDesktop(recentsAnimationTargets);
|
||||
|
||||
@@ -16,13 +16,11 @@
|
||||
|
||||
package com.android.quickstep.views;
|
||||
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_CANCEL_BUTTON;
|
||||
import static com.android.settingslib.widget.theme.R.dimen.settingslib_preferred_minimum_touch_target;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
@@ -42,9 +40,8 @@ import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.PendingAnimation;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.statemanager.BaseState;
|
||||
import com.android.launcher3.statemanager.StateManager;
|
||||
import com.android.launcher3.states.StateAnimationConfig;
|
||||
import com.android.quickstep.util.AnimUtils;
|
||||
import com.android.quickstep.util.SplitSelectStateController;
|
||||
|
||||
/**
|
||||
@@ -57,7 +54,6 @@ import com.android.quickstep.util.SplitSelectStateController;
|
||||
public class SplitInstructionsView extends LinearLayout {
|
||||
private static final int BOUNCE_DURATION = 250;
|
||||
private static final float BOUNCE_HEIGHT = 20;
|
||||
private static final int DURATION_DEFAULT_SPLIT_DISMISS = 350;
|
||||
|
||||
private final RecentsViewContainer mContainer;
|
||||
public boolean mIsCurrentlyAnimating = false;
|
||||
@@ -165,25 +161,11 @@ public class SplitInstructionsView extends LinearLayout {
|
||||
private void exitSplitSelection() {
|
||||
RecentsView recentsView = mContainer.getOverviewPanel();
|
||||
SplitSelectStateController splitSelectController = recentsView.getSplitSelectController();
|
||||
|
||||
StateManager stateManager = recentsView.getStateManager();
|
||||
BaseState startState = stateManager.getState();
|
||||
long duration = startState.getTransitionDuration(mContainer.asContext(), false);
|
||||
if (duration == 0) {
|
||||
// Case where we're in contextual on workspace (NORMAL), which by default has 0
|
||||
// transition duration
|
||||
duration = DURATION_DEFAULT_SPLIT_DISMISS;
|
||||
}
|
||||
StateAnimationConfig config = new StateAnimationConfig();
|
||||
config.duration = duration;
|
||||
AnimatorSet stateAnim = stateManager.createAtomicAnimation(
|
||||
startState, NORMAL, config);
|
||||
AnimatorSet dismissAnim = splitSelectController.getSplitAnimationController()
|
||||
.createPlaceholderDismissAnim(mContainer,
|
||||
LAUNCHER_SPLIT_SELECTION_EXIT_CANCEL_BUTTON, duration);
|
||||
stateAnim.play(dismissAnim);
|
||||
stateManager.setCurrentAnimation(stateAnim, NORMAL);
|
||||
stateAnim.start();
|
||||
|
||||
AnimUtils.goToNormalStateWithSplitDismissal(stateManager, mContainer,
|
||||
LAUNCHER_SPLIT_SELECTION_EXIT_CANCEL_BUTTON,
|
||||
splitSelectController.getSplitAnimationController());
|
||||
}
|
||||
|
||||
void ensureProperRotation() {
|
||||
|
||||
+5
-1
@@ -18,6 +18,7 @@ package com.android.launcher3.taskbar
|
||||
|
||||
import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Process
|
||||
import android.os.UserHandle
|
||||
@@ -56,6 +57,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() {
|
||||
|
||||
@Mock private lateinit var mockIconCache: TaskIconCache
|
||||
@Mock private lateinit var mockRecentsModel: RecentsModel
|
||||
@Mock private lateinit var mockContext: Context
|
||||
@Mock private lateinit var mockDesktopVisibilityController: DesktopVisibilityController
|
||||
|
||||
private var taskListChangeId: Int = 1
|
||||
@@ -71,7 +73,9 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() {
|
||||
|
||||
whenever(mockRecentsModel.iconCache).thenReturn(mockIconCache)
|
||||
recentAppsController =
|
||||
TaskbarRecentAppsController(mockRecentsModel) { mockDesktopVisibilityController }
|
||||
TaskbarRecentAppsController(mockContext, mockRecentsModel) {
|
||||
mockDesktopVisibilityController
|
||||
}
|
||||
recentAppsController.init(taskbarControllers)
|
||||
recentAppsController.canShowRunningApps = true
|
||||
recentAppsController.canShowRecentApps = true
|
||||
|
||||
@@ -29,6 +29,7 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.KeyguardManager;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
@@ -54,7 +55,9 @@ import java.util.stream.Collectors;
|
||||
public class RecentTasksListTest {
|
||||
|
||||
@Mock
|
||||
private SystemUiProxy mockSystemUiProxy;
|
||||
private Context mContext;
|
||||
@Mock
|
||||
private SystemUiProxy mSystemUiProxy;
|
||||
@Mock
|
||||
private TopTaskTracker mTopTaskTracker;
|
||||
|
||||
@@ -66,14 +69,14 @@ public class RecentTasksListTest {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
LooperExecutor mockMainThreadExecutor = mock(LooperExecutor.class);
|
||||
KeyguardManager mockKeyguardManager = mock(KeyguardManager.class);
|
||||
mRecentTasksList = new RecentTasksList(mockMainThreadExecutor, mockKeyguardManager,
|
||||
mockSystemUiProxy, mTopTaskTracker);
|
||||
mRecentTasksList = new RecentTasksList(mContext, mockMainThreadExecutor,
|
||||
mockKeyguardManager, mSystemUiProxy, mTopTaskTracker);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onRecentTasksChanged_doesNotFetchTasks() throws Exception {
|
||||
mRecentTasksList.onRecentTasksChanged();
|
||||
verify(mockSystemUiProxy, times(0))
|
||||
verify(mSystemUiProxy, times(0))
|
||||
.getRecentTasks(anyInt(), anyInt());
|
||||
}
|
||||
|
||||
@@ -81,7 +84,7 @@ public class RecentTasksListTest {
|
||||
public void loadTasksInBackground_onlyKeys_noValidTaskDescription() throws Exception {
|
||||
GroupedRecentTaskInfo recentTaskInfos = GroupedRecentTaskInfo.forSplitTasks(
|
||||
new ActivityManager.RecentTaskInfo(), new ActivityManager.RecentTaskInfo(), null);
|
||||
when(mockSystemUiProxy.getRecentTasks(anyInt(), anyInt()))
|
||||
when(mSystemUiProxy.getRecentTasks(anyInt(), anyInt()))
|
||||
.thenReturn(new ArrayList<>(Collections.singletonList(recentTaskInfos)));
|
||||
|
||||
List<GroupTask> taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, -1,
|
||||
@@ -94,7 +97,7 @@ public class RecentTasksListTest {
|
||||
|
||||
@Test
|
||||
public void loadTasksInBackground_GetRecentTasksException() throws Exception {
|
||||
when(mockSystemUiProxy.getRecentTasks(anyInt(), anyInt()))
|
||||
when(mSystemUiProxy.getRecentTasks(anyInt(), anyInt()))
|
||||
.thenThrow(new SystemUiProxy.GetRecentTasksException("task load failed"));
|
||||
|
||||
RecentTasksList.TaskLoadResult taskList = mRecentTasksList.loadTasksInBackground(
|
||||
@@ -113,7 +116,7 @@ public class RecentTasksListTest {
|
||||
task2.taskDescription = new ActivityManager.TaskDescription();
|
||||
GroupedRecentTaskInfo recentTaskInfos = GroupedRecentTaskInfo.forSplitTasks(task1, task2,
|
||||
null);
|
||||
when(mockSystemUiProxy.getRecentTasks(anyInt(), anyInt()))
|
||||
when(mSystemUiProxy.getRecentTasks(anyInt(), anyInt()))
|
||||
.thenReturn(new ArrayList<>(Collections.singletonList(recentTaskInfos)));
|
||||
|
||||
List<GroupTask> taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, -1,
|
||||
@@ -132,7 +135,7 @@ public class RecentTasksListTest {
|
||||
createRecentTaskInfo(5 /* taskId */)};
|
||||
GroupedRecentTaskInfo recentTaskInfos = GroupedRecentTaskInfo.forFreeformTasks(
|
||||
tasks, Collections.emptySet() /* minimizedTaskIds */);
|
||||
when(mockSystemUiProxy.getRecentTasks(anyInt(), anyInt()))
|
||||
when(mSystemUiProxy.getRecentTasks(anyInt(), anyInt()))
|
||||
.thenReturn(new ArrayList<>(Collections.singletonList(recentTaskInfos)));
|
||||
|
||||
List<GroupTask> taskList = mRecentTasksList.loadTasksInBackground(
|
||||
@@ -158,7 +161,7 @@ public class RecentTasksListTest {
|
||||
Arrays.stream(new Integer[]{1, 4, 5}).collect(Collectors.toSet());
|
||||
GroupedRecentTaskInfo recentTaskInfos =
|
||||
GroupedRecentTaskInfo.forFreeformTasks(tasks, minimizedTaskIds);
|
||||
when(mockSystemUiProxy.getRecentTasks(anyInt(), anyInt()))
|
||||
when(mSystemUiProxy.getRecentTasks(anyInt(), anyInt()))
|
||||
.thenReturn(new ArrayList<>(Collections.singletonList(recentTaskInfos)));
|
||||
|
||||
List<GroupTask> taskList = mRecentTasksList.loadTasksInBackground(
|
||||
|
||||
@@ -22,8 +22,5 @@
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="?attr/materialColorSurfaceContainerLow" />
|
||||
<padding
|
||||
android:left="@dimen/rounded_button_padding"
|
||||
android:right="@dimen/rounded_button_padding" />
|
||||
</shape>
|
||||
|
||||
|
||||
@@ -44,8 +44,7 @@
|
||||
<FrameLayout
|
||||
android:layout_width="@dimen/rounded_button_width"
|
||||
android:layout_height="@dimen/rounded_button_width"
|
||||
android:background="@drawable/rounded_action_button"
|
||||
android:padding="@dimen/rounded_button_padding">
|
||||
android:background="@drawable/rounded_action_button">
|
||||
<ImageButton
|
||||
android:id="@+id/action_btn"
|
||||
android:layout_width="@dimen/x_icon_size"
|
||||
|
||||
@@ -172,8 +172,6 @@
|
||||
<dimen name="padded_rounded_button_height">48dp</dimen>
|
||||
<dimen name="rounded_button_height">48dp</dimen>
|
||||
<dimen name="rounded_button_radius">200dp</dimen>
|
||||
<dimen name="rounded_button_padding">8dp</dimen>
|
||||
|
||||
|
||||
<!-- Widget tray -->
|
||||
<dimen name="widget_cell_vertical_padding">8dp</dimen>
|
||||
|
||||
@@ -746,7 +746,8 @@ public final class Utilities {
|
||||
* | +--+ |
|
||||
* | |
|
||||
* +----------------+
|
||||
* This would be case delta % 4 == 2:
|
||||
* This would be case delta % 4 == 2: // This is case was reverted to previous behaviour which
|
||||
* doesn't match the illustration due to b/353965234
|
||||
* +-------------+
|
||||
* | |
|
||||
* | |
|
||||
@@ -768,7 +769,6 @@ public final class Utilities {
|
||||
int delta) {
|
||||
int rdelta = ((delta % 4) + 4) % 4;
|
||||
int origLeft = inOutBounds.left;
|
||||
int origTop = inOutBounds.top;
|
||||
switch (rdelta) {
|
||||
case 0:
|
||||
return;
|
||||
@@ -780,8 +780,6 @@ public final class Utilities {
|
||||
return;
|
||||
case 2:
|
||||
inOutBounds.left = parentWidth - inOutBounds.right;
|
||||
inOutBounds.top = parentHeight - inOutBounds.bottom;
|
||||
inOutBounds.bottom = parentHeight - origTop;
|
||||
inOutBounds.right = parentWidth - origLeft;
|
||||
return;
|
||||
case 3:
|
||||
|
||||
@@ -262,11 +262,12 @@ public class AllAppsStore<T extends Context & ActivityContext> {
|
||||
writer.println(prefix + "\tAllAppsStore Apps[] size: " + mApps.length);
|
||||
for (int i = 0; i < mApps.length; i++) {
|
||||
writer.println(String.format(Locale.getDefault(),
|
||||
"%s\tPackage index, name, and class: " + "%d/%s:%s",
|
||||
"%s\tPackage index, name, class, and description: %d/%s:%s, %s",
|
||||
prefix,
|
||||
i,
|
||||
mApps[i].componentName.getPackageName(),
|
||||
mApps[i].componentName.getClassName()));
|
||||
mApps[i].componentName.getClassName(),
|
||||
mApps[i].contentDescription));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ import androidx.annotation.Nullable;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import com.android.launcher3.Flags;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.util.PackageUserKey;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
@@ -183,6 +183,11 @@ public class UserCache implements SafeCloseable {
|
||||
mUserToSerialMap.put(userHandle, info);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void putToPreInstallCache(UserHandle userHandle, List<String> preInstalledApps) {
|
||||
mUserToPreInstallAppMap.put(userHandle, preInstalledApps);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UserManager#getUserProfiles()
|
||||
*/
|
||||
|
||||
@@ -76,4 +76,5 @@ public class LogConfig {
|
||||
* When turned on, we enable zero state web data loader related logging.
|
||||
*/
|
||||
public static final String ZERO_WEB_DATA_LOADER = "ZeroStateWebDataLoaderLog";
|
||||
public static final String SEARCH_TARGET_UTIL_LOG = "SearchTargetUtilLog";
|
||||
}
|
||||
|
||||
@@ -376,9 +376,10 @@ class UtilitiesTest {
|
||||
Utilities.rotateBounds(rect, 100, 100, 1)
|
||||
assertEquals(Rect(70, 40, 80, 80), rect)
|
||||
|
||||
rect = Rect(20, 70, 60, 80)
|
||||
Utilities.rotateBounds(rect, 100, 100, 2)
|
||||
assertEquals(Rect(40, 20, 80, 30), rect)
|
||||
// case removed for b/28435189
|
||||
// rect = Rect(20, 70, 60, 80)
|
||||
// Utilities.rotateBounds(rect, 100, 100, 2)
|
||||
// assertEquals(Rect(40, 20, 80, 30), rect)
|
||||
|
||||
rect = Rect(20, 70, 60, 80)
|
||||
Utilities.rotateBounds(rect, 100, 100, 3)
|
||||
|
||||
@@ -23,6 +23,7 @@ import android.os.Handler
|
||||
import android.os.Looper
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.SmallTest
|
||||
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
|
||||
import com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import java.util.function.Consumer
|
||||
@@ -114,6 +115,7 @@ class SimpleBroadcastReceiverTest {
|
||||
underTest = SimpleBroadcastReceiver(Handler(Looper.getMainLooper()), intentConsumer)
|
||||
|
||||
underTest.register(context, completionRunnable, 1, "test_action_1", "test_action_2")
|
||||
getInstrumentation().waitForIdleSync()
|
||||
|
||||
verify(context).registerReceiver(same(underTest), intentFilterCaptor.capture(), eq(1))
|
||||
verify(completionRunnable).run()
|
||||
@@ -136,6 +138,7 @@ class SimpleBroadcastReceiverTest {
|
||||
underTest = SimpleBroadcastReceiver(Handler(Looper.getMainLooper()), intentConsumer)
|
||||
|
||||
underTest.unregisterReceiverSafely(context)
|
||||
getInstrumentation().waitForIdleSync()
|
||||
|
||||
verify(context).unregisterReceiver(same(underTest))
|
||||
}
|
||||
|
||||
@@ -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.folder
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.launcher3.folder.FolderNameInfos.*
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
data class Label(val index: Int, val label: String, val score: Float)
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class FolderNameInfosTest {
|
||||
|
||||
companion object {
|
||||
val statusList =
|
||||
listOf(
|
||||
SUCCESS,
|
||||
HAS_PRIMARY,
|
||||
HAS_SUGGESTIONS,
|
||||
ERROR_NO_PROVIDER,
|
||||
ERROR_APP_LOOKUP_FAILED,
|
||||
ERROR_ALL_APP_LOOKUP_FAILED,
|
||||
ERROR_NO_LABELS_GENERATED,
|
||||
ERROR_LABEL_LOOKUP_FAILED,
|
||||
ERROR_ALL_LABEL_LOOKUP_FAILED,
|
||||
ERROR_NO_PACKAGES,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun status() {
|
||||
assertStatus(statusList)
|
||||
assertStatus(
|
||||
listOf(
|
||||
ERROR_NO_PROVIDER,
|
||||
ERROR_APP_LOOKUP_FAILED,
|
||||
ERROR_ALL_APP_LOOKUP_FAILED,
|
||||
ERROR_NO_LABELS_GENERATED,
|
||||
ERROR_LABEL_LOOKUP_FAILED,
|
||||
ERROR_ALL_LABEL_LOOKUP_FAILED,
|
||||
ERROR_NO_PACKAGES,
|
||||
)
|
||||
)
|
||||
assertStatus(
|
||||
listOf(
|
||||
SUCCESS,
|
||||
HAS_PRIMARY,
|
||||
HAS_SUGGESTIONS,
|
||||
)
|
||||
)
|
||||
assertStatus(
|
||||
listOf(
|
||||
SUCCESS,
|
||||
HAS_PRIMARY,
|
||||
HAS_SUGGESTIONS,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun assertStatus(statusList: List<Int>) {
|
||||
var infos = FolderNameInfos()
|
||||
statusList.forEach { infos.setStatus(it) }
|
||||
assert(infos.status() == statusList.sum()) {
|
||||
"There is an overlap on the status constants!"
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun hasPrimary() {
|
||||
assertHasPrimary(
|
||||
createNameInfos(listOf(Label(0, "label", 1f)), statusList),
|
||||
hasPrimary = true
|
||||
)
|
||||
assertHasPrimary(
|
||||
createNameInfos(listOf(Label(1, "label", 1f)), statusList),
|
||||
hasPrimary = false
|
||||
)
|
||||
assertHasPrimary(
|
||||
createNameInfos(
|
||||
listOf(Label(0, "label", 1f)),
|
||||
listOf(
|
||||
ERROR_NO_PROVIDER,
|
||||
ERROR_APP_LOOKUP_FAILED,
|
||||
ERROR_ALL_APP_LOOKUP_FAILED,
|
||||
ERROR_NO_LABELS_GENERATED,
|
||||
ERROR_LABEL_LOOKUP_FAILED,
|
||||
ERROR_ALL_LABEL_LOOKUP_FAILED,
|
||||
ERROR_NO_PACKAGES,
|
||||
)
|
||||
),
|
||||
hasPrimary = false
|
||||
)
|
||||
}
|
||||
|
||||
private fun assertHasPrimary(nameInfos: FolderNameInfos, hasPrimary: Boolean) =
|
||||
assert(nameInfos.hasPrimary() == hasPrimary)
|
||||
|
||||
private fun createNameInfos(labels: List<Label>?, statusList: List<Int>?): FolderNameInfos {
|
||||
val infos = FolderNameInfos()
|
||||
labels?.forEach { infos.setLabel(it.index, it.label, it.score) }
|
||||
statusList?.forEach { infos.setStatus(it) }
|
||||
return infos
|
||||
}
|
||||
|
||||
@Test
|
||||
fun hasSuggestions() {
|
||||
assertHasSuggestions(
|
||||
createNameInfos(listOf(Label(0, "label", 1f)), null),
|
||||
hasSuggestions = true
|
||||
)
|
||||
assertHasSuggestions(createNameInfos(null, null), hasSuggestions = false)
|
||||
// There is a max of 4 suggestions
|
||||
assertHasSuggestions(
|
||||
createNameInfos(listOf(Label(5, "label", 1f)), null),
|
||||
hasSuggestions = false
|
||||
)
|
||||
assertHasSuggestions(
|
||||
createNameInfos(
|
||||
listOf(
|
||||
Label(0, "label", 1f),
|
||||
Label(1, "label", 1f),
|
||||
Label(2, "label", 1f),
|
||||
Label(3, "label", 1f)
|
||||
),
|
||||
null
|
||||
),
|
||||
hasSuggestions = true
|
||||
)
|
||||
}
|
||||
|
||||
private fun assertHasSuggestions(nameInfos: FolderNameInfos, hasSuggestions: Boolean) =
|
||||
assert(nameInfos.hasSuggestions() == hasSuggestions)
|
||||
|
||||
@Test
|
||||
fun hasContains() {
|
||||
assertContains(
|
||||
createNameInfos(
|
||||
listOf(
|
||||
Label(0, "label1", 1f),
|
||||
Label(1, "label2", 1f),
|
||||
Label(2, "label3", 1f),
|
||||
Label(3, "label4", 1f)
|
||||
),
|
||||
null
|
||||
),
|
||||
label = Label(-1, "label3", -1f),
|
||||
contains = true
|
||||
)
|
||||
assertContains(
|
||||
createNameInfos(
|
||||
listOf(
|
||||
Label(0, "label1", 1f),
|
||||
Label(1, "label2", 1f),
|
||||
Label(2, "label3", 1f),
|
||||
Label(3, "label4", 1f)
|
||||
),
|
||||
null
|
||||
),
|
||||
label = Label(-1, "label5", -1f),
|
||||
contains = false
|
||||
)
|
||||
assertContains(
|
||||
createNameInfos(null, null),
|
||||
label = Label(-1, "label1", -1f),
|
||||
contains = false
|
||||
)
|
||||
assertContains(
|
||||
createNameInfos(
|
||||
listOf(
|
||||
Label(0, "label1", 1f),
|
||||
Label(1, "label2", 1f),
|
||||
Label(2, "lAbel3", 1f),
|
||||
Label(3, "lEbel4", 1f)
|
||||
),
|
||||
null
|
||||
),
|
||||
label = Label(-1, "LaBEl3", -1f),
|
||||
contains = true
|
||||
)
|
||||
}
|
||||
|
||||
private fun assertContains(nameInfos: FolderNameInfos, label: Label, contains: Boolean) =
|
||||
assert(nameInfos.contains(label.label) == contains)
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* 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.pm
|
||||
|
||||
import android.content.pm.LauncherApps
|
||||
import android.content.pm.PackageInstaller
|
||||
import android.os.Build
|
||||
import android.os.UserHandle
|
||||
import android.platform.test.annotations.EnableFlags
|
||||
import android.platform.test.flag.junit.SetFlagsRule
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.SdkSuppress
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.launcher3.Flags.FLAG_ENABLE_SUPPORT_FOR_ARCHIVING
|
||||
import com.android.launcher3.util.Executors.MODEL_EXECUTOR
|
||||
import com.android.launcher3.util.LauncherModelHelper
|
||||
import com.android.launcher3.util.PackageUserKey
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.kotlin.any
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.spy
|
||||
import org.mockito.kotlin.verify
|
||||
import org.mockito.kotlin.whenever
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class InstallSessionTrackerTest {
|
||||
@get:Rule val setFlagsRule = SetFlagsRule()
|
||||
|
||||
private val mockInstallSessionHelper: InstallSessionHelper = mock()
|
||||
private val mockCallback: InstallSessionTracker.Callback = mock()
|
||||
private val mockPackageInstaller: PackageInstaller = mock()
|
||||
|
||||
private val launcherModelHelper = LauncherModelHelper()
|
||||
private val sandboxContext = launcherModelHelper.sandboxContext
|
||||
|
||||
lateinit var launcherApps: LauncherApps
|
||||
lateinit var installSessionTracker: InstallSessionTracker
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
launcherApps = sandboxContext.spyService(LauncherApps::class.java)
|
||||
installSessionTracker =
|
||||
InstallSessionTracker(
|
||||
mockInstallSessionHelper,
|
||||
mockCallback,
|
||||
mockPackageInstaller,
|
||||
launcherApps
|
||||
)
|
||||
}
|
||||
|
||||
@After
|
||||
fun teardown() {
|
||||
launcherModelHelper.destroy()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `onCreated triggers callbacks for setting up new install session`() {
|
||||
// Given
|
||||
val expectedSessionId = 1
|
||||
val expectedSession =
|
||||
PackageInstaller.SessionInfo().apply {
|
||||
sessionId = expectedSessionId
|
||||
appPackageName = "appPackageName"
|
||||
userId = 0
|
||||
}
|
||||
val expectedPackageKey = PackageUserKey("appPackageName", UserHandle(0))
|
||||
whenever(mockInstallSessionHelper.getVerifiedSessionInfo(expectedSessionId))
|
||||
.thenReturn(expectedSession)
|
||||
// When
|
||||
installSessionTracker.onCreated(expectedSessionId)
|
||||
// Then
|
||||
verify(mockCallback).onInstallSessionCreated(any())
|
||||
verify(mockCallback).onUpdateSessionDisplay(expectedPackageKey, expectedSession)
|
||||
verify(mockInstallSessionHelper).tryQueuePromiseAppIcon(expectedSession)
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableFlags(FLAG_ENABLE_SUPPORT_FOR_ARCHIVING)
|
||||
fun `onCreated for unarchival triggers onPackageStateChanged`() {
|
||||
// Given
|
||||
val expectedSessionId = 1
|
||||
val expectedSession =
|
||||
spy(PackageInstaller.SessionInfo()).apply {
|
||||
sessionId = expectedSessionId
|
||||
appPackageName = "appPackageName"
|
||||
userId = 0
|
||||
whenever(isUnarchival).thenReturn(true)
|
||||
}
|
||||
whenever(mockInstallSessionHelper.getVerifiedSessionInfo(expectedSessionId))
|
||||
.thenReturn(expectedSession)
|
||||
// When
|
||||
installSessionTracker.onCreated(expectedSessionId)
|
||||
// Then
|
||||
verify(mockCallback).onPackageStateChanged(any())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `onFinished triggers onPackageStateChanged if session found in cache`() {
|
||||
// Given
|
||||
val expectedSessionId = 1
|
||||
val expectedSession =
|
||||
PackageInstaller.SessionInfo().apply {
|
||||
sessionId = expectedSessionId
|
||||
appPackageName = "appPackageName"
|
||||
userId = 0
|
||||
}
|
||||
val expectedPackageKey = PackageUserKey("appPackageName", UserHandle(0))
|
||||
whenever(mockInstallSessionHelper.getVerifiedSessionInfo(expectedSessionId))
|
||||
.thenReturn(expectedSession)
|
||||
whenever(mockInstallSessionHelper.activeSessions)
|
||||
.thenReturn(hashMapOf(expectedPackageKey to expectedSession))
|
||||
// When
|
||||
installSessionTracker.onFinished(expectedSessionId, /* success */ true)
|
||||
// Then
|
||||
verify(mockCallback).onPackageStateChanged(any())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `onFinished failure calls onSessionFailure and promise icon removal for existing icon`() {
|
||||
// Given
|
||||
val expectedSessionId = 1
|
||||
val expectedPackage = "appPackageName"
|
||||
val expectedSession =
|
||||
PackageInstaller.SessionInfo().apply {
|
||||
sessionId = expectedSessionId
|
||||
appPackageName = expectedPackage
|
||||
userId = 0
|
||||
}
|
||||
val expectedPackageKey = PackageUserKey(expectedPackage, UserHandle(0))
|
||||
whenever(mockInstallSessionHelper.getVerifiedSessionInfo(expectedSessionId))
|
||||
.thenReturn(expectedSession)
|
||||
whenever(mockInstallSessionHelper.activeSessions)
|
||||
.thenReturn(hashMapOf(expectedPackageKey to expectedSession))
|
||||
whenever(mockInstallSessionHelper.promiseIconAddedForId(expectedSessionId)).thenReturn(true)
|
||||
// When
|
||||
installSessionTracker.onFinished(expectedSessionId, /* success */ false)
|
||||
// Then
|
||||
verify(mockCallback).onSessionFailure(expectedPackage, expectedPackageKey.mUser)
|
||||
verify(mockInstallSessionHelper).removePromiseIconId(expectedSessionId)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `onProgressChanged triggers onPackageStateChanged if verified session found`() {
|
||||
// Given
|
||||
val expectedSessionId = 1
|
||||
val expectedSession =
|
||||
PackageInstaller.SessionInfo().apply {
|
||||
sessionId = expectedSessionId
|
||||
appPackageName = "appPackageName"
|
||||
userId = 0
|
||||
}
|
||||
whenever(mockInstallSessionHelper.getVerifiedSessionInfo(expectedSessionId))
|
||||
.thenReturn(expectedSession)
|
||||
// When
|
||||
installSessionTracker.onProgressChanged(expectedSessionId, /* progress */ 50f)
|
||||
// Then
|
||||
verify(mockCallback).onPackageStateChanged(any())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `onBadgingChanged triggers session display update and queues promise icon if verified`() {
|
||||
// Given
|
||||
val expectedSessionId = 1
|
||||
val expectedSession =
|
||||
PackageInstaller.SessionInfo().apply {
|
||||
sessionId = expectedSessionId
|
||||
appPackageName = "appPackageName"
|
||||
userId = 0
|
||||
}
|
||||
val expectedPackageKey = PackageUserKey("appPackageName", UserHandle(0))
|
||||
whenever(mockInstallSessionHelper.getVerifiedSessionInfo(expectedSessionId))
|
||||
.thenReturn(expectedSession)
|
||||
// When
|
||||
installSessionTracker.onBadgingChanged(expectedSessionId)
|
||||
// Then
|
||||
verify(mockCallback).onUpdateSessionDisplay(expectedPackageKey, expectedSession)
|
||||
verify(mockInstallSessionHelper).tryQueuePromiseAppIcon(expectedSession)
|
||||
}
|
||||
|
||||
@Test
|
||||
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
|
||||
fun `register triggers registerPackageInstallerSessionCallback for versions from Q`() {
|
||||
// Given
|
||||
whenever(
|
||||
launcherApps.registerPackageInstallerSessionCallback(
|
||||
MODEL_EXECUTOR,
|
||||
installSessionTracker
|
||||
)
|
||||
)
|
||||
.then { /* no-op */ }
|
||||
// When
|
||||
installSessionTracker.register()
|
||||
// Then
|
||||
verify(launcherApps)
|
||||
.registerPackageInstallerSessionCallback(MODEL_EXECUTOR, installSessionTracker)
|
||||
}
|
||||
|
||||
@Test
|
||||
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
|
||||
fun `unregister triggers unregisterPackageInstallerSessionCallback for versions from Q`() {
|
||||
// Given
|
||||
whenever(launcherApps.unregisterPackageInstallerSessionCallback(installSessionTracker))
|
||||
.then { /* no-op */ }
|
||||
// When
|
||||
installSessionTracker.unregister()
|
||||
// Then
|
||||
verify(launcherApps).unregisterPackageInstallerSessionCallback(installSessionTracker)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* 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.pm
|
||||
|
||||
import android.os.Process.myUserHandle
|
||||
import android.os.UserHandle
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import com.android.launcher3.util.Executors.MODEL_EXECUTOR
|
||||
import com.android.launcher3.util.LauncherModelHelper
|
||||
import com.android.launcher3.util.TestUtil
|
||||
import com.android.launcher3.util.UserIconInfo
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class UserCacheTest {
|
||||
private val launcherModelHelper = LauncherModelHelper()
|
||||
private val sandboxContext = launcherModelHelper.sandboxContext
|
||||
private lateinit var userCache: UserCache
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
userCache = UserCache.getInstance(sandboxContext)
|
||||
}
|
||||
|
||||
@After
|
||||
fun teardown() {
|
||||
launcherModelHelper.destroy()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getBadgeDrawable only returns a UserBadgeDrawable given a user in the cache`() {
|
||||
// Given
|
||||
val expectedIconInfo = UserIconInfo(myUserHandle(), UserIconInfo.TYPE_WORK)
|
||||
TestUtil.runOnExecutorSync(MODEL_EXECUTOR) {
|
||||
userCache.putToCache(myUserHandle(), expectedIconInfo)
|
||||
}
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync()
|
||||
// When
|
||||
val actualDrawable = UserCache.getBadgeDrawable(sandboxContext, myUserHandle())
|
||||
val unexpectedDrawable = UserCache.getBadgeDrawable(sandboxContext, UserHandle(66))
|
||||
// Then
|
||||
assertThat(actualDrawable).isNotNull()
|
||||
assertThat(unexpectedDrawable).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getPreInstallApps returns list of pre installed apps given a user`() {
|
||||
// Given
|
||||
val expectedApps = listOf("Google")
|
||||
TestUtil.runOnExecutorSync(MODEL_EXECUTOR) {
|
||||
userCache.putToPreInstallCache(myUserHandle(), expectedApps)
|
||||
}
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync()
|
||||
// When
|
||||
val actualApps = userCache.getPreInstallApps(myUserHandle())
|
||||
// Then
|
||||
assertThat(actualApps).isEqualTo(expectedApps)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getUserProfiles returns copy of UserCache profiles`() {
|
||||
// Given
|
||||
val expectedProfiles = listOf(myUserHandle())
|
||||
val expectedIconInfo = UserIconInfo(myUserHandle(), UserIconInfo.TYPE_MAIN)
|
||||
TestUtil.runOnExecutorSync(MODEL_EXECUTOR) {
|
||||
userCache.putToCache(myUserHandle(), expectedIconInfo)
|
||||
}
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync()
|
||||
// When
|
||||
val actualProfiles = userCache.userProfiles
|
||||
// Then
|
||||
assertThat(actualProfiles).isEqualTo(expectedProfiles)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getUserForSerialNumber returns user key matching given entry serial number`() {
|
||||
// Given
|
||||
val expectedSerial = 42L
|
||||
val expectedProfile = UserHandle(42)
|
||||
val expectedIconInfo = UserIconInfo(myUserHandle(), UserIconInfo.TYPE_MAIN, expectedSerial)
|
||||
TestUtil.runOnExecutorSync(MODEL_EXECUTOR) {
|
||||
userCache.putToCache(expectedProfile, expectedIconInfo)
|
||||
}
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync()
|
||||
// When
|
||||
val actualProfile = userCache.getUserForSerialNumber(expectedSerial)
|
||||
// Then
|
||||
assertThat(actualProfile).isEqualTo(expectedProfile)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getUserInfo returns cached UserIconInfo given user key`() {
|
||||
// Given
|
||||
val expectedProfile = UserHandle(1)
|
||||
val expectedIconInfo = UserIconInfo(myUserHandle(), UserIconInfo.TYPE_WORK)
|
||||
TestUtil.runOnExecutorSync(MODEL_EXECUTOR) {
|
||||
userCache.putToCache(expectedProfile, expectedIconInfo)
|
||||
}
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync()
|
||||
// When
|
||||
val actualIconInfo = userCache.getUserInfo(expectedProfile)
|
||||
// Then
|
||||
assertThat(actualIconInfo).isEqualTo(expectedIconInfo)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getSerialNumberForUser returns cached UserIconInfo serial number given user key`() {
|
||||
// Given
|
||||
val expectedSerial = 42L
|
||||
val expectedProfile = UserHandle(1)
|
||||
val expectedIconInfo = UserIconInfo(myUserHandle(), UserIconInfo.TYPE_WORK, expectedSerial)
|
||||
TestUtil.runOnExecutorSync(MODEL_EXECUTOR) {
|
||||
userCache.putToCache(expectedProfile, expectedIconInfo)
|
||||
}
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync()
|
||||
// When
|
||||
val actualSerial = userCache.getSerialNumberForUser(expectedProfile)
|
||||
// Then
|
||||
assertThat(actualSerial).isEqualTo(expectedSerial)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user