diff options
62 files changed, 685 insertions, 956 deletions
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java index a87b91d87f1c..3bffa890122a 100644 --- a/core/java/android/window/WindowContainerTransaction.java +++ b/core/java/android/window/WindowContainerTransaction.java @@ -348,8 +348,10 @@ public final class WindowContainerTransaction implements Parcelable { * @param currentParent of the tasks to perform the operation no. * {@code null} will perform the operation on the display. * @param newParent for the tasks. {@code null} will perform the operation on the display. - * @param windowingModes of the tasks to reparent. - * @param activityTypes of the tasks to reparent. + * @param windowingModes of the tasks to reparent. {@code null} ignore this attribute when + * perform the operation. + * @param activityTypes of the tasks to reparent. {@code null} ignore this attribute when + * perform the operation. * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to * the bottom. */ diff --git a/core/jni/android_graphics_BLASTBufferQueue.cpp b/core/jni/android_graphics_BLASTBufferQueue.cpp index 4af28ea24361..1520ea5c6831 100644 --- a/core/jni/android_graphics_BLASTBufferQueue.cpp +++ b/core/jni/android_graphics_BLASTBufferQueue.cpp @@ -41,7 +41,12 @@ struct { static JNIEnv* getenv(JavaVM* vm) { JNIEnv* env; - if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { + auto result = vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6); + if (result == JNI_EDETACHED) { + if (vm->AttachCurrentThreadAsDaemon(&env, nullptr) != JNI_OK) { + LOG_ALWAYS_FATAL("Failed to AttachCurrentThread!"); + } + } else if (result != JNI_OK) { LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", vm); } return env; @@ -60,28 +65,22 @@ public: } ~TransactionHangCallbackWrapper() { - if (mTransactionHangObject) { - getenv()->DeleteGlobalRef(mTransactionHangObject); + if (mTransactionHangObject != nullptr) { + getenv(mVm)->DeleteGlobalRef(mTransactionHangObject); mTransactionHangObject = nullptr; } } void onTransactionHang(bool isGpuHang) { if (mTransactionHangObject) { - getenv()->CallVoidMethod(mTransactionHangObject, - gTransactionHangCallback.onTransactionHang, isGpuHang); + getenv(mVm)->CallVoidMethod(mTransactionHangObject, + gTransactionHangCallback.onTransactionHang, isGpuHang); } } private: JavaVM* mVm; jobject mTransactionHangObject; - - JNIEnv* getenv() { - JNIEnv* env; - mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6); - return env; - } }; static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring jName, diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 6706e4e87e0d..f01e2e809c21 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -577,12 +577,6 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "-1521427940": { - "message": "commitVisibility: %s: visible=%b mVisibleRequested=%b", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, "-1517908912": { "message": "requestScrollCapture: caught exception dispatching to window.token=%s", "level": "WARN", @@ -1513,6 +1507,12 @@ "group": "WM_DEBUG_FOCUS_LIGHT", "at": "com\/android\/server\/wm\/DisplayContent.java" }, + "-636553602": { + "message": "commitVisibility: %s: visible=%b visibleRequested=%b, isInTransition=%b, runningAnimation=%b, caller=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "-635082269": { "message": "******** booted=%b msg=%b haveBoot=%b haveApp=%b haveWall=%b wallEnabled=%b haveKeyguard=%b", "level": "INFO", diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/PhysicsAnimator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/PhysicsAnimator.kt index b483fe03e80f..312af4ff7bc2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/PhysicsAnimator.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/PhysicsAnimator.kt @@ -829,8 +829,12 @@ class PhysicsAnimator<T> private constructor (target: T) { /** Cancels all in progress animations on all properties. */ fun cancel() { - cancelAction(flingAnimations.keys) - cancelAction(springAnimations.keys) + if (flingAnimations.size > 0) { + cancelAction(flingAnimations.keys) + } + if (springAnimations.size > 0) { + cancelAction(springAnimations.keys) + } } /** Cancels in progress animations on the provided properties only. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java index 5801d43aaefd..2e64c945ca25 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java @@ -487,13 +487,25 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange private DividerSnapAlgorithm getSnapAlgorithm(Context context, Rect rootBounds, @Nullable Rect stableInsets) { final boolean isLandscape = isLandscape(rootBounds); + final Rect insets = stableInsets != null ? stableInsets : getDisplayInsets(context); + + // Make split axis insets value same as the larger one to avoid bounds1 and bounds2 + // have difference after split switching for solving issues on non-resizable app case. + if (isLandscape) { + final int largerInsets = Math.max(insets.left, insets.right); + insets.set(largerInsets, insets.top, largerInsets, insets.bottom); + } else { + final int largerInsets = Math.max(insets.top, insets.bottom); + insets.set(insets.left, largerInsets, insets.right, largerInsets); + } + return new DividerSnapAlgorithm( context.getResources(), rootBounds.width(), rootBounds.height(), mDividerSize, !isLandscape, - stableInsets != null ? stableInsets : getDisplayInsets(context), + insets, isLandscape ? DOCKED_LEFT : DOCKED_TOP /* dockSide */); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java index 9b614875119b..afc706ee9c8e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java @@ -15,6 +15,11 @@ */ package com.android.wm.shell.common.split; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; + import android.annotation.IntDef; /** Helper utility class of methods and constants that are available to be imported in Launcher. */ @@ -44,4 +49,10 @@ public class SplitScreenConstants { }) public @interface SplitPosition { } + + public static final int[] CONTROLLED_ACTIVITY_TYPES = {ACTIVITY_TYPE_STANDARD}; + public static final int[] CONTROLLED_WINDOWING_MODES = + {WINDOWING_MODE_FULLSCREEN, WINDOWING_MODE_UNDEFINED}; + public static final int[] CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE = + {WINDOWING_MODE_FULLSCREEN, WINDOWING_MODE_UNDEFINED, WINDOWING_MODE_MULTI_WINDOW}; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java index 2bfa5db502ce..e7ec15e70c11 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java @@ -16,6 +16,9 @@ package com.android.wm.shell.splitscreen; +import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES; +import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES; + import android.content.Context; import android.view.SurfaceSession; import android.window.WindowContainerToken; @@ -74,10 +77,10 @@ class MainStage extends StageTaskListener { if (mRootTaskInfo == null) return; final WindowContainerToken rootToken = mRootTaskInfo.token; wct.reparentTasks( - rootToken, - null /* newParent */, - CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE, - CONTROLLED_ACTIVITY_TYPES, - toTop); + rootToken, + null /* newParent */, + null /* windowingModes */, + null /* activityTypes */, + toTop); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java index f92a0d3901b9..8639b36faf4c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java @@ -47,8 +47,8 @@ class SideStage extends StageTaskListener { wct.reparentTasks( mRootTaskInfo.token, null /* newParent */, - CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE, - CONTROLLED_ACTIVITY_TYPES, + null /* windowingModes */, + null /* activityTypes */, toTop); return true; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index c8ee010e60e0..47bfaa64c831 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -26,6 +26,8 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.RemoteAnimationTarget.MODE_OPENING; import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; +import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES; +import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED; @@ -64,6 +66,7 @@ import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.InstanceId; import com.android.internal.protolog.common.ProtoLog; +import com.android.internal.util.ArrayUtils; import com.android.launcher3.icons.IconProvider; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; @@ -227,6 +230,12 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, && mStageCoordinator.getStageOfTask(taskId) != STAGE_TYPE_UNDEFINED; } + public boolean isValidToEnterSplitScreen(@NonNull ActivityManager.RunningTaskInfo taskInfo) { + return taskInfo.supportsMultiWindow + && ArrayUtils.contains(CONTROLLED_ACTIVITY_TYPES, taskInfo.getActivityType()) + && ArrayUtils.contains(CONTROLLED_WINDOWING_MODES, taskInfo.getWindowingMode()); + } + public @SplitPosition int getSplitPosition(int taskId) { return mStageCoordinator.getSplitPosition(taskId); } @@ -463,11 +472,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, return Objects.equals(launchingActivity, pairedActivity); } - if (mFocusingTaskInfo != null - // TODO (b/238032411): have an API to determine whether an activity is valid for - // split screen or not. - && mFocusingTaskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN - && mFocusingTaskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD) { + if (mFocusingTaskInfo != null && isValidToEnterSplitScreen(mFocusingTaskInfo)) { return Objects.equals(mFocusingTaskInfo.baseIntent.getComponent(), launchingActivity); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index 70d728d90b6a..e19c572c4850 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -87,6 +87,7 @@ import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.SurfaceSession; import android.view.WindowManager; +import android.widget.Toast; import android.window.DisplayAreaInfo; import android.window.RemoteTransition; import android.window.TransitionInfo; @@ -98,6 +99,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.InstanceId; import com.android.internal.protolog.common.ProtoLog; import com.android.launcher3.icons.IconProvider; +import com.android.wm.shell.R; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayImeController; @@ -1921,10 +1923,13 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, @Override public void onNoLongerSupportMultiWindow() { if (mMainStage.isActive()) { + final Toast splitUnsupportedToast = Toast.makeText(mContext, + R.string.dock_non_resizeble_failed_to_dock_text, Toast.LENGTH_SHORT); final boolean isMainStage = mMainStageListener == this; if (!ENABLE_SHELL_TRANSITIONS) { StageCoordinator.this.exitSplitScreen(isMainStage ? mMainStage : mSideStage, EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW); + splitUnsupportedToast.show(); return; } @@ -1933,6 +1938,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, prepareExitSplitScreen(stageType, wct); mSplitTransitions.startDismissTransition(wct,StageCoordinator.this, stageType, EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW); + splitUnsupportedToast.show(); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java index cb9e1a39ec52..d17ff7aff667 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java @@ -17,12 +17,12 @@ package com.android.wm.shell.splitscreen; import static android.app.ActivityTaskManager.INVALID_TASK_ID; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; +import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES; +import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE; import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS; import android.annotation.CallSuper; @@ -40,6 +40,7 @@ import android.window.WindowContainerTransaction; import androidx.annotation.NonNull; +import com.android.internal.util.ArrayUtils; import com.android.launcher3.icons.IconProvider; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.SurfaceUtils; @@ -62,12 +63,6 @@ import java.util.function.Predicate; class StageTaskListener implements ShellTaskOrganizer.TaskListener { private static final String TAG = StageTaskListener.class.getSimpleName(); - protected static final int[] CONTROLLED_ACTIVITY_TYPES = {ACTIVITY_TYPE_STANDARD}; - protected static final int[] CONTROLLED_WINDOWING_MODES = - {WINDOWING_MODE_FULLSCREEN, WINDOWING_MODE_UNDEFINED}; - protected static final int[] CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE = - {WINDOWING_MODE_FULLSCREEN, WINDOWING_MODE_UNDEFINED, WINDOWING_MODE_MULTI_WINDOW}; - /** Callback interface for listening to changes in a split-screen stage. */ public interface StageListenerCallbacks { void onRootTaskAppeared(); @@ -212,12 +207,15 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { } mRootTaskInfo = taskInfo; } else if (taskInfo.parentTaskId == mRootTaskInfo.taskId) { - if (!taskInfo.supportsMultiWindow) { - // Leave split screen if the task no longer supports multi window. + if (!taskInfo.supportsMultiWindow + || !ArrayUtils.contains(CONTROLLED_ACTIVITY_TYPES, taskInfo.getActivityType()) + || !ArrayUtils.contains(CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE, + taskInfo.getWindowingMode())) { + // Leave split screen if the task no longer supports multi window or have + // uncontrolled task. mCallbacks.onNoLongerSupportMultiWindow(); return; } - mChildrenTaskInfo.put(taskInfo.taskId, taskInfo); mCallbacks.onChildTaskStatusChanged(taskInfo.taskId, true /* present */, taskInfo.isVisible); diff --git a/packages/CompanionDeviceManager/res/values/strings.xml b/packages/CompanionDeviceManager/res/values/strings.xml index a389bfc42725..cb85ae4fe66b 100644 --- a/packages/CompanionDeviceManager/res/values/strings.xml +++ b/packages/CompanionDeviceManager/res/values/strings.xml @@ -48,7 +48,7 @@ <string name="helper_title_app_streaming">Cross-device services</string> <!-- Description of the helper dialog for APP_STREAMING profile. [CHAR LIMIT=NONE] --> - <string name="helper_summary_app_streaming"><xliff:g id="app_name" example="GMS">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="device_type" example="Chromebook">%2$s</xliff:g> to access your phone\u2019s photos, media, and notifications</string> + <string name="helper_summary_app_streaming"><xliff:g id="app_name" example="GMS">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="device_type" example="Chromebook">%2$s</xliff:g> to stream apps between your devices</string> <!-- ================= DEVICE_PROFILE_AUTOMOTIVE_PROJECTION ================= --> @@ -82,7 +82,7 @@ <string name="helper_title_computer">Google Play services</string> <!-- Description of the helper dialog for COMPUTER profile. [CHAR LIMIT=NONE] --> - <string name="helper_summary_computer"> <xliff:g id="app_name" example="GMS">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="device_type" example="Chromebook">%2$s</xliff:g> to stream apps between your devices</string> + <string name="helper_summary_computer"><xliff:g id="app_name" example="GMS">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="device_type" example="Chromebook">%2$s</xliff:g> to access your phone\u2019s photos, media, and notifications</string> <!-- ================= null profile ================= --> diff --git a/packages/SystemUI/res/drawable/screenshot_edit_background.xml b/packages/SystemUI/res/drawable/screenshot_edit_background.xml index ff5c62e1600b..a1185a2d5479 100644 --- a/packages/SystemUI/res/drawable/screenshot_edit_background.xml +++ b/packages/SystemUI/res/drawable/screenshot_edit_background.xml @@ -17,7 +17,7 @@ <!-- Long screenshot edit FAB background --> <ripple xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" - android:color="?android:textColorPrimary"> + android:color="@color/overlay_button_ripple"> <item android:id="@android:id/background"> <shape android:shape="rectangle"> <solid android:color="?androidprv:attr/colorAccentPrimary"/> diff --git a/packages/SystemUI/res/layout/brightness_mirror_container.xml b/packages/SystemUI/res/layout/brightness_mirror_container.xml index ac90db3e5e19..1bf45aad8906 100644 --- a/packages/SystemUI/res/layout/brightness_mirror_container.xml +++ b/packages/SystemUI/res/layout/brightness_mirror_container.xml @@ -23,7 +23,6 @@ android:background="@drawable/brightness_mirror_background" android:layout_gravity="center_vertical" android:layout_margin="8dp" - android:padding="@dimen/rounded_slider_background_padding" android:gravity="center" android:visibility="invisible"> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java index e9c1acbf7ca0..e3f568732b9d 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java @@ -18,6 +18,9 @@ package com.android.systemui.shared.recents.model; import static android.view.Display.DEFAULT_DISPLAY; +import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES; +import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES; + import android.app.ActivityManager; import android.app.ActivityManager.TaskDescription; import android.app.TaskInfo; @@ -31,6 +34,8 @@ import android.view.ViewDebug; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.android.internal.util.ArrayUtils; + import java.io.PrintWriter; import java.util.Objects; @@ -242,8 +247,10 @@ public class Task { ActivityManager.TaskDescription td = taskInfo.taskDescription; return new Task(taskKey, td != null ? td.getPrimaryColor() : 0, - td != null ? td.getBackgroundColor() : 0, - taskInfo.supportsMultiWindow, isLocked, td, taskInfo.topActivity); + td != null ? td.getBackgroundColor() : 0, taskInfo.supportsMultiWindow + && ArrayUtils.contains(CONTROLLED_ACTIVITY_TYPES, taskInfo.getActivityType()) + && ArrayUtils.contains(CONTROLLED_WINDOWING_MODES, taskInfo.getWindowingMode()), + isLocked, td, taskInfo.topActivity); } public Task(TaskKey key) { diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerKt.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerKt.kt new file mode 100644 index 000000000000..c1429335292f --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerKt.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.shared.system + +import android.app.ActivityManager + +/** Kotlin extensions for [ActivityManager] */ +object ActivityManagerKt { + + /** + * Returns `true` whether the app with the given package name has an activity at the top of the + * most recent task; `false` otherwise + */ + fun ActivityManager.isInForeground(packageName: String): Boolean { + val tasks: List<ActivityManager.RunningTaskInfo> = getRunningTasks(1) + return tasks.isNotEmpty() && packageName == tasks[0].topActivity.packageName + } +} diff --git a/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt b/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt index 99267e8ee1c9..cccd3a482ef0 100644 --- a/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt @@ -17,27 +17,28 @@ package com.android.systemui.camera import android.app.ActivityManager -import android.app.ActivityManager.RunningTaskInfo import android.app.ActivityOptions -import android.app.ActivityTaskManager +import android.app.IActivityTaskManager import android.content.ContentResolver import android.content.Context import android.content.Intent import android.content.pm.PackageManager import android.content.pm.ResolveInfo -import android.os.AsyncTask import android.os.RemoteException import android.os.UserHandle import android.util.Log import android.view.WindowManager +import androidx.annotation.VisibleForTesting import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.ActivityIntentHelper -import com.android.systemui.camera.CameraIntents.Companion.isSecureCameraIntent +import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.shared.system.ActivityManagerKt.isInForeground import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.phone.CentralSurfaces import com.android.systemui.statusbar.phone.PanelViewController import com.android.systemui.statusbar.policy.KeyguardStateController +import java.util.concurrent.Executor import javax.inject.Inject /** @@ -52,8 +53,10 @@ class CameraGestureHelper @Inject constructor( private val activityManager: ActivityManager, private val activityStarter: ActivityStarter, private val activityIntentHelper: ActivityIntentHelper, + private val activityTaskManager: IActivityTaskManager, private val cameraIntents: CameraIntentsWrapper, private val contentResolver: ContentResolver, + @Main private val uiExecutor: Executor, ) { /** * Whether the camera application can be launched for the camera launch gesture. @@ -63,15 +66,15 @@ class CameraGestureHelper @Inject constructor( return false } - val resolveInfo: ResolveInfo = packageManager.resolveActivityAsUser( + val resolveInfo: ResolveInfo? = packageManager.resolveActivityAsUser( getStartCameraIntent(), PackageManager.MATCH_DEFAULT_ONLY, KeyguardUpdateMonitor.getCurrentUser() ) - val resolvedPackage = resolveInfo.activityInfo?.packageName + val resolvedPackage = resolveInfo?.activityInfo?.packageName return (resolvedPackage != null && (statusBarState != StatusBarState.SHADE || - !isForegroundApp(resolvedPackage))) + !activityManager.isInForeground(resolvedPackage))) } /** @@ -85,8 +88,8 @@ class CameraGestureHelper @Inject constructor( val wouldLaunchResolverActivity = activityIntentHelper.wouldLaunchResolverActivity( intent, KeyguardUpdateMonitor.getCurrentUser() ) - if (isSecureCameraIntent(intent) && !wouldLaunchResolverActivity) { - AsyncTask.execute { + if (CameraIntents.isSecureCameraIntent(intent) && !wouldLaunchResolverActivity) { + uiExecutor.execute { // Normally an activity will set its requested rotation animation on its window. // However when launching an activity causes the orientation to change this is too // late. In these cases, the default animation is used. This doesn't look good for @@ -98,7 +101,7 @@ class CameraGestureHelper @Inject constructor( activityOptions.rotationAnimationHint = WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS try { - ActivityTaskManager.getService().startActivityAsUser( + activityTaskManager.startActivityAsUser( null, context.basePackageName, context.attributionTag, @@ -148,16 +151,8 @@ class CameraGestureHelper @Inject constructor( } } - /** - * Returns `true` if the application with the given package name is running in the foreground; - * `false` otherwise - */ - private fun isForegroundApp(packageName: String): Boolean { - val tasks: List<RunningTaskInfo> = activityManager.getRunningTasks(1) - return tasks.isNotEmpty() && packageName == tasks[0].topActivity.packageName - } - companion object { - private const val EXTRA_CAMERA_LAUNCH_SOURCE = "com.android.systemui.camera_launch_source" + @VisibleForTesting + const val EXTRA_CAMERA_LAUNCH_SOURCE = "com.android.systemui.camera_launch_source" } } diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/EditTextActivity.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/EditTextActivity.java index 3f78f97ba563..1fa9ac574c7e 100644 --- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/EditTextActivity.java +++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/EditTextActivity.java @@ -74,6 +74,7 @@ public class EditTextActivity extends Activity } mEditText.setText(clip.getItemAt(0).getText()); mEditText.requestFocus(); + mEditText.setSelection(0); mSensitive = clip.getDescription().getExtras() != null && clip.getDescription().getExtras() .getBoolean(ClipDescription.EXTRA_IS_SENSITIVE); diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java index f2f275323d58..ec4c4e6b3363 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java @@ -42,14 +42,11 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter { private static final String TAG = "MediaOutputAdapter"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - private final MediaOutputDialog mMediaOutputDialog; private ViewGroup mConnectedItem; private boolean mIncludeDynamicGroup; - public MediaOutputAdapter(MediaOutputController controller, - MediaOutputDialog mediaOutputDialog) { + public MediaOutputAdapter(MediaOutputController controller) { super(controller); - mMediaOutputDialog = mediaOutputDialog; setHasStableIds(true); } diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java index 8f065461c22d..310469dd5415 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java @@ -74,7 +74,7 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog { MediaOutputBroadcastDialog(Context context, boolean aboveStatusbar, BroadcastSender broadcastSender, MediaOutputController mediaOutputController) { super(context, broadcastSender, mediaOutputController); - mAdapter = new MediaOutputGroupAdapter(mMediaOutputController); + mAdapter = new MediaOutputAdapter(mMediaOutputController); // TODO(b/226710953): Move the part to MediaOutputBaseDialog for every class // that extends MediaOutputBaseDialog if (!aboveStatusbar) { diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java index a6cf408e0099..7cf0063481a5 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java @@ -42,7 +42,7 @@ public class MediaOutputDialog extends MediaOutputBaseDialog { MediaOutputController mediaOutputController, UiEventLogger uiEventLogger) { super(context, broadcastSender, mediaOutputController); mUiEventLogger = uiEventLogger; - mAdapter = new MediaOutputAdapter(mMediaOutputController, this); + mAdapter = new MediaOutputAdapter(mMediaOutputController); if (!aboveStatusbar) { getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); } diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java deleted file mode 100644 index ba2f006fc58e..000000000000 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (C) 2020 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.systemui.media.dialog; - -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.drawable.Drawable; -import android.text.TextUtils; -import android.util.Log; -import android.util.TypedValue; -import android.view.View; -import android.view.ViewGroup; - -import androidx.annotation.NonNull; - -import com.android.settingslib.media.MediaDevice; -import com.android.systemui.R; - -import java.util.List; - -/** - * Adapter for media output dynamic group dialog. - */ -//TODO: clear this class after new UI updated -public class MediaOutputGroupAdapter extends MediaOutputBaseAdapter { - - private static final String TAG = "MediaOutputGroupAdapter"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - - private final List<MediaDevice> mGroupMediaDevices; - - public MediaOutputGroupAdapter(MediaOutputController controller) { - super(controller); - mGroupMediaDevices = controller.getGroupMediaDevices(); - } - - @Override - public MediaDeviceBaseViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, - int viewType) { - super.onCreateViewHolder(viewGroup, viewType); - - return new GroupViewHolder(mHolderView); - } - - @Override - public void onBindViewHolder(@NonNull MediaDeviceBaseViewHolder viewHolder, int position) { - // Add "Group" - if (position == 0) { - viewHolder.onBind(CUSTOMIZED_ITEM_GROUP, true /* topMargin */, - false /* bottomMargin */); - return; - } - // Add available devices - final int newPosition = position - 1; - final int size = mGroupMediaDevices.size(); - if (newPosition < size) { - viewHolder.onBind(mGroupMediaDevices.get(newPosition), false /* topMargin */, - newPosition == (size - 1) /* bottomMargin */, position); - return; - } - if (DEBUG) { - Log.d(TAG, "Incorrect position: " + position); - } - } - - @Override - public int getItemCount() { - // Require extra item for group volume operation - return mGroupMediaDevices.size() + 1; - } - - @Override - CharSequence getItemTitle(MediaDevice device) { - return super.getItemTitle(device); - } - - class GroupViewHolder extends MediaDeviceBaseViewHolder { - - GroupViewHolder(View view) { - super(view); - } - - @Override - void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin, int position) { - super.onBind(device, topMargin, bottomMargin, position); - mCheckBox.setVisibility(View.VISIBLE); - mCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> { - onCheckBoxClicked(isChecked, device); - }); - boolean isCurrentSeekbarInvisible = mSeekBar.getVisibility() == View.GONE; - setTwoLineLayout(device, false /* bFocused */, true /* showSeekBar */, - false /* showProgressBar */, false /* showSubtitle*/); - initSeekbar(device, isCurrentSeekbarInvisible); - final List<MediaDevice> selectedDevices = mController.getSelectedMediaDevice(); - if (isDeviceIncluded(mController.getSelectableMediaDevice(), device)) { - mCheckBox.setButtonDrawable(R.drawable.ic_check_box); - mCheckBox.setChecked(false); - mCheckBox.setEnabled(true); - } else if (isDeviceIncluded(selectedDevices, device)) { - if (selectedDevices.size() == 1 || !isDeviceIncluded( - mController.getDeselectableMediaDevice(), device)) { - mCheckBox.setButtonDrawable(getDisabledCheckboxDrawable()); - mCheckBox.setChecked(true); - mCheckBox.setEnabled(false); - } else { - mCheckBox.setButtonDrawable(R.drawable.ic_check_box); - mCheckBox.setChecked(true); - mCheckBox.setEnabled(true); - } - } - } - - @Override - void onBind(int customizedItem, boolean topMargin, boolean bottomMargin) { - if (customizedItem == CUSTOMIZED_ITEM_GROUP) { - setTwoLineLayout(mContext.getText(R.string.media_output_dialog_group), - true /* bFocused */, true /* showSeekBar */, false /* showProgressBar */, - false /* showSubtitle*/); - mTitleIcon.setImageDrawable(getSpeakerDrawable()); - mCheckBox.setVisibility(View.GONE); - initSessionSeekbar(); - } - } - - private void onCheckBoxClicked(boolean isChecked, MediaDevice device) { - if (isChecked && isDeviceIncluded(mController.getSelectableMediaDevice(), device)) { - mController.addDeviceToPlayMedia(device); - } else if (!isChecked && isDeviceIncluded(mController.getDeselectableMediaDevice(), - device)) { - mController.removeDeviceFromPlayMedia(device); - } - } - - private Drawable getDisabledCheckboxDrawable() { - final Drawable drawable = mContext.getDrawable(R.drawable.ic_check_box_blue_24dp) - .mutate(); - final Bitmap checkbox = Bitmap.createBitmap(drawable.getIntrinsicWidth(), - drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); - final Canvas canvas = new Canvas(checkbox); - TypedValue value = new TypedValue(); - mContext.getTheme().resolveAttribute(android.R.attr.disabledAlpha, value, true); - drawable.setAlpha((int) (value.getFloat() * 255)); - drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); - drawable.draw(canvas); - - return drawable; - } - - private boolean isDeviceIncluded(List<MediaDevice> deviceList, MediaDevice targetDevice) { - for (MediaDevice device : deviceList) { - if (TextUtils.equals(device.getId(), targetDevice.getId())) { - return true; - } - } - return false; - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java deleted file mode 100644 index bb3f969c86df..000000000000 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2020 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.systemui.media.dialog; - -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.view.View; -import android.view.WindowManager; - -import androidx.core.graphics.drawable.IconCompat; - -import com.android.systemui.R; -import com.android.systemui.broadcast.BroadcastSender; - -/** - * Dialog for media output group. - */ -// TODO(b/203073091): Remove this class once group logic been implemented. -public class MediaOutputGroupDialog extends MediaOutputBaseDialog { - - MediaOutputGroupDialog(Context context, boolean aboveStatusbar, BroadcastSender broadcastSender, - MediaOutputController mediaOutputController) { - super(context, broadcastSender, mediaOutputController); - mMediaOutputController.resetGroupMediaDevices(); - mAdapter = new MediaOutputGroupAdapter(mMediaOutputController); - if (!aboveStatusbar) { - getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); - } - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - } - - @Override - int getHeaderIconRes() { - return R.drawable.ic_arrow_back; - } - - @Override - IconCompat getHeaderIcon() { - return null; - } - - @Override - int getHeaderIconSize() { - return mContext.getResources().getDimensionPixelSize( - R.dimen.media_output_dialog_header_back_icon_size); - } - - @Override - CharSequence getHeaderText() { - return mContext.getString(R.string.media_output_dialog_add_output); - } - - @Override - CharSequence getHeaderSubtitle() { - final int size = mMediaOutputController.getSelectedMediaDevice().size(); - if (size == 1) { - return mContext.getText(R.string.media_output_dialog_single_device); - } - return mContext.getString(R.string.media_output_dialog_multiple_devices, size); - } - - @Override - Drawable getAppSourceIcon() { - return null; - } - - @Override - int getStopButtonVisibility() { - return View.VISIBLE; - } - - @Override - void onHeaderIconClick() { - // Given that we launched the media output group dialog from the media output dialog, - // dismissing this dialog will show the media output dialog again. - dismiss(); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java index 6a3799b38dc5..d1aa01bb2125 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java @@ -75,8 +75,8 @@ public class NotifInflaterImpl implements NotifInflater { } @Override - public void abortInflation(NotificationEntry entry) { - entry.abortTask(); + public boolean abortInflation(NotificationEntry entry) { + return entry.abortTask(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java index 0a16fb65b1ac..b6392f705c49 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java @@ -476,11 +476,13 @@ public final class NotificationEntry extends ListEntry { /** * Abort all existing inflation tasks */ - public void abortTask() { + public boolean abortTask() { if (mRunningTask != null) { mRunningTask.abort(); mRunningTask = null; + return true; } + return false; } public void setInflationTask(InflationTask abortableTask) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java index 93761f580dd4..075a0dc7555e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java @@ -314,60 +314,62 @@ public class ShadeListBuilder implements Dumpable { } }; - private void onPreRenderInvalidated(Invalidator invalidator) { + private void onPreRenderInvalidated(Invalidator invalidator, @Nullable String reason) { Assert.isMainThread(); - mLogger.logPreRenderInvalidated(invalidator.getName(), mPipelineState.getState()); + mLogger.logPreRenderInvalidated(invalidator, mPipelineState.getState(), reason); rebuildListIfBefore(STATE_FINALIZING); } - private void onPreGroupFilterInvalidated(NotifFilter filter) { + private void onPreGroupFilterInvalidated(NotifFilter filter, @Nullable String reason) { Assert.isMainThread(); - mLogger.logPreGroupFilterInvalidated(filter.getName(), mPipelineState.getState()); + mLogger.logPreGroupFilterInvalidated(filter, mPipelineState.getState(), reason); rebuildListIfBefore(STATE_PRE_GROUP_FILTERING); } - private void onReorderingAllowedInvalidated(NotifStabilityManager stabilityManager) { + private void onReorderingAllowedInvalidated(NotifStabilityManager stabilityManager, + @Nullable String reason) { Assert.isMainThread(); mLogger.logReorderingAllowedInvalidated( - stabilityManager.getName(), - mPipelineState.getState()); + stabilityManager, + mPipelineState.getState(), + reason); rebuildListIfBefore(STATE_GROUPING); } - private void onPromoterInvalidated(NotifPromoter promoter) { + private void onPromoterInvalidated(NotifPromoter promoter, @Nullable String reason) { Assert.isMainThread(); - mLogger.logPromoterInvalidated(promoter.getName(), mPipelineState.getState()); + mLogger.logPromoterInvalidated(promoter, mPipelineState.getState(), reason); rebuildListIfBefore(STATE_TRANSFORMING); } - private void onNotifSectionInvalidated(NotifSectioner section) { + private void onNotifSectionInvalidated(NotifSectioner section, @Nullable String reason) { Assert.isMainThread(); - mLogger.logNotifSectionInvalidated(section.getName(), mPipelineState.getState()); + mLogger.logNotifSectionInvalidated(section, mPipelineState.getState(), reason); rebuildListIfBefore(STATE_SORTING); } - private void onFinalizeFilterInvalidated(NotifFilter filter) { + private void onFinalizeFilterInvalidated(NotifFilter filter, @Nullable String reason) { Assert.isMainThread(); - mLogger.logFinalizeFilterInvalidated(filter.getName(), mPipelineState.getState()); + mLogger.logFinalizeFilterInvalidated(filter, mPipelineState.getState(), reason); rebuildListIfBefore(STATE_FINALIZE_FILTERING); } - private void onNotifComparatorInvalidated(NotifComparator comparator) { + private void onNotifComparatorInvalidated(NotifComparator comparator, @Nullable String reason) { Assert.isMainThread(); - mLogger.logNotifComparatorInvalidated(comparator.getName(), mPipelineState.getState()); + mLogger.logNotifComparatorInvalidated(comparator, mPipelineState.getState(), reason); rebuildListIfBefore(STATE_SORTING); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java index 7293953eb8d3..3627b4084ec7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java @@ -142,7 +142,7 @@ public class BubbleCoordinator implements Coordinator { @Override public void invalidateNotifications(String reason) { - mNotifFilter.invalidateList(); + mNotifFilter.invalidateList(reason); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DebugModeCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DebugModeCoordinator.kt index df54ccd85e73..240540515705 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DebugModeCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DebugModeCoordinator.kt @@ -30,12 +30,12 @@ class DebugModeCoordinator @Inject constructor( ) : Coordinator { override fun attach(pipeline: NotifPipeline) { - pipeline.addPreGroupFilter(preGroupFilter) - debugModeFilterProvider.registerInvalidationListener(preGroupFilter::invalidateList) + pipeline.addPreGroupFilter(filter) + debugModeFilterProvider.registerInvalidationListener { filter.invalidateList(null) } } - private val preGroupFilter = object : NotifFilter("DebugModeCoordinator") { + private val filter = object : NotifFilter("DebugModeFilter") { override fun shouldFilterOut(entry: NotificationEntry, now: Long) = debugModeFilterProvider.shouldFilterOut(entry) } -}
\ No newline at end of file +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java index e8652493da6b..058042c4bccd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java @@ -90,7 +90,7 @@ public class DeviceProvisionedCoordinator implements Coordinator { new DeviceProvisionedController.DeviceProvisionedListener() { @Override public void onDeviceProvisionedChanged() { - mNotifFilter.invalidateList(); + mNotifFilter.invalidateList("onDeviceProvisionedChanged"); } }; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt index a61db4107c94..8278b549a7a0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt @@ -35,6 +35,7 @@ import com.android.systemui.statusbar.notification.collection.render.NodeControl import com.android.systemui.statusbar.notification.dagger.IncomingHeader import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider +import com.android.systemui.statusbar.notification.logKey import com.android.systemui.statusbar.notification.stack.BUCKET_HEADS_UP import com.android.systemui.statusbar.policy.HeadsUpManager import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener @@ -278,8 +279,8 @@ class HeadsUpCoordinator @Inject constructor( .firstOrNull() ?.let { posted -> posted.entry.takeIf { entry -> - locationLookupByKey(entry.key) == GroupLocation.Isolated - && entry.sbn.notification.groupAlertBehavior == GROUP_ALERT_SUMMARY + locationLookupByKey(entry.key) == GroupLocation.Isolated && + entry.sbn.notification.groupAlertBehavior == GROUP_ALERT_SUMMARY } } @@ -512,7 +513,7 @@ class HeadsUpCoordinator @Inject constructor( private val mOnHeadsUpChangedListener = object : OnHeadsUpChangedListener { override fun onHeadsUpStateChanged(entry: NotificationEntry, isHeadsUp: Boolean) { if (!isHeadsUp) { - mNotifPromoter.invalidateList() + mNotifPromoter.invalidateList("headsUpEnded: ${entry.logKey}") mHeadsUpViewBinder.unbindHeadsUpView(entry) endNotifLifetimeExtensionIfExtended(entry) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinator.java index 7b5cf8511900..e4e2bc16b77e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinator.java @@ -41,14 +41,11 @@ import javax.inject.Inject; @CoordinatorScope public class HideNotifsForOtherUsersCoordinator implements Coordinator { private final NotificationLockscreenUserManager mLockscreenUserManager; - private final SharedCoordinatorLogger mLogger; @Inject public HideNotifsForOtherUsersCoordinator( - NotificationLockscreenUserManager lockscreenUserManager, - SharedCoordinatorLogger logger) { + NotificationLockscreenUserManager lockscreenUserManager) { mLockscreenUserManager = lockscreenUserManager; - mLogger = logger; } @Override @@ -70,23 +67,19 @@ public class HideNotifsForOtherUsersCoordinator implements Coordinator { // changes @Override public void onCurrentProfilesChanged(SparseArray<UserInfo> currentProfiles) { - mLogger.logUserOrProfileChanged( - mLockscreenUserManager.getCurrentUserId(), - profileIdsToStr(currentProfiles)); - mFilter.invalidateList(); + StringBuilder sb = new StringBuilder("onCurrentProfilesChanged:"); + sb.append(" user=").append(mLockscreenUserManager.getCurrentUserId()); + sb.append(" profiles="); + sb.append("{"); + for (int i = 0; i < currentProfiles.size(); i++) { + if (i != 0) { + sb.append(","); + } + sb.append(currentProfiles.keyAt(i)); + } + sb.append("}"); + mFilter.invalidateList(sb.toString()); } }; - private String profileIdsToStr(SparseArray<UserInfo> currentProfiles) { - StringBuilder sb = new StringBuilder(); - sb.append("{"); - for (int i = 0; i < currentProfiles.size(); i++) { - sb.append(currentProfiles.keyAt(i)); - if (i < currentProfiles.size() - 1) { - sb.append(","); - } - } - sb.append("}"); - return sb.toString(); - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java index ef63be0633bf..e3d71c8b29d9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java @@ -38,18 +38,15 @@ public class KeyguardCoordinator implements Coordinator { private static final String TAG = "KeyguardCoordinator"; private final KeyguardNotificationVisibilityProvider mKeyguardNotificationVisibilityProvider; private final SectionHeaderVisibilityProvider mSectionHeaderVisibilityProvider; - private final SharedCoordinatorLogger mLogger; private final StatusBarStateController mStatusBarStateController; @Inject public KeyguardCoordinator( KeyguardNotificationVisibilityProvider keyguardNotificationVisibilityProvider, SectionHeaderVisibilityProvider sectionHeaderVisibilityProvider, - SharedCoordinatorLogger logger, StatusBarStateController statusBarStateController) { mKeyguardNotificationVisibilityProvider = keyguardNotificationVisibilityProvider; mSectionHeaderVisibilityProvider = sectionHeaderVisibilityProvider; - mLogger = logger; mStatusBarStateController = statusBarStateController; } @@ -78,9 +75,8 @@ public class KeyguardCoordinator implements Coordinator { } private void invalidateListFromFilter(String reason) { - mLogger.logKeyguardCoordinatorInvalidated(reason); updateSectionHeadersVisibility(); - mNotifFilter.invalidateList(); + mNotifFilter.invalidateList(reason); } private void updateSectionHeadersVisibility() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java index 023c4ef2b8b7..ef1e57b4cd3b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.notification.collection.coordinator; +import static com.android.systemui.statusbar.notification.NotificationUtils.logKey; import static com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer.NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED; import static java.util.Objects.requireNonNull; @@ -147,7 +148,8 @@ public class PreparationCoordinator implements Coordinator { @Override public void attach(NotifPipeline pipeline) { mNotifErrorManager.addInflationErrorListener(mInflationErrorListener); - mAdjustmentProvider.addDirtyListener(mNotifInflatingFilter::invalidateList); + mAdjustmentProvider.addDirtyListener( + () -> mNotifInflatingFilter.invalidateList("adjustmentProviderChanged")); pipeline.addCollectionListener(mNotifCollectionListener); // Inflate after grouping/sorting since that affects what views to inflate. @@ -245,12 +247,13 @@ public class PreparationCoordinator implements Coordinator { } catch (RemoteException ex) { // System server is dead, nothing to do about that } - mNotifInflationErrorFilter.invalidateList(); + mNotifInflationErrorFilter.invalidateList("onNotifInflationError for " + logKey(entry)); } @Override public void onNotifInflationErrorCleared(NotificationEntry entry) { - mNotifInflationErrorFilter.invalidateList(); + mNotifInflationErrorFilter.invalidateList( + "onNotifInflationErrorCleared for " + logKey(entry)); } }; @@ -360,9 +363,11 @@ public class PreparationCoordinator implements Coordinator { } private void abortInflation(NotificationEntry entry, String reason) { - mLogger.logInflationAborted(entry, reason); - mNotifInflater.abortInflation(entry); - mInflatingNotifs.remove(entry); + final boolean taskAborted = mNotifInflater.abortInflation(entry); + final boolean wasInflating = mInflatingNotifs.remove(entry); + if (taskAborted || wasInflating) { + mLogger.logInflationAborted(entry, reason); + } } private void onInflationFinished(NotificationEntry entry, NotifViewController controller) { @@ -371,7 +376,7 @@ public class PreparationCoordinator implements Coordinator { mViewBarn.registerViewForEntry(entry, controller); mInflationStates.put(entry, STATE_INFLATED); mBindEventManager.notifyViewBound(entry); - mNotifInflatingFilter.invalidateList(); + mNotifInflatingFilter.invalidateList("onInflationFinished for " + logKey(entry)); } private void freeNotifViews(NotificationEntry entry) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java index 5ac481341d43..67a8a63ad7da 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java @@ -199,7 +199,7 @@ public class RankingCoordinator implements Coordinator { new StatusBarStateController.StateListener() { @Override public void onDozingChanged(boolean isDozing) { - mDndVisualEffectsFilter.invalidateList(); + mDndVisualEffectsFilter.invalidateList("onDozingChanged to " + isDozing); } }; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt index 3f8a39f62dfb..aeeeb4fb054d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt @@ -64,7 +64,7 @@ private class SensitiveContentCoordinatorImpl @Inject constructor( pipeline.addPreRenderInvalidator(this) } - override fun onDynamicPrivacyChanged(): Unit = invalidateList() + override fun onDynamicPrivacyChanged(): Unit = invalidateList("onDynamicPrivacyChanged") override fun onBeforeRenderList(entries: List<ListEntry>) { if (keyguardStateController.isKeyguardGoingAway() || diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SharedCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SharedCoordinatorLogger.kt deleted file mode 100644 index 25bc641f0a84..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SharedCoordinatorLogger.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2020 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.systemui.statusbar.notification.collection.coordinator - -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel -import com.android.systemui.log.dagger.NotificationLog -import javax.inject.Inject - -/** - * Shared logging class for coordinators that don't log enough to merit their own logger. - */ -class SharedCoordinatorLogger @Inject constructor( - @NotificationLog private val buffer: LogBuffer -) { - fun logUserOrProfileChanged(userId: Int, profiles: String) { - buffer.log("NotCurrentUserFilter", LogLevel.INFO, { - int1 = userId - str1 = profiles - }, { - "Current user or profiles changed. Current user is $int1; profiles are $str1" - }) - } - - fun logKeyguardCoordinatorInvalidated(reason: String) { - buffer.log("KeyguardCoordinator", LogLevel.DEBUG, { - str1 = reason - }, { - "KeyguardCoordinator invalidated: $str1" - }) - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinator.kt index ce361ea88bdc..9d0f974ea68f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinator.kt @@ -30,6 +30,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener +import com.android.systemui.statusbar.notification.logKey import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.time.SystemClock import java.util.concurrent.TimeUnit.SECONDS @@ -130,7 +131,7 @@ class SmartspaceDedupingCoordinator @Inject constructor( } if (changed) { - filter.invalidateList() + filter.invalidateList("onNewSmartspaceTargets") notificationEntryManager.updateNotifications("Smartspace targets changed") } @@ -167,7 +168,7 @@ class SmartspaceDedupingCoordinator @Inject constructor( target.cancelTimeoutRunnable = executor.executeDelayed({ target.cancelTimeoutRunnable = null target.shouldFilter = true - filter.invalidateList() + filter.invalidateList("updateAlertException: ${entry.logKey}") notificationEntryManager.updateNotifications("deduping timeout expired") }, alertExceptionExpires - now) } @@ -184,7 +185,7 @@ class SmartspaceDedupingCoordinator @Inject constructor( isOnLockscreen = newState == StatusBarState.KEYGUARD if (isOnLockscreen != wasOnLockscreen) { - filter.invalidateList() + filter.invalidateList("recordStatusBarState: " + StatusBarState.toString(newState)) // No need to call notificationEntryManager.updateNotifications; something else already // does it for us when the keyguard state changes } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java index b9d23b4a344a..0833df505bf3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java @@ -192,11 +192,16 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable, + " reorderingAllowed " + wasReorderingAllowed + "->" + mReorderingAllowed + " when setting " + field + "=" + value); } - if ((mPipelineRunAllowed && mIsSuppressingPipelineRun) - || (mReorderingAllowed && (mIsSuppressingGroupChange - || isSuppressingSectionChange() - || mIsSuppressingEntryReorder))) { - mNotifStabilityManager.invalidateList(); + if (mPipelineRunAllowed && mIsSuppressingPipelineRun) { + mNotifStabilityManager.invalidateList("pipeline run suppression ended"); + } else if (mReorderingAllowed && (mIsSuppressingGroupChange + || isSuppressingSectionChange() + || mIsSuppressingEntryReorder)) { + String reason = "reorder suppression ended for" + + " group=" + mIsSuppressingGroupChange + + " section=" + isSuppressingSectionChange() + + " sort=" + mIsSuppressingEntryReorder; + mNotifStabilityManager.invalidateList(reason); } mVisualStabilityProvider.setReorderingAllowed(mReorderingAllowed); } @@ -241,7 +246,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable, now + ALLOW_SECTION_CHANGE_TIMEOUT)); if (!wasSectionChangeAllowed) { - mNotifStabilityManager.invalidateList(); + mNotifStabilityManager.invalidateList("temporarilyAllowSectionChanges"); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt index 567ec85cf6c7..08e21e8f668e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt @@ -42,9 +42,9 @@ interface NotifInflater { /** * Request to stop the inflation of an entry. For example, called when a notification is - * removed and no longer needs to be inflated. + * removed and no longer needs to be inflated. Returns whether anything may have been aborted. */ - fun abortInflation(entry: NotificationEntry) + fun abortInflation(entry: NotificationEntry): Boolean /** * Called to let the system remove the content views from the notification row. @@ -62,4 +62,4 @@ interface NotifInflater { * A class holding parameters used when inflating the notification row */ class Params(val isLowPriority: Boolean, val reason: String) -}
\ No newline at end of file +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt index 10a627d65b83..4c406e3ba0b4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt @@ -25,8 +25,15 @@ import com.android.systemui.statusbar.notification.NotifPipelineFlags import com.android.systemui.statusbar.notification.collection.GroupEntry import com.android.systemui.statusbar.notification.collection.ListEntry import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.StateName +import com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.getStateName +import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Invalidator +import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter +import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner +import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager +import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable import com.android.systemui.statusbar.notification.logKey import com.android.systemui.util.Compile import javax.inject.Inject @@ -60,68 +67,63 @@ class ShadeListBuilderLogger @Inject constructor( }) } - fun logPreRenderInvalidated(filterName: String, pipelineState: Int) { + private fun logPluggableInvalidated( + type: String, + pluggable: Pluggable<*>, + @StateName pipelineState: Int, + reason: String? + ) { buffer.log(TAG, DEBUG, { - str1 = filterName + str1 = type + str2 = pluggable.name int1 = pipelineState + str3 = reason }, { - """Pre-render Invalidator "$str1" invalidated; pipeline state is $int1""" + """Invalidated while ${getStateName(int1)} by $str1 "$str2" because $str3""" }) } - fun logPreGroupFilterInvalidated(filterName: String, pipelineState: Int) { - buffer.log(TAG, DEBUG, { - str1 = filterName - int1 = pipelineState - }, { - """Pre-group NotifFilter "$str1" invalidated; pipeline state is $int1""" - }) - } + fun logPreRenderInvalidated( + invalidator: Invalidator, + @StateName pipelineState: Int, + reason: String? + ) = logPluggableInvalidated("Pre-render Invalidator", invalidator, pipelineState, reason) - fun logReorderingAllowedInvalidated(name: String, pipelineState: Int) { - buffer.log(TAG, DEBUG, { - str1 = name - int1 = pipelineState - }, { - """ReorderingNowAllowed "$str1" invalidated; pipeline state is $int1""" - }) - } + fun logPreGroupFilterInvalidated( + filter: NotifFilter, + @StateName pipelineState: Int, + reason: String? + ) = logPluggableInvalidated("Pre-group NotifFilter", filter, pipelineState, reason) - fun logPromoterInvalidated(name: String, pipelineState: Int) { - buffer.log(TAG, DEBUG, { - str1 = name - int1 = pipelineState - }, { - """NotifPromoter "$str1" invalidated; pipeline state is $int1""" - }) - } + fun logReorderingAllowedInvalidated( + stabilityManager: NotifStabilityManager, + @StateName pipelineState: Int, + reason: String? + ) = logPluggableInvalidated("ReorderingNowAllowed", stabilityManager, pipelineState, reason) - fun logNotifSectionInvalidated(name: String, pipelineState: Int) { - buffer.log(TAG, DEBUG, { - str1 = name - int1 = pipelineState - }, { - """NotifSection "$str1" invalidated; pipeline state is $int1""" - }) - } + fun logPromoterInvalidated( + promoter: NotifPromoter, + @StateName pipelineState: Int, + reason: String? + ) = logPluggableInvalidated("NotifPromoter", promoter, pipelineState, reason) - fun logNotifComparatorInvalidated(name: String, pipelineState: Int) { - buffer.log(TAG, DEBUG, { - str1 = name - int1 = pipelineState - }, { - """NotifComparator "$str1" invalidated; pipeline state is $int1""" - }) - } + fun logNotifSectionInvalidated( + sectioner: NotifSectioner, + @StateName pipelineState: Int, + reason: String? + ) = logPluggableInvalidated("NotifSection", sectioner, pipelineState, reason) - fun logFinalizeFilterInvalidated(name: String, pipelineState: Int) { - buffer.log(TAG, DEBUG, { - str1 = name - int1 = pipelineState - }, { - """Finalize NotifFilter "$str1" invalidated; pipeline state is $int1""" - }) - } + fun logNotifComparatorInvalidated( + comparator: NotifComparator, + @StateName pipelineState: Int, + reason: String? + ) = logPluggableInvalidated("NotifComparator", comparator, pipelineState, reason) + + fun logFinalizeFilterInvalidated( + filter: NotifFilter, + @StateName pipelineState: Int, + reason: String? + ) = logPluggableInvalidated("Finalize NotifFilter", filter, pipelineState, reason) fun logDuplicateSummary( buildId: Int, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java index b981a9621526..966ab4c61b50 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java @@ -49,10 +49,10 @@ public abstract class Pluggable<This> { * Call this method when something has caused this pluggable's behavior to change. The pipeline * will be re-run. */ - public final void invalidateList() { + public final void invalidateList(@Nullable String reason) { if (mListener != null) { Trace.beginSection("Pluggable<" + mName + ">.invalidateList"); - mListener.onPluggableInvalidated((This) this); + mListener.onPluggableInvalidated((This) this, reason); Trace.endSection(); } } @@ -74,7 +74,7 @@ public abstract class Pluggable<This> { * @param <T> The type of pluggable that is being listened to. */ public interface PluggableListener<T> { - /** Called whenever {@link #invalidateList()} is called on this pluggable. */ - void onPluggableInvalidated(T pluggable); + /** Called whenever {@link #invalidateList(String)} is called on this pluggable. */ + void onPluggableInvalidated(T pluggable, @Nullable String reason); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java index 2daa4759457d..6258deda804f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -2721,7 +2721,8 @@ public class CentralSurfacesImpl extends CoreStartable implements @Override public void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction, boolean afterKeyguardGone) { - if (mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_ASLEEP + if (!action.willRunAnimationOnKeyguard() + && mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_ASLEEP && mKeyguardStateController.canDismissLockScreen() && !mStatusBarStateController.leaveOpenOnKeyguardHide() && mDozeServiceHost.isPulsing()) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java index 5bd20ff2d090..a29ba916eb41 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java @@ -68,6 +68,7 @@ public class BrightnessMirrorController mBrightnessMirror.setVisibility(View.INVISIBLE); }); mVisibilityCallback = visibilityCallback; + updateResources(); } public void showMirror() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/camera/CameraGestureHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/camera/CameraGestureHelperTest.kt new file mode 100644 index 000000000000..ca94ea826782 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/camera/CameraGestureHelperTest.kt @@ -0,0 +1,311 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.camera + +import android.app.ActivityManager +import android.app.IActivityTaskManager +import android.content.ComponentName +import android.content.ContentResolver +import android.content.Intent +import android.content.pm.ActivityInfo +import android.content.pm.PackageManager +import android.content.pm.ResolveInfo +import androidx.test.filters.SmallTest +import com.android.systemui.ActivityIntentHelper +import com.android.systemui.SysuiTestCase +import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.statusbar.StatusBarState +import com.android.systemui.statusbar.phone.CentralSurfaces +import com.android.systemui.statusbar.policy.KeyguardStateController +import com.android.systemui.util.mockito.KotlinArgumentCaptor +import com.android.systemui.util.mockito.eq +import com.android.systemui.util.mockito.mock +import com.google.common.truth.Truth.assertThat +import com.google.common.util.concurrent.MoreExecutors +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.mockito.Mock +import org.mockito.Mockito.any +import org.mockito.Mockito.anyInt +import org.mockito.Mockito.verify +import org.mockito.Mockito.`when` as whenever +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(JUnit4::class) +class CameraGestureHelperTest : SysuiTestCase() { + + @Mock + lateinit var centralSurfaces: CentralSurfaces + @Mock + lateinit var keyguardStateController: KeyguardStateController + @Mock + lateinit var packageManager: PackageManager + @Mock + lateinit var activityManager: ActivityManager + @Mock + lateinit var activityStarter: ActivityStarter + @Mock + lateinit var activityIntentHelper: ActivityIntentHelper + @Mock + lateinit var activityTaskManager: IActivityTaskManager + @Mock + lateinit var cameraIntents: CameraIntentsWrapper + @Mock + lateinit var contentResolver: ContentResolver + + private lateinit var underTest: CameraGestureHelper + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + whenever(cameraIntents.getSecureCameraIntent()).thenReturn( + Intent(CameraIntents.DEFAULT_SECURE_CAMERA_INTENT_ACTION) + ) + whenever(cameraIntents.getInsecureCameraIntent()).thenReturn( + Intent(CameraIntents.DEFAULT_INSECURE_CAMERA_INTENT_ACTION) + ) + + prepare() + + underTest = CameraGestureHelper( + context = mock(), + centralSurfaces = centralSurfaces, + keyguardStateController = keyguardStateController, + packageManager = packageManager, + activityManager = activityManager, + activityStarter = activityStarter, + activityIntentHelper = activityIntentHelper, + activityTaskManager = activityTaskManager, + cameraIntents = cameraIntents, + contentResolver = contentResolver, + uiExecutor = MoreExecutors.directExecutor(), + ) + } + + /** + * Prepares for tests by setting up the various mocks to emulate a specific device state. + * + * <p>Safe to call multiple times in a single test (for example, once in [setUp] and once in the + * actual test case). + * + * @param isCameraAllowedByAdmin Whether the device administrator allows use of the camera app + * @param installedCameraAppCount The number of installed camera apps on the device + * @param isUsingSecureScreenLockOption Whether the user-controlled setting for Screen Lock is + * set with a "secure" option that requires the user to provide some secret/credentials to be + * able to unlock the device, for example "Face Unlock", "PIN", or "Password". Examples of + * non-secure options are "None" and "Swipe" + * @param isCameraActivityRunningOnTop Whether the camera activity is running at the top of the + * most recent/current task of activities + * @param isTaskListEmpty Whether there are no active activity tasks at all. Note that this is + * treated as `false` if [isCameraActivityRunningOnTop] is set to `true` + */ + private fun prepare( + isCameraAllowedByAdmin: Boolean = true, + installedCameraAppCount: Int = 1, + isUsingSecureScreenLockOption: Boolean = true, + isCameraActivityRunningOnTop: Boolean = false, + isTaskListEmpty: Boolean = false, + ) { + whenever(centralSurfaces.isCameraAllowedByAdmin).thenReturn(isCameraAllowedByAdmin) + + whenever(activityIntentHelper.wouldLaunchResolverActivity(any(), anyInt())) + .thenReturn(installedCameraAppCount > 1) + + whenever(keyguardStateController.isMethodSecure).thenReturn(isUsingSecureScreenLockOption) + whenever(keyguardStateController.canDismissLockScreen()) + .thenReturn(!isUsingSecureScreenLockOption) + + if (installedCameraAppCount >= 1) { + val resolveInfo = ResolveInfo().apply { + this.activityInfo = ActivityInfo().apply { + packageName = CAMERA_APP_PACKAGE_NAME + } + } + whenever(packageManager.resolveActivityAsUser(any(), anyInt(), anyInt())).thenReturn( + resolveInfo + ) + } else { + whenever(packageManager.resolveActivityAsUser(any(), anyInt(), anyInt())).thenReturn( + null + ) + } + + when { + isCameraActivityRunningOnTop -> { + val runningTaskInfo = ActivityManager.RunningTaskInfo().apply { + topActivity = ComponentName(CAMERA_APP_PACKAGE_NAME, "cameraActivity") + } + whenever(activityManager.getRunningTasks(anyInt())).thenReturn( + listOf( + runningTaskInfo + ) + ) + } + isTaskListEmpty -> { + whenever(activityManager.getRunningTasks(anyInt())).thenReturn(emptyList()) + } + else -> { + whenever(activityManager.getRunningTasks(anyInt())).thenReturn(listOf()) + } + } + } + + @Test + fun `canCameraGestureBeLaunched - status bar state is keyguard - returns true`() { + assertThat(underTest.canCameraGestureBeLaunched(StatusBarState.KEYGUARD)).isTrue() + } + + @Test + fun `canCameraGestureBeLaunched - state is shade-locked - returns true`() { + assertThat(underTest.canCameraGestureBeLaunched(StatusBarState.SHADE_LOCKED)).isTrue() + } + + @Test + fun `canCameraGestureBeLaunched - state is keyguard - camera activity on top - returns true`() { + prepare(isCameraActivityRunningOnTop = true) + + assertThat(underTest.canCameraGestureBeLaunched(StatusBarState.KEYGUARD)).isTrue() + } + + @Test + fun `canCameraGestureBeLaunched - state is shade-locked - camera activity on top - true`() { + prepare(isCameraActivityRunningOnTop = true) + + assertThat(underTest.canCameraGestureBeLaunched(StatusBarState.SHADE_LOCKED)).isTrue() + } + + @Test + fun `canCameraGestureBeLaunched - not allowed by admin - returns false`() { + prepare(isCameraAllowedByAdmin = false) + + assertThat(underTest.canCameraGestureBeLaunched(StatusBarState.KEYGUARD)).isFalse() + } + + @Test + fun `canCameraGestureBeLaunched - intent does not resolve to any app - returns false`() { + prepare(installedCameraAppCount = 0) + + assertThat(underTest.canCameraGestureBeLaunched(StatusBarState.KEYGUARD)).isFalse() + } + + @Test + fun `canCameraGestureBeLaunched - state is shade - no running tasks - returns true`() { + prepare(isCameraActivityRunningOnTop = false, isTaskListEmpty = true) + + assertThat(underTest.canCameraGestureBeLaunched(StatusBarState.SHADE)).isTrue() + } + + @Test + fun `canCameraGestureBeLaunched - state is shade - camera activity on top - returns false`() { + prepare(isCameraActivityRunningOnTop = true) + + assertThat(underTest.canCameraGestureBeLaunched(StatusBarState.SHADE)).isFalse() + } + + @Test + fun `canCameraGestureBeLaunched - state is shade - camera activity not on top - true`() { + assertThat(underTest.canCameraGestureBeLaunched(StatusBarState.SHADE)).isTrue() + } + + @Test + fun `launchCamera - only one camera app installed - using secure screen lock option`() { + val source = 1337 + + underTest.launchCamera(source) + + assertActivityStarting(isSecure = true, source = source) + } + + @Test + fun `launchCamera - only one camera app installed - using non-secure screen lock option`() { + prepare(isUsingSecureScreenLockOption = false) + val source = 1337 + + underTest.launchCamera(source) + + assertActivityStarting(isSecure = false, source = source) + } + + @Test + fun `launchCamera - multiple camera apps installed - using secure screen lock option`() { + prepare(installedCameraAppCount = 2) + val source = 1337 + + underTest.launchCamera(source) + + assertActivityStarting( + isSecure = true, + source = source, + moreThanOneCameraAppInstalled = true + ) + } + + @Test + fun `launchCamera - multiple camera apps installed - using non-secure screen lock option`() { + prepare( + isUsingSecureScreenLockOption = false, + installedCameraAppCount = 2, + ) + val source = 1337 + + underTest.launchCamera(source) + + assertActivityStarting( + isSecure = false, + moreThanOneCameraAppInstalled = true, + source = source + ) + } + + private fun assertActivityStarting( + isSecure: Boolean, + source: Int, + moreThanOneCameraAppInstalled: Boolean = false, + ) { + val intentCaptor = KotlinArgumentCaptor(Intent::class.java) + if (isSecure && !moreThanOneCameraAppInstalled) { + verify(activityTaskManager).startActivityAsUser( + any(), + any(), + any(), + intentCaptor.capture(), + any(), + any(), + any(), + anyInt(), + anyInt(), + any(), + any(), + anyInt() + ) + } else { + verify(activityStarter).startActivity(intentCaptor.capture(), eq(false)) + } + val intent = intentCaptor.value + + assertThat(CameraIntents.isSecureCameraIntent(intent)).isEqualTo(isSecure) + assertThat(intent.getIntExtra(CameraGestureHelper.EXTRA_CAMERA_LAUNCH_SOURCE, -1)) + .isEqualTo(source) + } + + companion object { + private const val CAMERA_APP_PACKAGE_NAME = "cameraAppPackageName" + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java index 59475cf0cb90..226182961934 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java @@ -71,7 +71,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase { @Before public void setUp() { - mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController, mMediaOutputDialog); + mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController); mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter .onCreateViewHolder(new LinearLayout(mContext), 0); mSpyMediaOutputSeekbar = spy(mViewHolder.mSeekBar); diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupAdapterTest.java deleted file mode 100644 index 9256cd32291f..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupAdapterTest.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright (C) 2020 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.systemui.media.dialog; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.graphics.drawable.Icon; -import android.testing.AndroidTestingRunner; -import android.view.View; -import android.widget.LinearLayout; - -import androidx.core.graphics.drawable.IconCompat; -import androidx.test.filters.SmallTest; - -import com.android.settingslib.media.MediaDevice; -import com.android.systemui.R; -import com.android.systemui.SysuiTestCase; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.ArrayList; -import java.util.List; - -@SmallTest -@RunWith(AndroidTestingRunner.class) -public class MediaOutputGroupAdapterTest extends SysuiTestCase { - - private static final String TEST_DEVICE_NAME_1 = "test_device_name_1"; - private static final String TEST_DEVICE_NAME_2 = "test_device_name_2"; - private static final String TEST_DEVICE_ID_1 = "test_device_id_1"; - private static final String TEST_DEVICE_ID_2 = "test_device_id_2"; - private static final int TEST_VOLUME = 10; - private static final int TEST_MAX_VOLUME = 50; - - // Mock - private MediaOutputController mMediaOutputController = mock(MediaOutputController.class); - private MediaDevice mMediaDevice1 = mock(MediaDevice.class); - private MediaDevice mMediaDevice2 = mock(MediaDevice.class); - private Icon mIcon = mock(Icon.class); - private IconCompat mIconCompat = mock(IconCompat.class); - - private MediaOutputGroupAdapter mGroupAdapter; - private MediaOutputGroupAdapter.GroupViewHolder mGroupViewHolder; - private List<MediaDevice> mGroupMediaDevices = new ArrayList<>(); - private List<MediaDevice> mSelectableMediaDevices = new ArrayList<>(); - private List<MediaDevice> mSelectedMediaDevices = new ArrayList<>(); - private List<MediaDevice> mDeselectableMediaDevices = new ArrayList<>(); - - @Before - public void setUp() { - when(mMediaOutputController.getGroupMediaDevices()).thenReturn(mGroupMediaDevices); - when(mMediaOutputController.getDeviceIconCompat(mMediaDevice1)).thenReturn(mIconCompat); - when(mMediaOutputController.getDeviceIconCompat(mMediaDevice2)).thenReturn(mIconCompat); - when(mMediaOutputController.getSelectableMediaDevice()).thenReturn(mSelectableMediaDevices); - when(mMediaOutputController.getSelectedMediaDevice()).thenReturn(mSelectedMediaDevices); - when(mMediaOutputController.getDeselectableMediaDevice()).thenReturn( - mDeselectableMediaDevices); - when(mIconCompat.toIcon(mContext)).thenReturn(mIcon); - when(mMediaDevice1.getName()).thenReturn(TEST_DEVICE_NAME_1); - when(mMediaDevice1.getId()).thenReturn(TEST_DEVICE_ID_1); - when(mMediaDevice2.getName()).thenReturn(TEST_DEVICE_NAME_2); - when(mMediaDevice2.getId()).thenReturn(TEST_DEVICE_ID_2); - mGroupMediaDevices.add(mMediaDevice1); - mGroupMediaDevices.add(mMediaDevice2); - mSelectedMediaDevices.add(mMediaDevice1); - mSelectableMediaDevices.add(mMediaDevice2); - mDeselectableMediaDevices.add(mMediaDevice1); - - mGroupAdapter = new MediaOutputGroupAdapter(mMediaOutputController); - mGroupViewHolder = (MediaOutputGroupAdapter.GroupViewHolder) mGroupAdapter - .onCreateViewHolder(new LinearLayout(mContext), 0); - } - - @Test - public void onBindViewHolder_verifyGroupItem() { - mGroupAdapter.onBindViewHolder(mGroupViewHolder, 0); - - assertThat(mGroupViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE); - assertThat(mGroupViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE); - assertThat(mGroupViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE); - assertThat(mGroupViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE); - assertThat(mGroupViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE); - assertThat(mGroupViewHolder.mTwoLineTitleText.getVisibility()).isEqualTo(View.VISIBLE); - assertThat(mGroupViewHolder.mTwoLineTitleText.getText()).isEqualTo(mContext.getText( - R.string.media_output_dialog_group)); - } - - @Test - public void onBindViewHolder_singleSelectedDevice_verifyView() { - mGroupAdapter.onBindViewHolder(mGroupViewHolder, 1); - - assertThat(mGroupViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE); - assertThat(mGroupViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE); - assertThat(mGroupViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE); - assertThat(mGroupViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE); - assertThat(mGroupViewHolder.mTwoLineTitleText.getVisibility()).isEqualTo(View.VISIBLE); - assertThat(mGroupViewHolder.mTwoLineTitleText.getText()).isEqualTo(TEST_DEVICE_NAME_1); - assertThat(mGroupViewHolder.mCheckBox.getVisibility()).isEqualTo(View.VISIBLE); - assertThat(mGroupViewHolder.mCheckBox.isChecked()).isTrue(); - // Disabled checkBox - assertThat(mGroupViewHolder.mCheckBox.isEnabled()).isFalse(); - } - - @Test - public void onBindViewHolder_multipleSelectedDevice_verifyView() { - mSelectedMediaDevices.clear(); - mSelectedMediaDevices.add(mMediaDevice1); - mSelectedMediaDevices.add(mMediaDevice2); - mDeselectableMediaDevices.clear(); - mDeselectableMediaDevices.add(mMediaDevice1); - mDeselectableMediaDevices.add(mMediaDevice2); - mSelectableMediaDevices.clear(); - - mGroupAdapter.onBindViewHolder(mGroupViewHolder, 1); - - assertThat(mGroupViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE); - assertThat(mGroupViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE); - assertThat(mGroupViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE); - assertThat(mGroupViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE); - assertThat(mGroupViewHolder.mTwoLineTitleText.getVisibility()).isEqualTo(View.VISIBLE); - assertThat(mGroupViewHolder.mTwoLineTitleText.getText()).isEqualTo(TEST_DEVICE_NAME_1); - assertThat(mGroupViewHolder.mCheckBox.getVisibility()).isEqualTo(View.VISIBLE); - assertThat(mGroupViewHolder.mCheckBox.isChecked()).isTrue(); - // Enabled checkBox - assertThat(mGroupViewHolder.mCheckBox.isEnabled()).isTrue(); - } - - @Test - public void onBindViewHolder_notDeselectedDevice_verifyView() { - mSelectedMediaDevices.clear(); - mSelectedMediaDevices.add(mMediaDevice1); - mSelectedMediaDevices.add(mMediaDevice2); - mDeselectableMediaDevices.clear(); - mDeselectableMediaDevices.add(mMediaDevice1); - mSelectableMediaDevices.clear(); - - mGroupAdapter.onBindViewHolder(mGroupViewHolder, 2); - - assertThat(mGroupViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE); - assertThat(mGroupViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE); - assertThat(mGroupViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE); - assertThat(mGroupViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE); - assertThat(mGroupViewHolder.mTwoLineTitleText.getVisibility()).isEqualTo(View.VISIBLE); - assertThat(mGroupViewHolder.mTwoLineTitleText.getText()).isEqualTo(TEST_DEVICE_NAME_2); - assertThat(mGroupViewHolder.mCheckBox.getVisibility()).isEqualTo(View.VISIBLE); - assertThat(mGroupViewHolder.mCheckBox.isChecked()).isTrue(); - // Disabled checkBox - assertThat(mGroupViewHolder.mCheckBox.isEnabled()).isFalse(); - } - - @Test - public void onBindViewHolder_selectableDevice_verifyCheckBox() { - mGroupAdapter.onBindViewHolder(mGroupViewHolder, 2); - - assertThat(mGroupViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE); - assertThat(mGroupViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE); - assertThat(mGroupViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE); - assertThat(mGroupViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE); - assertThat(mGroupViewHolder.mTwoLineTitleText.getVisibility()).isEqualTo(View.VISIBLE); - assertThat(mGroupViewHolder.mTwoLineTitleText.getText()).isEqualTo(TEST_DEVICE_NAME_2); - assertThat(mGroupViewHolder.mCheckBox.getVisibility()).isEqualTo(View.VISIBLE); - assertThat(mGroupViewHolder.mCheckBox.isChecked()).isFalse(); - // Enabled checkBox - assertThat(mGroupViewHolder.mCheckBox.isEnabled()).isTrue(); - } - - @Test - public void onBindViewHolder_verifyDeviceVolume() { - when(mMediaDevice1.getCurrentVolume()).thenReturn(TEST_VOLUME); - when(mMediaDevice1.getMaxVolume()).thenReturn(TEST_MAX_VOLUME); - mGroupViewHolder.mSeekBar.setVisibility(View.VISIBLE); - - mGroupAdapter.onBindViewHolder(mGroupViewHolder, 1); - - assertThat(mGroupViewHolder.mSeekBar.getVolume()).isEqualTo(TEST_VOLUME); - } - - @Test - public void clickSelectedDevice_verifyRemoveDeviceFromPlayMedia() { - mSelectedMediaDevices.clear(); - mSelectedMediaDevices.add(mMediaDevice1); - mSelectedMediaDevices.add(mMediaDevice2); - mDeselectableMediaDevices.clear(); - mDeselectableMediaDevices.add(mMediaDevice1); - mDeselectableMediaDevices.add(mMediaDevice2); - mSelectableMediaDevices.clear(); - - mGroupAdapter.onBindViewHolder(mGroupViewHolder, 1); - mGroupViewHolder.mCheckBox.performClick(); - - verify(mMediaOutputController).removeDeviceFromPlayMedia(mMediaDevice1); - } - - @Test - public void clickSelectabelDevice_verifyAddDeviceToPlayMedia() { - mGroupAdapter.onBindViewHolder(mGroupViewHolder, 2); - - mGroupViewHolder.mCheckBox.performClick(); - - verify(mMediaOutputController).addDeviceToPlayMedia(mMediaDevice2); - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java deleted file mode 100644 index 4534ae6448ec..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2020 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.systemui.media.dialog; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import android.media.AudioManager; -import android.media.session.MediaSessionManager; -import android.os.PowerExemptionManager; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; -import android.view.View; - -import androidx.test.filters.SmallTest; - -import com.android.settingslib.bluetooth.LocalBluetoothManager; -import com.android.settingslib.media.LocalMediaManager; -import com.android.settingslib.media.MediaDevice; -import com.android.systemui.R; -import com.android.systemui.SysuiTestCase; -import com.android.systemui.animation.DialogLaunchAnimator; -import com.android.systemui.broadcast.BroadcastSender; -import com.android.systemui.media.nearby.NearbyMediaDevicesManager; -import com.android.systemui.plugins.ActivityStarter; -import com.android.systemui.statusbar.notification.NotificationEntryManager; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -@SmallTest -@RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper -public class MediaOutputGroupDialogTest extends SysuiTestCase { - - private static final String TEST_PACKAGE = "test_package"; - - // Mock - private MediaSessionManager mMediaSessionManager = mock(MediaSessionManager.class); - private LocalBluetoothManager mLocalBluetoothManager = mock(LocalBluetoothManager.class); - private ActivityStarter mStarter = mock(ActivityStarter.class); - private BroadcastSender mBroadcastSender = mock(BroadcastSender.class); - private LocalMediaManager mLocalMediaManager = mock(LocalMediaManager.class); - private MediaDevice mMediaDevice = mock(MediaDevice.class); - private MediaDevice mMediaDevice1 = mock(MediaDevice.class); - private NotificationEntryManager mNotificationEntryManager = - mock(NotificationEntryManager.class); - private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class); - private NearbyMediaDevicesManager mNearbyMediaDevicesManager = mock( - NearbyMediaDevicesManager.class); - private final AudioManager mAudioManager = mock(AudioManager.class); - private PowerExemptionManager mPowerExemptionManager = mock(PowerExemptionManager.class); - - private MediaOutputGroupDialog mMediaOutputGroupDialog; - private MediaOutputController mMediaOutputController; - private List<MediaDevice> mMediaDevices = new ArrayList<>(); - - @Before - public void setUp() { - mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, - mMediaSessionManager, mLocalBluetoothManager, mStarter, - mNotificationEntryManager, mDialogLaunchAnimator, - Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager); - mMediaOutputController.mLocalMediaManager = mLocalMediaManager; - mMediaOutputGroupDialog = new MediaOutputGroupDialog(mContext, false, mBroadcastSender, - mMediaOutputController); - mMediaOutputGroupDialog.show(); - when(mLocalMediaManager.getSelectedMediaDevice()).thenReturn(mMediaDevices); - } - - @After - public void tearDown() { - mMediaOutputGroupDialog.dismissDialog(); - } - - @Test - public void getStopButtonVisibility_returnVisible() { - assertThat(mMediaOutputGroupDialog.getStopButtonVisibility()).isEqualTo(View.VISIBLE); - } - - @Test - public void getHeaderSubtitle_singleDevice_verifyTitle() { - mMediaDevices.add(mMediaDevice); - - assertThat(mMediaOutputGroupDialog.getHeaderSubtitle()).isEqualTo( - mContext.getText(R.string.media_output_dialog_single_device)); - } - - @Test - public void getHeaderSubtitle_multipleDevices_verifyTitle() { - mMediaDevices.add(mMediaDevice); - mMediaDevices.add(mMediaDevice1); - - assertThat(mMediaOutputGroupDialog.getHeaderSubtitle()).isEqualTo(mContext.getString( - R.string.media_output_dialog_multiple_devices, mMediaDevices.size())); - } - -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java index 555adfdfdc31..dfa38abc1ff8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java @@ -1028,37 +1028,37 @@ public class ShadeListBuilderTest extends SysuiTestCase { // WHEN each pluggable is invalidated THEN the list is re-rendered clearInvocations(mOnRenderListListener); - packageFilter.invalidateList(); + packageFilter.invalidateList(null); assertTrue(mPipelineChoreographer.isScheduled()); mPipelineChoreographer.runIfScheduled(); verify(mOnRenderListListener).onRenderList(anyList()); clearInvocations(mOnRenderListListener); - idPromoter.invalidateList(); + idPromoter.invalidateList(null); assertTrue(mPipelineChoreographer.isScheduled()); mPipelineChoreographer.runIfScheduled(); verify(mOnRenderListListener).onRenderList(anyList()); clearInvocations(mOnRenderListListener); - section.invalidateList(); + section.invalidateList(null); assertTrue(mPipelineChoreographer.isScheduled()); mPipelineChoreographer.runIfScheduled(); verify(mOnRenderListListener).onRenderList(anyList()); clearInvocations(mOnRenderListListener); - hypeComparator.invalidateList(); + hypeComparator.invalidateList(null); assertTrue(mPipelineChoreographer.isScheduled()); mPipelineChoreographer.runIfScheduled(); verify(mOnRenderListListener).onRenderList(anyList()); clearInvocations(mOnRenderListListener); - sectionComparator.invalidateList(); + sectionComparator.invalidateList(null); assertTrue(mPipelineChoreographer.isScheduled()); mPipelineChoreographer.runIfScheduled(); verify(mOnRenderListListener).onRenderList(anyList()); clearInvocations(mOnRenderListListener); - preRenderInvalidator.invalidateList(); + preRenderInvalidator.invalidateList(null); assertTrue(mPipelineChoreographer.isScheduled()); mPipelineChoreographer.runIfScheduled(); verify(mOnRenderListListener).onRenderList(anyList()); @@ -1584,7 +1584,7 @@ public class ShadeListBuilderTest extends SysuiTestCase { // WHEN visual stability manager allows group changes again mStabilityManager.setAllowGroupChanges(true); - mStabilityManager.invalidateList(); + mStabilityManager.invalidateList(null); mPipelineChoreographer.runIfScheduled(); // THEN entries are grouped @@ -1623,7 +1623,7 @@ public class ShadeListBuilderTest extends SysuiTestCase { // WHEN section changes are allowed again mStabilityManager.setAllowSectionChanges(true); - mStabilityManager.invalidateList(); + mStabilityManager.invalidateList(null); mPipelineChoreographer.runIfScheduled(); // THEN the section updates @@ -1719,7 +1719,7 @@ public class ShadeListBuilderTest extends SysuiTestCase { public void testOutOfOrderPreGroupFilterInvalidationThrows() { // GIVEN a PreGroupNotifFilter that gets invalidated during the grouping stage NotifFilter filter = new PackageFilter(PACKAGE_5); - OnBeforeTransformGroupsListener listener = (list) -> filter.invalidateList(); + OnBeforeTransformGroupsListener listener = (list) -> filter.invalidateList(null); mListBuilder.addPreGroupFilter(filter); mListBuilder.addOnBeforeTransformGroupsListener(listener); @@ -1735,7 +1735,7 @@ public class ShadeListBuilderTest extends SysuiTestCase { // GIVEN a NotifPromoter that gets invalidated during the sorting stage NotifPromoter promoter = new IdPromoter(47); OnBeforeSortListener listener = - (list) -> promoter.invalidateList(); + (list) -> promoter.invalidateList(null); mListBuilder.addPromoter(promoter); mListBuilder.addOnBeforeSortListener(listener); @@ -1751,7 +1751,7 @@ public class ShadeListBuilderTest extends SysuiTestCase { // GIVEN a NotifComparator that gets invalidated during the finalizing stage NotifComparator comparator = new HypeComparator(PACKAGE_5); OnBeforeRenderListListener listener = - (list) -> comparator.invalidateList(); + (list) -> comparator.invalidateList(null); mListBuilder.setComparators(singletonList(comparator)); mListBuilder.addOnBeforeRenderListListener(listener); @@ -1766,7 +1766,7 @@ public class ShadeListBuilderTest extends SysuiTestCase { public void testOutOfOrderPreRenderFilterInvalidationThrows() { // GIVEN a PreRenderNotifFilter that gets invalidated during the finalizing stage NotifFilter filter = new PackageFilter(PACKAGE_5); - OnBeforeRenderListListener listener = (list) -> filter.invalidateList(); + OnBeforeRenderListListener listener = (list) -> filter.invalidateList(null); mListBuilder.addFinalizeFilter(filter); mListBuilder.addOnBeforeRenderListListener(listener); @@ -1903,7 +1903,7 @@ public class ShadeListBuilderTest extends SysuiTestCase { public void testInOrderPreRenderFilter() { // GIVEN a PreRenderFilter that gets invalidated during the grouping stage NotifFilter filter = new PackageFilter(PACKAGE_5); - OnBeforeTransformGroupsListener listener = (list) -> filter.invalidateList(); + OnBeforeTransformGroupsListener listener = (list) -> filter.invalidateList(null); mListBuilder.addFinalizeFilter(filter); mListBuilder.addOnBeforeTransformGroupsListener(listener); @@ -1936,8 +1936,8 @@ public class ShadeListBuilderTest extends SysuiTestCase { mListBuilder.addFinalizeFilter(filter2); // WHEN both filters invalidate - filter1.invalidateList(); - filter2.invalidateList(); + filter1.invalidateList(null); + filter2.invalidateList(null); // THEN the pipeline choreographer is scheduled to evaluate, AND the pipeline hasn't // actually run. diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinatorTest.java index d21053bcd691..27542a462d36 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinatorTest.java @@ -18,7 +18,9 @@ package com.android.systemui.statusbar.notification.collection.coordinator; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -51,7 +53,6 @@ public class HideNotifsForOtherUsersCoordinatorTest extends SysuiTestCase { @Mock private NotificationLockscreenUserManager mLockscreenUserManager; @Mock private NotifPipeline mNotifPipeline; @Mock private PluggableListener<NotifFilter> mInvalidationListener; - @Mock private SharedCoordinatorLogger mLogger; @Captor private ArgumentCaptor<UserChangedListener> mUserChangedListenerCaptor; @Captor private ArgumentCaptor<NotifFilter> mNotifFilterCaptor; @@ -66,7 +67,7 @@ public class HideNotifsForOtherUsersCoordinatorTest extends SysuiTestCase { MockitoAnnotations.initMocks(this); HideNotifsForOtherUsersCoordinator coordinator = - new HideNotifsForOtherUsersCoordinator(mLockscreenUserManager, mLogger); + new HideNotifsForOtherUsersCoordinator(mLockscreenUserManager); coordinator.attach(mNotifPipeline); verify(mLockscreenUserManager).addUserChangedListener(mUserChangedListenerCaptor.capture()); @@ -102,6 +103,6 @@ public class HideNotifsForOtherUsersCoordinatorTest extends SysuiTestCase { mCapturedUserChangeListener.onCurrentProfilesChanged(new SparseArray<>()); // THEN the filter is invalidated - verify(mInvalidationListener).onPluggableInvalidated(mCapturedNotifFilter); + verify(mInvalidationListener).onPluggableInvalidated(eq(mCapturedNotifFilter), any()); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt index 8c506a6d16ae..7e2e6f619946 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt @@ -41,7 +41,6 @@ class KeyguardCoordinatorTest : SysuiTestCase() { private val notifPipeline: NotifPipeline = mock() private val keyguardNotifVisibilityProvider: KeyguardNotificationVisibilityProvider = mock() private val sectionHeaderVisibilityProvider: SectionHeaderVisibilityProvider = mock() - private val sharedCoordinatorLogger: SharedCoordinatorLogger = mock() private val statusBarStateController: StatusBarStateController = mock() private lateinit var onStateChangeListener: Consumer<String> @@ -52,7 +51,6 @@ class KeyguardCoordinatorTest : SysuiTestCase() { val keyguardCoordinator = KeyguardCoordinator( keyguardNotifVisibilityProvider, sectionHeaderVisibilityProvider, - sharedCoordinatorLogger, statusBarStateController ) keyguardCoordinator.attach(notifPipeline) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java index a6d3719de5cc..f4adf6927e31 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java @@ -463,7 +463,8 @@ public class PreparationCoordinatorTest extends SysuiTestCase { } @Override - public void abortInflation(@NonNull NotificationEntry entry) { + public boolean abortInflation(@NonNull NotificationEntry entry) { + return false; } public InflationCallback getInflateCallback(NotificationEntry entry) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt index a2d8e3ddba24..27be4c802aec 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt @@ -34,6 +34,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.withArgCaptor import dagger.BindsInstance @@ -79,7 +80,7 @@ class SensitiveContentCoordinatorTest : SysuiTestCase() { dynamicPrivacyListener.onDynamicPrivacyChanged() - verify(invalidationListener).onPluggableInvalidated(invalidator) + verify(invalidationListener).onPluggableInvalidated(eq(invalidator), any()) } @Test @@ -265,4 +266,4 @@ interface TestSensitiveContentCoordinatorComponent { @BindsInstance keyguardStateController: KeyguardStateController ): TestSensitiveContentCoordinatorComponent } -}
\ No newline at end of file +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinatorTest.kt index fdff6e9a52f3..d4f05050b6dd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinatorTest.kt @@ -35,21 +35,23 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener import com.android.systemui.util.concurrency.FakeExecutor +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.withArgCaptor import com.android.systemui.util.time.FakeSystemClock +import java.util.concurrent.TimeUnit import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.mockito.Mock -import org.mockito.Mockito.`when` import org.mockito.Mockito.anyString import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.never import org.mockito.Mockito.verify +import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations -import java.util.concurrent.TimeUnit @SmallTest class SmartspaceDedupingCoordinatorTest : SysuiTestCase() { @@ -349,7 +351,7 @@ class SmartspaceDedupingCoordinatorTest : SysuiTestCase() { // THEN the new pipeline is invalidated (but the old one isn't because it's not // necessary) because the notif should no longer be filtered out - verify(pluggableListener).onPluggableInvalidated(filter) + verify(pluggableListener).onPluggableInvalidated(eq(filter), any()) verify(notificationEntryManager, never()).updateNotifications(anyString()) assertFalse(filter.shouldFilterOut(entry2HasNotRecentlyAlerted, now)) } @@ -387,7 +389,7 @@ class SmartspaceDedupingCoordinatorTest : SysuiTestCase() { } private fun verifyPipelinesInvalidated() { - verify(pluggableListener).onPluggableInvalidated(filter) + verify(pluggableListener).onPluggableInvalidated(eq(filter), any()) verify(notificationEntryManager).updateNotifications(anyString()) } @@ -396,7 +398,7 @@ class SmartspaceDedupingCoordinatorTest : SysuiTestCase() { } private fun verifyPipelinesNotInvalidated() { - verify(pluggableListener, never()).onPluggableInvalidated(filter) + verify(pluggableListener, never()).onPluggableInvalidated(eq(filter), any()) verify(notificationEntryManager, never()).updateNotifications(anyString()) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java index 2f37f8928e79..96c40ecd3d81 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java @@ -19,6 +19,7 @@ package com.android.systemui.statusbar.notification.collection.coordinator; import static junit.framework.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.never; @@ -55,6 +56,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.mockito.verification.VerificationMode; @SmallTest @RunWith(AndroidTestingRunner.class) @@ -130,7 +132,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { doAnswer(i -> { mNotifStabilityManager.onBeginRun(); return null; - }).when(mInvalidateListener).onPluggableInvalidated(eq(mNotifStabilityManager)); + }).when(mInvalidateListener).onPluggableInvalidated(eq(mNotifStabilityManager), any()); } @Test @@ -280,7 +282,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { mCoordinator.temporarilyAllowSectionChanges(mEntry, mFakeSystemClock.uptimeMillis()); // THEN the notification list is invalidated - verify(mInvalidateListener, times(1)).onPluggableInvalidated(mNotifStabilityManager); + verifyStabilityManagerWasInvalidated(times(1)); } @Test @@ -295,7 +297,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { mCoordinator.temporarilyAllowSectionChanges(mEntry, mFakeSystemClock.currentTimeMillis()); // THEN invalidate is not called because this entry was never suppressed from reordering - verify(mInvalidateListener, never()).onPluggableInvalidated(mNotifStabilityManager); + verifyStabilityManagerWasInvalidated(never()); } @Test @@ -312,7 +314,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { // THEN invalidate is not called because this entry was never suppressed from reordering; // THEN section changes are allowed for this notification - verify(mInvalidateListener, never()).onPluggableInvalidated(mNotifStabilityManager); + verifyStabilityManagerWasInvalidated(never()); assertTrue(mNotifStabilityManager.isSectionChangeAllowed(mEntry)); // WHEN we're pulsing (now disallowing reordering) @@ -341,13 +343,13 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { // WHEN we temporarily allow section changes for this notification entry mCoordinator.temporarilyAllowSectionChanges(mEntry, mFakeSystemClock.currentTimeMillis()); // can now reorder, so invalidates - verify(mInvalidateListener, times(1)).onPluggableInvalidated(mNotifStabilityManager); + verifyStabilityManagerWasInvalidated(times(1)); // WHEN reordering is now allowed because device isn't pulsing anymore setPulsing(false); // THEN invalidate isn't called a second time since reordering was already allowed - verify(mInvalidateListener, times(1)).onPluggableInvalidated(mNotifStabilityManager); + verifyStabilityManagerWasInvalidated(times(1)); } @Test @@ -368,7 +370,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { // THEN we never see any calls to invalidate since there weren't any notifications that // were being suppressed from grouping or section changes - verify(mInvalidateListener, never()).onPluggableInvalidated(mNotifStabilityManager); + verifyStabilityManagerWasInvalidated(never()); } @Test @@ -386,7 +388,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { setPanelExpanded(false); // invalidate is called because we were previously suppressing a group change - verify(mInvalidateListener, times(1)).onPluggableInvalidated(mNotifStabilityManager); + verifyStabilityManagerWasInvalidated(times(1)); } @Test @@ -400,7 +402,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { setActivityLaunching(false); // invalidate is called, b/c we were previously suppressing the pipeline from running - verify(mInvalidateListener, times(1)).onPluggableInvalidated(mNotifStabilityManager); + verifyStabilityManagerWasInvalidated(times(1)); } @Test @@ -414,7 +416,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { setPanelCollapsing(false); // invalidate is called, b/c we were previously suppressing the pipeline from running - verify(mInvalidateListener, times(1)).onPluggableInvalidated(mNotifStabilityManager); + verifyStabilityManagerWasInvalidated(times(1)); } @Test @@ -426,7 +428,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { setPanelCollapsing(false); // THEN invalidate is not called, b/c nothing has been suppressed - verify(mInvalidateListener, never()).onPluggableInvalidated(mNotifStabilityManager); + verifyStabilityManagerWasInvalidated(never()); } @Test @@ -438,7 +440,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { setActivityLaunching(false); // THEN invalidate is not called, b/c nothing has been suppressed - verify(mInvalidateListener, never()).onPluggableInvalidated(mNotifStabilityManager); + verifyStabilityManagerWasInvalidated(never()); } @Test @@ -457,7 +459,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { setPanelExpanded(false); // invalidate is called because we were previously suppressing an entry reorder - verify(mInvalidateListener, times(1)).onPluggableInvalidated(mNotifStabilityManager); + verifyStabilityManagerWasInvalidated(times(1)); } @Test @@ -474,7 +476,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { setPanelExpanded(false); // invalidate is not called because we were not told that an entry reorder was suppressed - verify(mInvalidateListener, never()).onPluggableInvalidated(mNotifStabilityManager); + verifyStabilityManagerWasInvalidated(never()); } @Test @@ -499,6 +501,10 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { assertFalse(mNotifStabilityManager.isGroupPruneAllowed(mGroupEntry)); } + private void verifyStabilityManagerWasInvalidated(VerificationMode mode) { + verify(mInvalidateListener, mode).onPluggableInvalidated(eq(mNotifStabilityManager), any()); + } + private void setActivityLaunching(boolean activityLaunching) { mNotifPanelEventsCallback.onLaunchingActivityChanged(activityLaunching); } diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java index 1af8ad344190..84707a8d9c00 100644 --- a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java +++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java @@ -398,18 +398,7 @@ public class AppPredictionPerUserService extends final IBinder.DeathRecipient mDeathRecipient; private final RemoteCallbackList<IPredictionCallback> mCallbacks = - new RemoteCallbackList<IPredictionCallback>() { - @Override - public void onCallbackDied(IPredictionCallback callback) { - if (DEBUG) { - Slog.d(TAG, "Binder died for session Id=" + mSessionId - + " and callback=" + callback.asBinder()); - } - if (mCallbacks.getRegisteredCallbackCount() == 0) { - destroy(); - } - } - }; + new RemoteCallbackList<>(); AppPredictionSessionInfo( @NonNull final AppPredictionSessionId id, diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 1a1c265f568d..9d15ed33797f 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -5754,10 +5754,12 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub @Override public void onImeParentChanged() { synchronized (ImfLock.class) { - // Hide the IME method menu when the IME surface parent will change in - // case seeing the dialog dismiss flickering during the next focused window - // starting the input connection. - mMenuController.hideInputMethodMenu(); + // Hide the IME method menu only when the IME surface parent is changed by the + // input target changed, in case seeing the dialog dismiss flickering during + // the next focused window starting the input connection. + if (mLastImeTargetWindow != mCurFocusedWindow) { + mMenuController.hideInputMethodMenu(); + } } } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index d4155d13992c..867be2427741 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -224,6 +224,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WIND import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES; +import static com.android.server.wm.WindowManagerService.sEnableShellTransitions; import static com.android.server.wm.WindowState.LEGACY_POLICY_VISIBILITY; import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN; @@ -3149,15 +3150,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mWillCloseOrEnterPip = willCloseOrEnterPip; } - /** - * Returns whether this {@link ActivityRecord} is considered closing. Conditions are either - * 1. Is this app animating and was requested to be hidden - * 2. App is delayed closing since it might enter PIP. - */ - boolean isClosingOrEnteringPip() { - return (isAnimating(TRANSITION | PARENTS, ANIMATION_TYPE_APP_TRANSITION) - && !mVisibleRequested) || mWillCloseOrEnterPip; + boolean willCloseOrEnterPip() { + return mWillCloseOrEnterPip; } + /** * @return Whether AppOps allows this package to enter picture-in-picture. */ @@ -5272,12 +5268,19 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } final int windowsCount = mChildren.size(); + // With Shell-Transition, the activity will running a transition when it is visible. + // It won't be included when fromTransition is true means the call from finishTransition. + final boolean runningAnimation = sEnableShellTransitions ? visible + : isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION); for (int i = 0; i < windowsCount; i++) { - mChildren.get(i).onAppVisibilityChanged(visible, isAnimating(PARENTS, - ANIMATION_TYPE_APP_TRANSITION)); + mChildren.get(i).onAppVisibilityChanged(visible, runningAnimation); } setVisible(visible); setVisibleRequested(visible); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "commitVisibility: %s: visible=%b" + + " visibleRequested=%b, isInTransition=%b, runningAnimation=%b, caller=%s", + this, isVisible(), mVisibleRequested, isInTransition(), runningAnimation, + Debug.getCallers(5)); if (!visible) { stopFreezingScreen(true, true); } else { @@ -5300,9 +5303,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A task.dispatchTaskInfoChangedIfNeeded(false /* force */); task = task.getParent().asTask(); } - ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, - "commitVisibility: %s: visible=%b mVisibleRequested=%b", this, - isVisible(), mVisibleRequested); final DisplayContent displayContent = getDisplayContent(); displayContent.getInputMonitor().setUpdateInputWindowsNeededLw(); if (performLayout) { diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java index 0d4cfa3a8128..3e6e06a27fdc 100644 --- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java @@ -234,7 +234,7 @@ final class ImeInsetsSourceProvider extends WindowContainerInsetsSourceProvider // private static boolean isImeLayeringTarget(@NonNull InsetsControlTarget target, @NonNull InsetsControlTarget dcTarget) { - return !dcTarget.getWindow().isClosing() && target == dcTarget; + return !isImeTargetWindowClosing(dcTarget.getWindow()) && target == dcTarget; } private static boolean isAboveImeLayeringTarget(@NonNull InsetsControlTarget target, @@ -256,7 +256,14 @@ final class ImeInsetsSourceProvider extends WindowContainerInsetsSourceProvider final InsetsControlTarget target = mDisplayContent.getImeTarget(IME_TARGET_CONTROL); return target == mImeRequester && (mImeRequester.getWindow() == null - || !mImeRequester.getWindow().isClosing()); + || !isImeTargetWindowClosing(mImeRequester.getWindow())); + } + + private static boolean isImeTargetWindowClosing(@NonNull WindowState win) { + return win.mAnimatingExit || win.mActivityRecord != null + && (win.mActivityRecord.isInTransition() + && !win.mActivityRecord.isVisibleRequested() + || win.mActivityRecord.willCloseOrEnterPip()); } private boolean isTargetChangedWithinActivity(InsetsControlTarget target) { diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 4bbb1b1fb745..6bb5eceec84e 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -1235,8 +1235,12 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub + " task=" + task); return false; } - if (!ArrayUtils.contains(hop.getActivityTypes(), task.getActivityType()) - || !ArrayUtils.contains(hop.getWindowingModes(), task.getWindowingMode())) { + if (!ArrayUtils.isEmpty(hop.getActivityTypes()) + && !ArrayUtils.contains(hop.getActivityTypes(), task.getActivityType())) { + return false; + } + if (!ArrayUtils.isEmpty(hop.getWindowingModes()) + && !ArrayUtils.contains(hop.getWindowingModes(), task.getWindowingMode())) { return false; } if (isLockTaskModeViolation(finalNewParent, task, isInLockTaskMode)) { diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 46091d842c2a..30d18ab04369 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -3461,10 +3461,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return mClient.asBinder().isBinderAlive(); } - boolean isClosing() { - return mAnimatingExit || (mActivityRecord != null && mActivityRecord.isClosingOrEnteringPip()); - } - void sendAppVisibilityToClients() { super.sendAppVisibilityToClients(); diff --git a/services/smartspace/java/com/android/server/smartspace/SmartspacePerUserService.java b/services/smartspace/java/com/android/server/smartspace/SmartspacePerUserService.java index dcffc9e73c0e..f041fbd7bf90 100644 --- a/services/smartspace/java/com/android/server/smartspace/SmartspacePerUserService.java +++ b/services/smartspace/java/com/android/server/smartspace/SmartspacePerUserService.java @@ -334,18 +334,7 @@ public class SmartspacePerUserService extends @NonNull private final SmartspaceConfig mSmartspaceConfig; private final RemoteCallbackList<ISmartspaceCallback> mCallbacks = - new RemoteCallbackList<ISmartspaceCallback>() { - @Override - public void onCallbackDied(ISmartspaceCallback callback) { - if (DEBUG) { - Slog.d(TAG, "Binder died for session Id=" + mSessionId - + " and callback=" + callback.asBinder()); - } - if (mCallbacks.getRegisteredCallbackCount() == 0) { - destroy(); - } - } - }; + new RemoteCallbackList<>(); SmartspaceSessionInfo( @NonNull final SmartspaceSessionId id, diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index 40e266c71328..11a7c7ddf778 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -2118,7 +2118,6 @@ public class DisplayContentTests extends WindowTestsBase { final WindowState appWin2 = createWindow(null, TYPE_BASE_APPLICATION, act2, "appWin2"); appWin2.setHasSurface(true); assertTrue(appWin2.canBeImeTarget()); - doReturn(true).when(appWin1).isClosing(); doReturn(true).when(appWin1).inTransitionSelfOrParent(); // Test step 3: Verify appWin2 will be the next IME target and the IME snapshot surface will |