diff options
22 files changed, 499 insertions, 276 deletions
diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml index f03b7f66cdc8..30c3d50ed8ad 100644 --- a/libs/WindowManager/Shell/res/values/config.xml +++ b/libs/WindowManager/Shell/res/values/config.xml @@ -19,6 +19,10 @@ by the resources of the app using the Shell library. --> <bool name="config_enableShellMainThread">false</bool> + <!-- Determines whether to register the shell task organizer on init. + TODO(b/238217847): This config is temporary until we refactor the base WMComponent. --> + <bool name="config_registerShellTaskOrganizerOnInit">true</bool> + <!-- Animation duration for PIP when entering. --> <integer name="config_pipEnterAnimationDuration">425</integer> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java index 1c0e6f726fbf..756d80204833 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java @@ -20,6 +20,9 @@ import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET; import static android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW; +import static com.android.wm.shell.transition.TransitionAnimationHelper.addBackgroundToTransition; +import static com.android.wm.shell.transition.TransitionAnimationHelper.getTransitionBackgroundColorIfSet; + import android.animation.Animator; import android.animation.ValueAnimator; import android.content.Context; @@ -42,7 +45,6 @@ import com.android.wm.shell.transition.Transitions; import java.util.ArrayList; import java.util.List; import java.util.Set; -import java.util.function.BiFunction; /** To run the ActivityEmbedding animations. */ class ActivityEmbeddingAnimationRunner { @@ -85,7 +87,7 @@ class ActivityEmbeddingAnimationRunner { @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Runnable animationFinishCallback) { final List<ActivityEmbeddingAnimationAdapter> adapters = - createAnimationAdapters(info, startTransaction); + createAnimationAdapters(info, startTransaction, finishTransaction); long duration = 0; for (ActivityEmbeddingAnimationAdapter adapter : adapters) { duration = Math.max(duration, adapter.getDurationHint()); @@ -129,7 +131,8 @@ class ActivityEmbeddingAnimationRunner { */ @NonNull private List<ActivityEmbeddingAnimationAdapter> createAnimationAdapters( - @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction) { + @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, + @NonNull SurfaceControl.Transaction finishTransaction) { boolean isChangeTransition = false; for (TransitionInfo.Change change : info.getChanges()) { if (change.hasFlags(FLAG_IS_BEHIND_STARTING_WINDOW)) { @@ -145,23 +148,25 @@ class ActivityEmbeddingAnimationRunner { return createChangeAnimationAdapters(info, startTransaction); } if (Transitions.isClosingType(info.getType())) { - return createCloseAnimationAdapters(info); + return createCloseAnimationAdapters(info, startTransaction, finishTransaction); } - return createOpenAnimationAdapters(info); + return createOpenAnimationAdapters(info, startTransaction, finishTransaction); } @NonNull private List<ActivityEmbeddingAnimationAdapter> createOpenAnimationAdapters( - @NonNull TransitionInfo info) { - return createOpenCloseAnimationAdapters(info, true /* isOpening */, - mAnimationSpec::loadOpenAnimation); + @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, + @NonNull SurfaceControl.Transaction finishTransaction) { + return createOpenCloseAnimationAdapters(info, startTransaction, finishTransaction, + true /* isOpening */, mAnimationSpec::loadOpenAnimation); } @NonNull private List<ActivityEmbeddingAnimationAdapter> createCloseAnimationAdapters( - @NonNull TransitionInfo info) { - return createOpenCloseAnimationAdapters(info, false /* isOpening */, - mAnimationSpec::loadCloseAnimation); + @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, + @NonNull SurfaceControl.Transaction finishTransaction) { + return createOpenCloseAnimationAdapters(info, startTransaction, finishTransaction, + false /* isOpening */, mAnimationSpec::loadCloseAnimation); } /** @@ -170,8 +175,9 @@ class ActivityEmbeddingAnimationRunner { */ @NonNull private List<ActivityEmbeddingAnimationAdapter> createOpenCloseAnimationAdapters( - @NonNull TransitionInfo info, boolean isOpening, - @NonNull BiFunction<TransitionInfo.Change, Rect, Animation> animationProvider) { + @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, + @NonNull SurfaceControl.Transaction finishTransaction, boolean isOpening, + @NonNull AnimationProvider animationProvider) { // We need to know if the change window is only a partial of the whole animation screen. // If so, we will need to adjust it to make the whole animation screen looks like one. final List<TransitionInfo.Change> openingChanges = new ArrayList<>(); @@ -194,7 +200,8 @@ class ActivityEmbeddingAnimationRunner { final List<ActivityEmbeddingAnimationAdapter> adapters = new ArrayList<>(); for (TransitionInfo.Change change : openingChanges) { final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter( - change, animationProvider, openingWholeScreenBounds); + info, change, startTransaction, finishTransaction, animationProvider, + openingWholeScreenBounds); if (isOpening) { adapter.overrideLayer(offsetLayer++); } @@ -202,7 +209,8 @@ class ActivityEmbeddingAnimationRunner { } for (TransitionInfo.Change change : closingChanges) { final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter( - change, animationProvider, closingWholeScreenBounds); + info, change, startTransaction, finishTransaction, animationProvider, + closingWholeScreenBounds); if (!isOpening) { adapter.overrideLayer(offsetLayer++); } @@ -213,10 +221,18 @@ class ActivityEmbeddingAnimationRunner { @NonNull private ActivityEmbeddingAnimationAdapter createOpenCloseAnimationAdapter( - @NonNull TransitionInfo.Change change, - @NonNull BiFunction<TransitionInfo.Change, Rect, Animation> animationProvider, - @NonNull Rect wholeAnimationBounds) { - final Animation animation = animationProvider.apply(change, wholeAnimationBounds); + @NonNull TransitionInfo info, @NonNull TransitionInfo.Change change, + @NonNull SurfaceControl.Transaction startTransaction, + @NonNull SurfaceControl.Transaction finishTransaction, + @NonNull AnimationProvider animationProvider, @NonNull Rect wholeAnimationBounds) { + final Animation animation = animationProvider.get(info, change, wholeAnimationBounds); + // We may want to show a background color for open/close transition. + final int backgroundColor = getTransitionBackgroundColorIfSet(info, change, animation, + 0 /* defaultColor */); + if (backgroundColor != 0) { + addBackgroundToTransition(info.getRootLeash(), backgroundColor, startTransaction, + finishTransaction); + } return new ActivityEmbeddingAnimationAdapter(animation, change, change.getLeash(), wholeAnimationBounds); } @@ -322,4 +338,10 @@ class ActivityEmbeddingAnimationRunner { return ScreenshotUtils.takeScreenshot(t, screenshotChange.getLeash(), animationChange.getLeash(), cropBounds, Integer.MAX_VALUE); } + + /** To provide an {@link Animation} based on the transition infos. */ + private interface AnimationProvider { + Animation get(@NonNull TransitionInfo info, @NonNull TransitionInfo.Change change, + @NonNull Rect animationBounds); + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java index ad0dddf77002..eb6ac7615266 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java @@ -17,6 +17,9 @@ package com.android.wm.shell.activityembedding; +import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_NONE; +import static com.android.wm.shell.transition.TransitionAnimationHelper.loadAttributeAnimation; + import android.content.Context; import android.graphics.Point; import android.graphics.Rect; @@ -33,7 +36,6 @@ import android.window.TransitionInfo; import androidx.annotation.NonNull; -import com.android.internal.R; import com.android.internal.policy.TransitionAnimation; import com.android.wm.shell.transition.Transitions; @@ -175,16 +177,20 @@ class ActivityEmbeddingAnimationSpec { } @NonNull - Animation loadOpenAnimation(@NonNull TransitionInfo.Change change, - @NonNull Rect wholeAnimationBounds) { + Animation loadOpenAnimation(@NonNull TransitionInfo info, + @NonNull TransitionInfo.Change change, @NonNull Rect wholeAnimationBounds) { final boolean isEnter = Transitions.isOpeningType(change.getMode()); final Animation animation; - // TODO(b/207070762): - // 1. Implement clearTop version: R.anim.task_fragment_clear_top_close_enter/exit - // 2. Implement edgeExtension version - animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter - ? R.anim.task_fragment_open_enter - : R.anim.task_fragment_open_exit); + // TODO(b/207070762): Implement edgeExtension version + if (shouldShowBackdrop(info, change)) { + animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter + ? com.android.internal.R.anim.task_fragment_clear_top_open_enter + : com.android.internal.R.anim.task_fragment_clear_top_open_exit); + } else { + animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter + ? com.android.internal.R.anim.task_fragment_open_enter + : com.android.internal.R.anim.task_fragment_open_exit); + } // Use the whole animation bounds instead of the change bounds, so that when multiple change // targets are opening at the same time, the animation applied to each will be the same. // Otherwise, we may see gap between the activities that are launching together. @@ -195,16 +201,20 @@ class ActivityEmbeddingAnimationSpec { } @NonNull - Animation loadCloseAnimation(@NonNull TransitionInfo.Change change, - @NonNull Rect wholeAnimationBounds) { + Animation loadCloseAnimation(@NonNull TransitionInfo info, + @NonNull TransitionInfo.Change change, @NonNull Rect wholeAnimationBounds) { final boolean isEnter = Transitions.isOpeningType(change.getMode()); final Animation animation; - // TODO(b/207070762): - // 1. Implement clearTop version: R.anim.task_fragment_clear_top_close_enter/exit - // 2. Implement edgeExtension version - animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter - ? R.anim.task_fragment_close_enter - : R.anim.task_fragment_close_exit); + // TODO(b/207070762): Implement edgeExtension version + if (shouldShowBackdrop(info, change)) { + animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter + ? com.android.internal.R.anim.task_fragment_clear_top_close_enter + : com.android.internal.R.anim.task_fragment_clear_top_close_exit); + } else { + animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter + ? com.android.internal.R.anim.task_fragment_close_enter + : com.android.internal.R.anim.task_fragment_close_exit); + } // Use the whole animation bounds instead of the change bounds, so that when multiple change // targets are closing at the same time, the animation applied to each will be the same. // Otherwise, we may see gap between the activities that are finishing together. @@ -213,4 +223,11 @@ class ActivityEmbeddingAnimationSpec { animation.scaleCurrentDuration(mTransitionAnimationScaleSetting); return animation; } + + private boolean shouldShowBackdrop(@NonNull TransitionInfo info, + @NonNull TransitionInfo.Change change) { + final Animation a = loadAttributeAnimation(info, change, WALLPAPER_TRANSITION_NONE, + mTransitionAnimation); + return a != null && a.getShowBackdrop(); + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java index 80cdd1f79cb5..c25bbbf06dda 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java @@ -29,6 +29,7 @@ import android.view.WindowManager; import com.android.internal.logging.UiEventLogger; import com.android.launcher3.icons.IconProvider; import com.android.wm.shell.ProtoLogController; +import com.android.wm.shell.R; import com.android.wm.shell.RootDisplayAreaOrganizer; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; @@ -173,6 +174,7 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides static ShellTaskOrganizer provideShellTaskOrganizer( + Context context, ShellInit shellInit, ShellCommandHandler shellCommandHandler, CompatUIController compatUI, @@ -180,6 +182,10 @@ public abstract class WMShellBaseModule { Optional<RecentTasksController> recentTasksOptional, @ShellMainThread ShellExecutor mainExecutor ) { + if (!context.getResources().getBoolean(R.bool.config_registerShellTaskOrganizerOnInit)) { + // TODO(b/238217847): Force override shell init if registration is disabled + shellInit = new ShellInit(mainExecutor); + } return new ShellTaskOrganizer(shellInit, shellCommandHandler, compatUI, unfoldAnimationController, recentTasksOptional, mainExecutor); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java index 4c927b6e84b8..dbb2948de5db 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java @@ -18,13 +18,11 @@ package com.android.wm.shell.transition; import static android.app.ActivityOptions.ANIM_CLIP_REVEAL; import static android.app.ActivityOptions.ANIM_CUSTOM; -import static android.app.ActivityOptions.ANIM_FROM_STYLE; import static android.app.ActivityOptions.ANIM_NONE; import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS; import static android.app.ActivityOptions.ANIM_SCALE_UP; import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN; import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED; import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_TYPE; @@ -43,10 +41,11 @@ import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_RELAUNCH; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManager.TRANSIT_TO_FRONT; -import static android.view.WindowManager.transitTypeToString; import static android.window.TransitionInfo.FLAG_CROSS_PROFILE_OWNER_THUMBNAIL; import static android.window.TransitionInfo.FLAG_CROSS_PROFILE_WORK_THUMBNAIL; import static android.window.TransitionInfo.FLAG_DISPLAY_HAS_ALERT_WINDOWS; +import static android.window.TransitionInfo.FLAG_FILLS_TASK; +import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY; import static android.window.TransitionInfo.FLAG_IS_DISPLAY; import static android.window.TransitionInfo.FLAG_IS_VOICE_INTERACTION; import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; @@ -59,6 +58,10 @@ import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITI import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_INTRA_OPEN; import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_NONE; import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_OPEN; +import static com.android.wm.shell.transition.TransitionAnimationHelper.addBackgroundToTransition; +import static com.android.wm.shell.transition.TransitionAnimationHelper.getTransitionBackgroundColorIfSet; +import static com.android.wm.shell.transition.TransitionAnimationHelper.loadAttributeAnimation; +import static com.android.wm.shell.transition.TransitionAnimationHelper.sDisableCustomTaskAnimationProperty; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -74,7 +77,6 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.Insets; import android.graphics.Paint; import android.graphics.PixelFormat; @@ -84,7 +86,6 @@ import android.graphics.drawable.Drawable; import android.hardware.HardwareBuffer; import android.os.Handler; import android.os.IBinder; -import android.os.SystemProperties; import android.os.UserHandle; import android.util.ArrayMap; import android.view.Choreographer; @@ -122,21 +123,6 @@ import java.util.function.Consumer; public class DefaultTransitionHandler implements Transitions.TransitionHandler { private static final int MAX_ANIMATION_DURATION = 3000; - /** - * Restrict ability of activities overriding transition animation in a way such that - * an activity can do it only when the transition happens within a same task. - * - * @see android.app.Activity#overridePendingTransition(int, int) - */ - private static final String DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY = - "persist.wm.disable_custom_task_animation"; - - /** - * @see #DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY - */ - static boolean sDisableCustomTaskAnimationProperty = - SystemProperties.getBoolean(DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY, true); - private final TransactionPool mTransactionPool; private final DisplayController mDisplayController; private final Context mContext; @@ -384,8 +370,10 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { change.getEndAbsBounds().top - info.getRootOffset().y); // Seamless display transition doesn't need to animate. if (isSeamlessDisplayChange) continue; - if (isTask) { - // Skip non-tasks since those usually have null bounds. + if (isTask || (change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY) + && !change.hasFlags(FLAG_FILLS_TASK))) { + // Update Task and embedded split window crop bounds, otherwise we may see crop + // on previous bounds during the rotation animation. startTransaction.setWindowCrop(change.getLeash(), change.getEndAbsBounds().width(), change.getEndAbsBounds().height()); } @@ -431,22 +419,8 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { cornerRadius = 0; } - if (a.getShowBackdrop()) { - if (info.getAnimationOptions().getBackgroundColor() != 0) { - // If available use the background color provided through AnimationOptions - backgroundColorForTransition = - info.getAnimationOptions().getBackgroundColor(); - } else if (a.getBackdropColor() != 0) { - // Otherwise fallback on the background color provided through the animation - // definition. - backgroundColorForTransition = a.getBackdropColor(); - } else if (change.getBackgroundColor() != 0) { - // Otherwise default to the window's background color if provided through - // the theme as the background color for the animation - the top most window - // with a valid background color and showBackground set takes precedence. - backgroundColorForTransition = change.getBackgroundColor(); - } - } + backgroundColorForTransition = getTransitionBackgroundColorIfSet(info, change, a, + backgroundColorForTransition); boolean delayedEdgeExtension = false; if (!isTask && a.hasExtension()) { @@ -668,29 +642,6 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { return edgeExtensionLayer; } - private void addBackgroundToTransition( - @NonNull SurfaceControl rootLeash, - @ColorInt int color, - @NonNull SurfaceControl.Transaction startTransaction, - @NonNull SurfaceControl.Transaction finishTransaction - ) { - final Color bgColor = Color.valueOf(color); - final float[] colorArray = new float[] { bgColor.red(), bgColor.green(), bgColor.blue() }; - - final SurfaceControl animationBackgroundSurface = new SurfaceControl.Builder() - .setName("Animation Background") - .setParent(rootLeash) - .setColorLayer() - .setOpaque(true) - .build(); - - startTransaction - .setLayer(animationBackgroundSurface, Integer.MIN_VALUE) - .setColor(animationBackgroundSurface, colorArray) - .show(animationBackgroundSurface); - finishTransaction.remove(animationBackgroundSurface); - } - @Nullable @Override public WindowContainerTransaction handleRequest(@NonNull IBinder transition, @@ -704,9 +655,9 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { } @Nullable - private Animation loadAnimation(TransitionInfo info, TransitionInfo.Change change, - int wallpaperTransit) { - Animation a = null; + private Animation loadAnimation(@NonNull TransitionInfo info, + @NonNull TransitionInfo.Change change, int wallpaperTransit) { + Animation a; final int type = info.getType(); final int flags = info.getFlags(); @@ -717,12 +668,10 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { final boolean isTask = change.getTaskInfo() != null; final TransitionInfo.AnimationOptions options = info.getAnimationOptions(); final int overrideType = options != null ? options.getType() : ANIM_NONE; - final boolean canCustomContainer = isTask ? !sDisableCustomTaskAnimationProperty : true; + final boolean canCustomContainer = !isTask || !sDisableCustomTaskAnimationProperty; final Rect endBounds = Transitions.isClosingType(changeMode) ? mRotator.getEndBoundsInStartRotation(change) : change.getEndAbsBounds(); - final boolean isDream = - isTask && change.getTaskInfo().topActivityType == ACTIVITY_TYPE_DREAM; if (info.isKeyguardGoingAway()) { a = mTransitionAnimation.loadKeyguardExitAnimation(flags, @@ -763,87 +712,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { // This received a transferred starting window, so don't animate return null; } else { - int animAttr = 0; - boolean translucent = false; - if (isDream) { - if (type == TRANSIT_OPEN) { - animAttr = enter - ? R.styleable.WindowAnimation_dreamActivityOpenEnterAnimation - : R.styleable.WindowAnimation_dreamActivityOpenExitAnimation; - } else if (type == TRANSIT_CLOSE) { - animAttr = enter - ? 0 - : R.styleable.WindowAnimation_dreamActivityCloseExitAnimation; - } - } else if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_OPEN) { - animAttr = enter - ? R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation - : R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation; - } else if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_CLOSE) { - animAttr = enter - ? R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation - : R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation; - } else if (wallpaperTransit == WALLPAPER_TRANSITION_OPEN) { - animAttr = enter - ? R.styleable.WindowAnimation_wallpaperOpenEnterAnimation - : R.styleable.WindowAnimation_wallpaperOpenExitAnimation; - } else if (wallpaperTransit == WALLPAPER_TRANSITION_CLOSE) { - animAttr = enter - ? R.styleable.WindowAnimation_wallpaperCloseEnterAnimation - : R.styleable.WindowAnimation_wallpaperCloseExitAnimation; - } else if (type == TRANSIT_OPEN) { - // We will translucent open animation for translucent activities and tasks. Choose - // WindowAnimation_activityOpenEnterAnimation and set translucent here, then - // TransitionAnimation loads appropriate animation later. - if ((changeFlags & FLAG_TRANSLUCENT) != 0 && enter) { - translucent = true; - } - if (isTask && !translucent) { - animAttr = enter - ? R.styleable.WindowAnimation_taskOpenEnterAnimation - : R.styleable.WindowAnimation_taskOpenExitAnimation; - } else { - animAttr = enter - ? R.styleable.WindowAnimation_activityOpenEnterAnimation - : R.styleable.WindowAnimation_activityOpenExitAnimation; - } - } else if (type == TRANSIT_TO_FRONT) { - animAttr = enter - ? R.styleable.WindowAnimation_taskToFrontEnterAnimation - : R.styleable.WindowAnimation_taskToFrontExitAnimation; - } else if (type == TRANSIT_CLOSE) { - if (isTask) { - animAttr = enter - ? R.styleable.WindowAnimation_taskCloseEnterAnimation - : R.styleable.WindowAnimation_taskCloseExitAnimation; - } else { - if ((changeFlags & FLAG_TRANSLUCENT) != 0 && !enter) { - translucent = true; - } - animAttr = enter - ? R.styleable.WindowAnimation_activityCloseEnterAnimation - : R.styleable.WindowAnimation_activityCloseExitAnimation; - } - } else if (type == TRANSIT_TO_BACK) { - animAttr = enter - ? R.styleable.WindowAnimation_taskToBackEnterAnimation - : R.styleable.WindowAnimation_taskToBackExitAnimation; - } - - if (animAttr != 0) { - if (overrideType == ANIM_FROM_STYLE && canCustomContainer) { - a = mTransitionAnimation - .loadAnimationAttr(options.getPackageName(), options.getAnimations(), - animAttr, translucent); - } else { - a = mTransitionAnimation.loadDefaultAnimationAttr(animAttr, translucent); - } - } - - ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, - "loadAnimation: anim=%s animAttr=0x%x type=%s isEntrance=%b", a, animAttr, - transitTypeToString(type), - enter); + a = loadAttributeAnimation(info, change, wallpaperTransit, mTransitionAnimation); } if (a != null) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java new file mode 100644 index 000000000000..efee6f40b53e --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2022 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.wm.shell.transition; + +import static android.app.ActivityOptions.ANIM_FROM_STYLE; +import static android.app.ActivityOptions.ANIM_NONE; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM; +import static android.view.WindowManager.TRANSIT_CLOSE; +import static android.view.WindowManager.TRANSIT_OPEN; +import static android.view.WindowManager.TRANSIT_TO_BACK; +import static android.view.WindowManager.TRANSIT_TO_FRONT; +import static android.view.WindowManager.transitTypeToString; +import static android.window.TransitionInfo.FLAG_TRANSLUCENT; + +import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_CLOSE; +import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_INTRA_CLOSE; +import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_INTRA_OPEN; +import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_OPEN; + +import android.annotation.ColorInt; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.graphics.Color; +import android.os.SystemProperties; +import android.view.SurfaceControl; +import android.view.animation.Animation; +import android.window.TransitionInfo; + +import com.android.internal.R; +import com.android.internal.policy.TransitionAnimation; +import com.android.internal.protolog.common.ProtoLog; +import com.android.wm.shell.protolog.ShellProtoLogGroup; + +/** The helper class that provides methods for adding styles to transition animations. */ +public class TransitionAnimationHelper { + + /** + * Restrict ability of activities overriding transition animation in a way such that + * an activity can do it only when the transition happens within a same task. + * + * @see android.app.Activity#overridePendingTransition(int, int) + */ + private static final String DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY = + "persist.wm.disable_custom_task_animation"; + + /** + * @see #DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY + */ + static final boolean sDisableCustomTaskAnimationProperty = + SystemProperties.getBoolean(DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY, true); + + /** Loads the animation that is defined through attribute id for the given transition. */ + @Nullable + public static Animation loadAttributeAnimation(@NonNull TransitionInfo info, + @NonNull TransitionInfo.Change change, int wallpaperTransit, + @NonNull TransitionAnimation transitionAnimation) { + final int type = info.getType(); + final int changeMode = change.getMode(); + final int changeFlags = change.getFlags(); + final boolean enter = Transitions.isOpeningType(changeMode); + final boolean isTask = change.getTaskInfo() != null; + final TransitionInfo.AnimationOptions options = info.getAnimationOptions(); + final int overrideType = options != null ? options.getType() : ANIM_NONE; + final boolean canCustomContainer = !isTask || !sDisableCustomTaskAnimationProperty; + final boolean isDream = + isTask && change.getTaskInfo().topActivityType == ACTIVITY_TYPE_DREAM; + int animAttr = 0; + boolean translucent = false; + if (isDream) { + if (type == TRANSIT_OPEN) { + animAttr = enter + ? R.styleable.WindowAnimation_dreamActivityOpenEnterAnimation + : R.styleable.WindowAnimation_dreamActivityOpenExitAnimation; + } else if (type == TRANSIT_CLOSE) { + animAttr = enter + ? 0 + : R.styleable.WindowAnimation_dreamActivityCloseExitAnimation; + } + } else if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_OPEN) { + animAttr = enter + ? R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation + : R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation; + } else if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_CLOSE) { + animAttr = enter + ? R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation + : R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation; + } else if (wallpaperTransit == WALLPAPER_TRANSITION_OPEN) { + animAttr = enter + ? R.styleable.WindowAnimation_wallpaperOpenEnterAnimation + : R.styleable.WindowAnimation_wallpaperOpenExitAnimation; + } else if (wallpaperTransit == WALLPAPER_TRANSITION_CLOSE) { + animAttr = enter + ? R.styleable.WindowAnimation_wallpaperCloseEnterAnimation + : R.styleable.WindowAnimation_wallpaperCloseExitAnimation; + } else if (type == TRANSIT_OPEN) { + // We will translucent open animation for translucent activities and tasks. Choose + // WindowAnimation_activityOpenEnterAnimation and set translucent here, then + // TransitionAnimation loads appropriate animation later. + if ((changeFlags & FLAG_TRANSLUCENT) != 0 && enter) { + translucent = true; + } + if (isTask && !translucent) { + animAttr = enter + ? R.styleable.WindowAnimation_taskOpenEnterAnimation + : R.styleable.WindowAnimation_taskOpenExitAnimation; + } else { + animAttr = enter + ? R.styleable.WindowAnimation_activityOpenEnterAnimation + : R.styleable.WindowAnimation_activityOpenExitAnimation; + } + } else if (type == TRANSIT_TO_FRONT) { + animAttr = enter + ? R.styleable.WindowAnimation_taskToFrontEnterAnimation + : R.styleable.WindowAnimation_taskToFrontExitAnimation; + } else if (type == TRANSIT_CLOSE) { + if (isTask) { + animAttr = enter + ? R.styleable.WindowAnimation_taskCloseEnterAnimation + : R.styleable.WindowAnimation_taskCloseExitAnimation; + } else { + if ((changeFlags & FLAG_TRANSLUCENT) != 0 && !enter) { + translucent = true; + } + animAttr = enter + ? R.styleable.WindowAnimation_activityCloseEnterAnimation + : R.styleable.WindowAnimation_activityCloseExitAnimation; + } + } else if (type == TRANSIT_TO_BACK) { + animAttr = enter + ? R.styleable.WindowAnimation_taskToBackEnterAnimation + : R.styleable.WindowAnimation_taskToBackExitAnimation; + } + + Animation a = null; + if (animAttr != 0) { + if (overrideType == ANIM_FROM_STYLE && canCustomContainer) { + a = transitionAnimation + .loadAnimationAttr(options.getPackageName(), options.getAnimations(), + animAttr, translucent); + } else { + a = transitionAnimation.loadDefaultAnimationAttr(animAttr, translucent); + } + } + + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, + "loadAnimation: anim=%s animAttr=0x%x type=%s isEntrance=%b", a, animAttr, + transitTypeToString(type), + enter); + return a; + } + + /** + * Gets the background {@link ColorInt} for the given transition animation if it is set. + * + * @param defaultColor {@link ColorInt} to return if there is no background color specified by + * the given transition animation. + */ + @ColorInt + public static int getTransitionBackgroundColorIfSet(@NonNull TransitionInfo info, + @NonNull TransitionInfo.Change change, @NonNull Animation a, + @ColorInt int defaultColor) { + if (!a.getShowBackdrop()) { + return defaultColor; + } + if (info.getAnimationOptions() != null + && info.getAnimationOptions().getBackgroundColor() != 0) { + // If available use the background color provided through AnimationOptions + return info.getAnimationOptions().getBackgroundColor(); + } else if (a.getBackdropColor() != 0) { + // Otherwise fallback on the background color provided through the animation + // definition. + return a.getBackdropColor(); + } else if (change.getBackgroundColor() != 0) { + // Otherwise default to the window's background color if provided through + // the theme as the background color for the animation - the top most window + // with a valid background color and showBackground set takes precedence. + return change.getBackgroundColor(); + } + return defaultColor; + } + + /** + * Adds the given {@code backgroundColor} as the background color to the transition animation. + */ + public static void addBackgroundToTransition(@NonNull SurfaceControl rootLeash, + @ColorInt int backgroundColor, @NonNull SurfaceControl.Transaction startTransaction, + @NonNull SurfaceControl.Transaction finishTransaction) { + if (backgroundColor == 0) { + // No background color. + return; + } + final Color bgColor = Color.valueOf(backgroundColor); + final float[] colorArray = new float[] { bgColor.red(), bgColor.green(), bgColor.blue() }; + final SurfaceControl animationBackgroundSurface = new SurfaceControl.Builder() + .setName("Animation Background") + .setParent(rootLeash) + .setColorLayer() + .setOpaque(true) + .build(); + startTransaction + .setLayer(animationBackgroundSurface, Integer.MIN_VALUE) + .setColor(animationBackgroundSurface, colorArray) + .show(animationBackgroundSurface); + finishTransaction.remove(animationBackgroundSurface); + } +} diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp index 1ebdc273931b..795af8a58351 100644 --- a/native/android/surface_control.cpp +++ b/native/android/surface_control.cpp @@ -300,7 +300,7 @@ void ASurfaceTransaction_setOnComplete(ASurfaceTransaction* aSurfaceTransaction, auto& aSurfaceControlStats = aSurfaceTransactionStats.aSurfaceControlStats; for (const auto& [surfaceControl, latchTime, acquireTimeOrFence, presentFence, - previousReleaseFence, transformHint, frameEvents] : surfaceControlStats) { + previousReleaseFence, transformHint, frameEvents, ignore] : surfaceControlStats) { ASurfaceControl* aSurfaceControl = reinterpret_cast<ASurfaceControl*>(surfaceControl.get()); aSurfaceControlStats[aSurfaceControl].acquireTimeOrFence = acquireTimeOrFence; aSurfaceControlStats[aSurfaceControl].previousReleaseFence = previousReleaseFence; @@ -650,7 +650,7 @@ void ASurfaceTransaction_setOnCommit(ASurfaceTransaction* aSurfaceTransaction, v auto& aSurfaceControlStats = aSurfaceTransactionStats.aSurfaceControlStats; for (const auto& [surfaceControl, latchTime, acquireTimeOrFence, presentFence, - previousReleaseFence, transformHint, frameEvents] : + previousReleaseFence, transformHint, frameEvents, ignore] : surfaceControlStats) { ASurfaceControl* aSurfaceControl = reinterpret_cast<ASurfaceControl*>(surfaceControl.get()); diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/NavigationEdgeBackPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/NavigationEdgeBackPlugin.java index 12372593b62f..506ccf3c2437 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/NavigationEdgeBackPlugin.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/NavigationEdgeBackPlugin.java @@ -61,5 +61,13 @@ public interface NavigationEdgeBackPlugin extends Plugin { /** Indicates that the gesture was cancelled and the system should not go back. */ void cancelBack(); + + /** + * Indicates if back will be triggered if committed in current state. + * + * @param triggerBack if back will be triggered in current state. + */ + // TODO(b/247883311): Remove default impl once SwipeBackGestureHandler overrides this. + default void setTriggerBack(boolean triggerBack) {} } } diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java index 67b683ec643a..2e13903814a5 100644 --- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java @@ -455,6 +455,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab } } + boolean needToUpdateProviderViews = false; final String newUniqueId = mDisplayInfo.uniqueId; if (!Objects.equals(newUniqueId, mDisplayUniqueId)) { mDisplayUniqueId = newUniqueId; @@ -472,6 +473,37 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab setupDecorations(); return; } + + if (mScreenDecorHwcLayer != null) { + updateHwLayerRoundedCornerDrawable(); + updateHwLayerRoundedCornerExistAndSize(); + } + needToUpdateProviderViews = true; + } + + final float newRatio = getPhysicalPixelDisplaySizeRatio(); + if (mRoundedCornerResDelegate.getPhysicalPixelDisplaySizeRatio() != newRatio) { + mRoundedCornerResDelegate.setPhysicalPixelDisplaySizeRatio(newRatio); + if (mScreenDecorHwcLayer != null) { + updateHwLayerRoundedCornerExistAndSize(); + } + needToUpdateProviderViews = true; + } + + if (needToUpdateProviderViews) { + updateOverlayProviderViews(null); + } else { + updateOverlayProviderViews(new Integer[] { + mFaceScanningViewId, + R.id.display_cutout, + R.id.display_cutout_left, + R.id.display_cutout_right, + R.id.display_cutout_bottom, + }); + } + + if (mScreenDecorHwcLayer != null) { + mScreenDecorHwcLayer.onDisplayChanged(newUniqueId); } } }; @@ -1037,8 +1069,6 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab && (newRotation != mRotation || displayModeChanged(mDisplayMode, newMod))) { mRotation = newRotation; mDisplayMode = newMod; - mRoundedCornerResDelegate.setPhysicalPixelDisplaySizeRatio( - getPhysicalPixelDisplaySizeRatio()); if (mScreenDecorHwcLayer != null) { mScreenDecorHwcLayer.pendingConfigChange = false; mScreenDecorHwcLayer.updateRotation(mRotation); diff --git a/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt b/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt index 8b4aeefb6ed4..a25286438387 100644 --- a/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt +++ b/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt @@ -78,18 +78,23 @@ class RoundedCornerResDelegate( reloadMeasures() } + private fun reloadAll(newReloadToken: Int) { + if (reloadToken == newReloadToken) { + return + } + reloadToken = newReloadToken + reloadRes() + reloadMeasures() + } + fun updateDisplayUniqueId(newDisplayUniqueId: String?, newReloadToken: Int?) { if (displayUniqueId != newDisplayUniqueId) { displayUniqueId = newDisplayUniqueId newReloadToken ?.let { reloadToken = it } reloadRes() reloadMeasures() - } else if (newReloadToken != null) { - if (reloadToken == newReloadToken) { - return - } - reloadToken = newReloadToken - reloadMeasures() + } else { + newReloadToken?.let { reloadAll(it) } } } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java index d605c1a42ec0..0f1338e4e872 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java @@ -303,6 +303,13 @@ public class EdgeBackGestureHandler extends CurrentUserTracker mOverviewProxyService.notifyBackAction(false, (int) mDownPoint.x, (int) mDownPoint.y, false /* isButton */, !mIsOnLeftEdge); } + + @Override + public void setTriggerBack(boolean triggerBack) { + if (mBackAnimation != null) { + mBackAnimation.setTriggerBack(triggerBack); + } + } }; private final SysUiState.SysUiStateCallback mSysUiStateCallback = diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java index 122852f7d07a..24efc762b39b 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java @@ -880,6 +880,7 @@ public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPl // Whenever the trigger back state changes the existing translation animation should be // cancelled mTranslationAnimation.cancel(); + mBackCallback.setTriggerBack(mTriggerBack); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java index bd75c75faa00..ae6ed2008a77 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java @@ -444,7 +444,7 @@ public class QSSecurityFooterUtils implements DialogInterface.OnClickListener { mShouldUseSettingsButton.set(false); mBgHandler.post(() -> { String settingsButtonText = getSettingsButton(); - final View dialogView = createDialogView(); + final View dialogView = createDialogView(quickSettingsContext); mMainHandler.post(() -> { mDialog = new SystemUIDialog(quickSettingsContext, 0); mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE); @@ -469,14 +469,14 @@ public class QSSecurityFooterUtils implements DialogInterface.OnClickListener { } @VisibleForTesting - View createDialogView() { + View createDialogView(Context quickSettingsContext) { if (mSecurityController.isParentalControlsEnabled()) { return createParentalControlsDialogView(); } - return createOrganizationDialogView(); + return createOrganizationDialogView(quickSettingsContext); } - private View createOrganizationDialogView() { + private View createOrganizationDialogView(Context quickSettingsContext) { final boolean isDeviceManaged = mSecurityController.isDeviceManaged(); final boolean hasWorkProfile = mSecurityController.hasWorkProfile(); final CharSequence deviceOwnerOrganization = @@ -487,7 +487,7 @@ public class QSSecurityFooterUtils implements DialogInterface.OnClickListener { final String vpnName = mSecurityController.getPrimaryVpnName(); final String vpnNameWorkProfile = mSecurityController.getWorkProfileVpnName(); - View dialogView = LayoutInflater.from(mContext) + View dialogView = LayoutInflater.from(quickSettingsContext) .inflate(R.layout.quick_settings_footer_dialog, null, false); // device management section diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index e61794b0243e..9d5392af3127 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -730,7 +730,9 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb private void setDozing(boolean dozing) { if (mDozing != dozing) { mDozing = dozing; - reset(true /* hideBouncerWhenShowing */); + if (dozing || mBouncer.needsFullscreenBouncer() || mOccluded) { + reset(dozing /* hideBouncerWhenShowing */); + } updateStates(); if (!dozing) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java index 5a26d05d7b37..df10dfe9f160 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java @@ -1005,13 +1005,18 @@ public class ScreenDecorationsTest extends SysuiTestCase { assertEquals(new Size(3, 3), resDelegate.getTopRoundedSize()); assertEquals(new Size(4, 4), resDelegate.getBottomRoundedSize()); - doReturn(2f).when(mScreenDecorations).getPhysicalPixelDisplaySizeRatio(); + setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, + getTestsDrawable(com.android.systemui.tests.R.drawable.rounded4px) + /* roundedTopDrawable */, + getTestsDrawable(com.android.systemui.tests.R.drawable.rounded5px) + /* roundedBottomDrawable */, + 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning*/); mDisplayInfo.rotation = Surface.ROTATION_270; mScreenDecorations.onConfigurationChanged(null); - assertEquals(new Size(6, 6), resDelegate.getTopRoundedSize()); - assertEquals(new Size(8, 8), resDelegate.getBottomRoundedSize()); + assertEquals(new Size(4, 4), resDelegate.getTopRoundedSize()); + assertEquals(new Size(5, 5), resDelegate.getBottomRoundedSize()); } @Test @@ -1288,6 +1293,51 @@ public class ScreenDecorationsTest extends SysuiTestCase { } @Test + public void testOnDisplayChanged_hwcLayer() { + setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, + null /* roundedTopDrawable */, null /* roundedBottomDrawable */, + 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */); + final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport(); + decorationSupport.format = PixelFormat.R_8; + doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport(); + + // top cutout + mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP)); + + mScreenDecorations.start(); + + final ScreenDecorHwcLayer hwcLayer = mScreenDecorations.mScreenDecorHwcLayer; + spyOn(hwcLayer); + doReturn(mDisplay).when(hwcLayer).getDisplay(); + + mScreenDecorations.mDisplayListener.onDisplayChanged(1); + + verify(hwcLayer, times(1)).onDisplayChanged(any()); + } + + @Test + public void testOnDisplayChanged_nonHwcLayer() { + setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, + null /* roundedTopDrawable */, null /* roundedBottomDrawable */, + 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */); + + // top cutout + mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP)); + + mScreenDecorations.start(); + + final ScreenDecorations.DisplayCutoutView cutoutView = (ScreenDecorations.DisplayCutoutView) + mScreenDecorations.getOverlayView(R.id.display_cutout); + assertNotNull(cutoutView); + spyOn(cutoutView); + doReturn(mDisplay).when(cutoutView).getDisplay(); + + mScreenDecorations.mDisplayListener.onDisplayChanged(1); + + verify(cutoutView, times(1)).onDisplayChanged(any()); + } + + @Test public void testHasSameProvidersWithNullOverlays() { setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, null /* roundedTopDrawable */, null /* roundedBottomDrawable */, diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt index 93a1868b72f5..f93336134900 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt @@ -24,11 +24,12 @@ import androidx.annotation.DrawableRes import androidx.test.filters.SmallTest import com.android.internal.R as InternalR import com.android.systemui.R as SystemUIR -import com.android.systemui.SysuiTestCase import com.android.systemui.tests.R +import com.android.systemui.SysuiTestCase import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test + import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.MockitoAnnotations @@ -101,11 +102,14 @@ class RoundedCornerResDelegateTest : SysuiTestCase() { assertEquals(Size(3, 3), roundedCornerResDelegate.topRoundedSize) assertEquals(Size(4, 4), roundedCornerResDelegate.bottomRoundedSize) - roundedCornerResDelegate.physicalPixelDisplaySizeRatio = 2f + setupResources(radius = 100, + roundedTopDrawable = getTestsDrawable(R.drawable.rounded4px), + roundedBottomDrawable = getTestsDrawable(R.drawable.rounded5px)) + roundedCornerResDelegate.updateDisplayUniqueId(null, 1) - assertEquals(Size(6, 6), roundedCornerResDelegate.topRoundedSize) - assertEquals(Size(8, 8), roundedCornerResDelegate.bottomRoundedSize) + assertEquals(Size(4, 4), roundedCornerResDelegate.topRoundedSize) + assertEquals(Size(5, 5), roundedCornerResDelegate.bottomRoundedSize) } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java index 233c267c3be0..1c686c66e31e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java @@ -726,7 +726,7 @@ public class QSSecurityFooterTest extends SysuiTestCase { when(mSecurityController.isParentalControlsEnabled()).thenReturn(true); when(mSecurityController.getLabel(any())).thenReturn(PARENTAL_CONTROLS_LABEL); - View view = mFooterUtils.createDialogView(); + View view = mFooterUtils.createDialogView(getContext()); TextView textView = (TextView) view.findViewById(R.id.parental_controls_title); assertEquals(PARENTAL_CONTROLS_LABEL, textView.getText()); } @@ -749,7 +749,7 @@ public class QSSecurityFooterTest extends SysuiTestCase { when(mSecurityController.getDeviceOwnerType(DEVICE_OWNER_COMPONENT)) .thenReturn(DEVICE_OWNER_TYPE_FINANCED); - View view = mFooterUtils.createDialogView(); + View view = mFooterUtils.createDialogView(getContext()); TextView managementSubtitle = view.findViewById(R.id.device_management_subtitle); assertEquals(View.VISIBLE, managementSubtitle.getVisibility()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java index ee4b9d9c93f2..dcce61b86ced 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java @@ -26,7 +26,6 @@ import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -526,21 +525,4 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { mBouncerExpansionCallback.onVisibilityChanged(false); verify(mCentralSurfaces).setBouncerShowingOverDream(false); } - - @Test - public void testSetDozing_Dozing() { - clearInvocations(mBouncer); - mStatusBarKeyguardViewManager.onDozingChanged(true); - // Once when shown and once with dozing changed. - verify(mBouncer, times(1)).hide(false); - } - - @Test - public void testSetDozing_notDozing() { - mStatusBarKeyguardViewManager.onDozingChanged(true); - clearInvocations(mBouncer); - mStatusBarKeyguardViewManager.onDozingChanged(false); - // Once when shown and twice with dozing changed. - verify(mBouncer, times(1)).hide(false); - } } diff --git a/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java b/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java index ad09f7cd3dde..33f1b4282e97 100644 --- a/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java +++ b/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java @@ -184,13 +184,21 @@ class BleCompanionDeviceScanner implements AssociationStore.OnChangeListener { @MainThread private void startScan() { enforceInitialized(); - // This method should not be called if scan is already in progress. - if (mScanning) throw new IllegalStateException("Scan is already in progress."); - // Neither should this method be called if the adapter is not available. - if (mBleScanner == null) throw new IllegalStateException("BLE is not available."); if (DEBUG) Log.i(TAG, "startScan()"); + // This method should not be called if scan is already in progress. + if (mScanning) { + Slog.w(TAG, "Scan is already in progress."); + return; + } + + // Neither should this method be called if the adapter is not available. + if (mBleScanner == null) { + Slog.w(TAG, "BLE is not available."); + return; + } + // Collect MAC addresses from all associations. final Set<String> macAddresses = new HashSet<>(); for (AssociationInfo association : mAssociationStore.getAssociations()) { @@ -221,8 +229,18 @@ class BleCompanionDeviceScanner implements AssociationStore.OnChangeListener { filters.add(filter); } - mBleScanner.startScan(filters, SCAN_SETTINGS, mScanCallback); - mScanning = true; + // BluetoothLeScanner will throw an IllegalStateException if startScan() is called while LE + // is not enabled. + if (mBtAdapter.isLeEnabled()) { + try { + mBleScanner.startScan(filters, SCAN_SETTINGS, mScanCallback); + mScanning = true; + } catch (IllegalStateException e) { + Slog.w(TAG, "Exception while starting BLE scanning", e); + } + } else { + Slog.w(TAG, "BLE scanning is not turned on"); + } } private void stopScanIfNeeded() { @@ -240,11 +258,11 @@ class BleCompanionDeviceScanner implements AssociationStore.OnChangeListener { if (mBtAdapter.isLeEnabled()) { try { mBleScanner.stopScan(mScanCallback); - } catch (RuntimeException e) { - // Just to be sure not to crash system server here if BluetoothLeScanner throws - // another RuntimeException. + } catch (IllegalStateException e) { Slog.w(TAG, "Exception while stopping BLE scanning", e); } + } else { + Slog.w(TAG, "BLE scanning is not turned on"); } mScanning = false; diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index efb2cb7a3283..2a219289cf10 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -411,8 +411,11 @@ final class LocalDisplayAdapter extends DisplayAdapter { // For a new display, we need to initialize the default mode ID. if (mDefaultModeId == INVALID_MODE_ID) { - mDefaultModeId = activeRecord.mMode.getModeId(); - mDefaultModeGroup = mActiveSfDisplayMode.group; + mDefaultModeId = mSystemPreferredModeId != INVALID_MODE_ID + ? mSystemPreferredModeId : activeRecord.mMode.getModeId(); + mDefaultModeGroup = mSystemPreferredModeId != INVALID_MODE_ID + ? preferredSfDisplayMode.group + : mActiveSfDisplayMode.group; } else if (modesAdded && activeModeChanged) { Slog.d(TAG, "New display modes are added and the active mode has changed, " + "use active mode as default mode."); @@ -894,13 +897,6 @@ final class LocalDisplayAdapter extends DisplayAdapter { public void setUserPreferredDisplayModeLocked(Display.Mode mode) { final int oldModeId = getPreferredModeId(); mUserPreferredMode = mode; - // When clearing the user preferred mode we need to also reset the default mode. This is - // used by DisplayModeDirector to determine the default resolution, so if we don't clear - // it then the resolution won't reset to what it would've been prior to setting a user - // preferred display mode. - if (mode == null && mSystemPreferredModeId != INVALID_MODE_ID) { - mDefaultModeId = mSystemPreferredModeId; - } if (mode != null && (mode.isRefreshRateSet() || mode.isResolutionSet())) { Display.Mode matchingSupportedMode; matchingSupportedMode = findMode(mode.getPhysicalWidth(), diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index 5599f2cfc374..9c95e31cc5f5 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -1032,8 +1032,12 @@ public class AppTransitionController { private void applyAnimations(ArraySet<ActivityRecord> openingApps, ArraySet<ActivityRecord> closingApps, @TransitionOldType int transit, LayoutParams animLp, boolean voiceInteraction) { + final RecentsAnimationController rac = mService.getRecentsAnimationController(); if (transit == WindowManager.TRANSIT_OLD_UNSET || (openingApps.isEmpty() && closingApps.isEmpty())) { + if (rac != null) { + rac.sendTasksAppeared(); + } return; } @@ -1071,7 +1075,6 @@ public class AppTransitionController { voiceInteraction); applyAnimations(closingWcs, closingApps, transit, false /* visible */, animLp, voiceInteraction); - final RecentsAnimationController rac = mService.getRecentsAnimationController(); if (rac != null) { rac.sendTasksAppeared(); } diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java index ed369c016770..9c615d140e85 100644 --- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java @@ -764,13 +764,11 @@ public class LocalDisplayAdapterTest { @Test public void testGetSystemPreferredDisplayMode() throws Exception { SurfaceControl.DisplayMode displayMode1 = createFakeDisplayMode(0, 1920, 1080, 60f); - // system preferred mode + // preferred mode SurfaceControl.DisplayMode displayMode2 = createFakeDisplayMode(1, 3840, 2160, 60f); - // user preferred mode - SurfaceControl.DisplayMode displayMode3 = createFakeDisplayMode(2, 1920, 1080, 30f); SurfaceControl.DisplayMode[] modes = - new SurfaceControl.DisplayMode[]{displayMode1, displayMode2, displayMode3}; + new SurfaceControl.DisplayMode[]{displayMode1, displayMode2}; FakeDisplay display = new FakeDisplay(PORT_A, modes, 0, 1); setUpDisplay(display); updateAvailableDisplays(); @@ -782,43 +780,24 @@ public class LocalDisplayAdapterTest { DisplayDeviceInfo displayDeviceInfo = mListener.addedDisplays.get( 0).getDisplayDeviceInfoLocked(); - assertThat(displayDeviceInfo.supportedModes.length).isEqualTo(modes.length); - Display.Mode defaultMode = getModeById(displayDeviceInfo, displayDeviceInfo.defaultModeId); - assertThat(matches(defaultMode, displayMode1)).isTrue(); - // Set the user preferred display mode - mListener.addedDisplays.get(0).setUserPreferredDisplayModeLocked( - new Display.Mode( - displayMode3.width, displayMode3.height, displayMode3.refreshRate)); - updateAvailableDisplays(); - waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); - displayDeviceInfo = mListener.addedDisplays.get( - 0).getDisplayDeviceInfoLocked(); - defaultMode = getModeById(displayDeviceInfo, displayDeviceInfo.defaultModeId); - assertThat(matches(defaultMode, displayMode3)).isTrue(); + assertThat(displayDeviceInfo.supportedModes.length).isEqualTo(modes.length); - // clear the user preferred mode - mListener.addedDisplays.get(0).setUserPreferredDisplayModeLocked(null); - updateAvailableDisplays(); - waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); - displayDeviceInfo = mListener.addedDisplays.get( - 0).getDisplayDeviceInfoLocked(); - defaultMode = getModeById(displayDeviceInfo, displayDeviceInfo.defaultModeId); + Display.Mode defaultMode = getModeById(displayDeviceInfo, displayDeviceInfo.defaultModeId); assertThat(matches(defaultMode, displayMode2)).isTrue(); - // Change the display and add new system preferred mode - SurfaceControl.DisplayMode addedDisplayInfo = createFakeDisplayMode(3, 2340, 1080, 20f); - modes = new SurfaceControl.DisplayMode[]{ - displayMode1, displayMode2, displayMode3, addedDisplayInfo}; + // Change the display and add new preferred mode + SurfaceControl.DisplayMode addedDisplayInfo = createFakeDisplayMode(2, 2340, 1080, 60f); + modes = new SurfaceControl.DisplayMode[]{displayMode1, displayMode2, addedDisplayInfo}; display.dynamicInfo.supportedDisplayModes = modes; - display.dynamicInfo.preferredBootDisplayMode = 3; + display.dynamicInfo.preferredBootDisplayMode = 2; setUpDisplay(display); mInjector.getTransmitter().sendHotplug(display, /* connected */ true); waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); assertTrue(mListener.traversalRequested); assertThat(mListener.addedDisplays.size()).isEqualTo(1); - assertThat(mListener.changedDisplays.size()).isEqualTo(3); + assertThat(mListener.changedDisplays.size()).isEqualTo(1); DisplayDevice displayDevice = mListener.changedDisplays.get(0); displayDevice.applyPendingDisplayDeviceInfoChangesLocked(); |