Merge "Apply navigation bars insets to the fullscreen dialog" into tm-qpr-dev
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index dac55ae..8db298f 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1325,7 +1325,8 @@
* flashlight brightness level via
* {@link android.hardware.camera2.CameraManager#turnOnTorchWithStrengthLevel }.
* If this value is equal to 1, flashlight brightness control is not supported.
- * The value for this key will be null for devices with no flash unit.</p>
+ * The value for this key will be null for devices with no flash unit.
+ * This level must be set to a safe value to prevent any burn out issues.</p>
* <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
*/
@PublicKey
diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl
index 61f524f..c4d3070 100644
--- a/core/java/android/view/IRecentsAnimationController.aidl
+++ b/core/java/android/view/IRecentsAnimationController.aidl
@@ -80,11 +80,6 @@
void setAnimationTargetsBehindSystemBars(boolean behindSystemBars);
/**
- * Hides the current input method if one is showing.
- */
- void hideCurrentInputMethod();
-
- /**
* Clean up the screenshot of previous task which was created during recents animation that
* was cancelled by a stack order change.
*
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 8ec32a6..7be8dff 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -3759,6 +3759,7 @@
}
}
mFirstInputStage.onWindowFocusChanged(hasWindowFocus);
+ mOnBackInvokedDispatcher.onWindowFocusChanged(hasWindowFocus);
// NOTE: there's no view visibility (appeared / disapparead) events when the windows focus
// is lost, so we don't need to to force a flush - there might be other events such as
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 23393ff..2268bef 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -6440,9 +6440,8 @@
public void setText(CharSequence text, BufferType type) {
setText(text, type, true, 0);
- if (mCharWrapper != null) {
- mCharWrapper.mChars = null;
- }
+ // drop any potential mCharWrappper leaks
+ mCharWrapper = null;
}
@UnsupportedAppUsage
@@ -6653,11 +6652,14 @@
* since the TextView has no way to know that the text
* has changed and that it needs to invalidate and re-layout.
*
+ * @throws NullPointerException if text is null
+ * @throws IndexOutOfBoundsException if start or start+len are not in 0 to text.length
+ *
* @param text char array to be displayed
* @param start start index in the char array
* @param len length of char count after {@code start}
*/
- public final void setText(char[] text, int start, int len) {
+ public final void setText(/* @NonNull */ char[] text, int start, int len) {
int oldlen = 0;
if (start < 0 || len < 0 || start + len > text.length) {
@@ -13888,16 +13890,17 @@
}
private static class CharWrapper implements CharSequence, GetChars, GraphicsOperations {
+ @NonNull
private char[] mChars;
private int mStart, mLength;
- public CharWrapper(char[] chars, int start, int len) {
+ CharWrapper(@NonNull char[] chars, int start, int len) {
mChars = chars;
mStart = start;
mLength = len;
}
- /* package */ void set(char[] chars, int start, int len) {
+ /* package */ void set(@NonNull char[] chars, int start, int len) {
mChars = chars;
mStart = start;
mLength = len;
diff --git a/core/java/android/window/ImeOnBackInvokedDispatcher.java b/core/java/android/window/ImeOnBackInvokedDispatcher.java
index 5924844..f1a052b 100644
--- a/core/java/android/window/ImeOnBackInvokedDispatcher.java
+++ b/core/java/android/window/ImeOnBackInvokedDispatcher.java
@@ -81,8 +81,10 @@
@OnBackInvokedDispatcher.Priority int priority,
@NonNull OnBackInvokedCallback callback) {
final Bundle bundle = new Bundle();
+ // Always invoke back for ime without checking the window focus.
final IOnBackInvokedCallback iCallback =
- new WindowOnBackInvokedDispatcher.OnBackInvokedCallbackWrapper(callback);
+ new WindowOnBackInvokedDispatcher.OnBackInvokedCallbackWrapper(callback,
+ () -> true);
bundle.putBinder(RESULT_KEY_CALLBACK, iCallback.asBinder());
bundle.putInt(RESULT_KEY_PRIORITY, priority);
bundle.putInt(RESULT_KEY_ID, callback.hashCode());
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index d147524d..02c5ebc 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -32,6 +32,7 @@
import java.util.HashMap;
import java.util.Objects;
import java.util.TreeMap;
+import java.util.function.Supplier;
/**
* Provides window based implementation of {@link OnBackInvokedDispatcher}.
@@ -64,6 +65,7 @@
private final TreeMap<Integer, ArrayList<OnBackInvokedCallback>>
mOnBackInvokedCallbacks = new TreeMap<>();
private final Checker mChecker;
+ private boolean mHasFocus;
public WindowOnBackInvokedDispatcher(boolean applicationCallBackEnabled) {
mChecker = new Checker(applicationCallBackEnabled);
@@ -189,7 +191,7 @@
.ImeOnBackInvokedCallback
? ((ImeOnBackInvokedDispatcher.ImeOnBackInvokedCallback)
callback).getIOnBackInvokedCallback()
- : new OnBackInvokedCallbackWrapper(callback);
+ : new OnBackInvokedCallbackWrapper(callback, this::hasFocus);
callbackInfo = new OnBackInvokedCallbackInfo(iCallback, priority);
}
mWindowSession.setOnBackInvokedCallbackInfo(mWindow, callbackInfo);
@@ -198,6 +200,17 @@
}
}
+ /**
+ * Called when window focus changed.
+ */
+ public void onWindowFocusChanged(boolean hasFocus) {
+ mHasFocus = hasFocus;
+ }
+
+ private boolean hasFocus() {
+ return mHasFocus;
+ }
+
public OnBackInvokedCallback getTopCallback() {
if (mAllCallbacks.isEmpty()) {
return null;
@@ -221,9 +234,11 @@
static class OnBackInvokedCallbackWrapper extends IOnBackInvokedCallback.Stub {
private final WeakReference<OnBackInvokedCallback> mCallback;
-
- OnBackInvokedCallbackWrapper(@NonNull OnBackInvokedCallback callback) {
+ private final Supplier<Boolean> mHasFocus;
+ OnBackInvokedCallbackWrapper(@NonNull OnBackInvokedCallback callback,
+ @NonNull Supplier<Boolean> hasFocus) {
mCallback = new WeakReference<>(callback);
+ mHasFocus = hasFocus;
}
@Override
@@ -263,7 +278,10 @@
if (callback == null) {
return;
}
-
+ if (!mHasFocus.get()) {
+ Log.w(TAG, "Skip back invoke due to current focus has lost.");
+ return;
+ }
callback.onBackInvoked();
});
}
diff --git a/core/tests/coretests/src/android/widget/TextViewTest.java b/core/tests/coretests/src/android/widget/TextViewTest.java
index 47ce2d8..cc4fbab 100644
--- a/core/tests/coretests/src/android/widget/TextViewTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewTest.java
@@ -304,6 +304,23 @@
assertFalse(mTextView.isCursorVisible());
}
+ @Test(expected = NullPointerException.class)
+ @UiThreadTest
+ public void setTextCharArrayNullThrows() {
+ mTextView = new TextView(mActivity);
+ mTextView.setText((char[]) null, 0, 0);
+ }
+
+ @Test
+ @UiThreadTest
+ public void setTextCharArrayValidAfterSetTextString() {
+ mTextView = new TextView(mActivity);
+ mTextView.setText(new char[] { 'h', 'i'}, 0, 2);
+ CharSequence charWrapper = mTextView.getText();
+ mTextView.setText("null out char wrapper");
+ assertEquals("hi", charWrapper.toString());
+ }
+
private String createLongText() {
int size = 600 * 1000;
final StringBuilder builder = new StringBuilder(size);
diff --git a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
index f448cb3..b5194f6 100644
--- a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
+++ b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
@@ -66,6 +66,7 @@
MockitoAnnotations.initMocks(this);
mDispatcher = new WindowOnBackInvokedDispatcher(true /* applicationCallbackEnabled */);
mDispatcher.attachToWindow(mWindowSession, mWindow);
+ mDispatcher.onWindowFocusChanged(true);
}
private void waitForIdle() {
@@ -152,4 +153,31 @@
waitForIdle();
verify(mCallback2).onBackStarted();
}
+
+ @Test
+ public void skipBackInvokeWhenNoFocus() throws RemoteException {
+ ArgumentCaptor<OnBackInvokedCallbackInfo> captor =
+ ArgumentCaptor.forClass(OnBackInvokedCallbackInfo.class);
+
+ mDispatcher.registerOnBackInvokedCallback(
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback1);
+
+ verify(mWindowSession, times(1)).setOnBackInvokedCallbackInfo(
+ Mockito.eq(mWindow),
+ captor.capture());
+
+ verify(mWindowSession).setOnBackInvokedCallbackInfo(Mockito.eq(mWindow), captor.capture());
+
+ // Should invoke back if it's still in focused.
+ captor.getValue().getCallback().onBackInvoked();
+ waitForIdle();
+ verify(mCallback1).onBackInvoked();
+
+ // In case the focus has lost during back gesture.
+ mDispatcher.onWindowFocusChanged(false);
+
+ captor.getValue().getCallback().onBackInvoked();
+ waitForIdle();
+ verifyZeroInteractions(mCallback1);
+ }
}
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index 84e949a..f8c015f 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -932,7 +932,7 @@
<font weight="700" style="normal" fallbackFor="serif">NotoSerifLao-Bold.ttf</font>
</family>
<family lang="und-Laoo" variant="compact">
- <font weight="400" style="normal">NotoSansLaoUI-Regular.ttf
+ <font weight="400" style="normal" postScriptName="NotoSansLaoUI">NotoSansLaoUI-Regular.ttf
</font>
<font weight="700" style="normal">NotoSansLaoUI-Bold.ttf</font>
</family>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
index 8c0affb..86f9d5b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
@@ -29,6 +29,13 @@
public interface BackAnimation {
/**
+ * Returns a binder that can be passed to an external process to update back animations.
+ */
+ default IBackAnimation createExternalInterface() {
+ return null;
+ }
+
+ /**
* Called when a {@link MotionEvent} is generated by a back gesture.
*
* @param touchX the X touch position of the {@link MotionEvent}.
@@ -47,13 +54,6 @@
void setTriggerBack(boolean triggerBack);
/**
- * Returns a binder that can be passed to an external process to update back animations.
- */
- default IBackAnimation createExternalInterface() {
- return null;
- }
-
- /**
* Sets the threshold values that defining edge swipe behavior.
* @param triggerThreshold the min threshold to trigger back.
* @param progressThreshold the max threshold to keep progressing back animation.
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 b69cbfa..40cf9a3 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
@@ -727,31 +727,23 @@
ActivityManager.RunningTaskInfo taskInfo1, ActivityManager.RunningTaskInfo taskInfo2) {
if (offsetX == 0 && offsetY == 0) {
wct.setBounds(taskInfo1.token, mBounds1);
- wct.setAppBounds(taskInfo1.token, null);
wct.setScreenSizeDp(taskInfo1.token,
SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
wct.setBounds(taskInfo2.token, mBounds2);
- wct.setAppBounds(taskInfo2.token, null);
wct.setScreenSizeDp(taskInfo2.token,
SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
} else {
- mTempRect.set(taskInfo1.configuration.windowConfiguration.getBounds());
+ getBounds1(mTempRect);
mTempRect.offset(offsetX, offsetY);
wct.setBounds(taskInfo1.token, mTempRect);
- mTempRect.set(taskInfo1.configuration.windowConfiguration.getAppBounds());
- mTempRect.offset(offsetX, offsetY);
- wct.setAppBounds(taskInfo1.token, mTempRect);
wct.setScreenSizeDp(taskInfo1.token,
taskInfo1.configuration.screenWidthDp,
taskInfo1.configuration.screenHeightDp);
- mTempRect.set(taskInfo2.configuration.windowConfiguration.getBounds());
+ getBounds2(mTempRect);
mTempRect.offset(offsetX, offsetY);
wct.setBounds(taskInfo2.token, mTempRect);
- mTempRect.set(taskInfo2.configuration.windowConfiguration.getAppBounds());
- mTempRect.offset(offsetX, offsetY);
- wct.setAppBounds(taskInfo2.token, mTempRect);
wct.setScreenSizeDp(taskInfo2.token,
taskInfo2.configuration.screenWidthDp,
taskInfo2.configuration.screenHeightDp);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUI.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUI.java
deleted file mode 100644
index b87cf47..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUI.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.wm.shell.compatui;
-
-import com.android.wm.shell.common.annotations.ExternalThread;
-
-/**
- * Interface to engage compat UI.
- */
-@ExternalThread
-public interface CompatUI {
- /**
- * Called when the keyguard showing state changes. Removes all compat UIs if the
- * keyguard is now showing.
- *
- * <p>Note that if the keyguard is occluded it will also be considered showing.
- *
- * @param showing indicates if the keyguard is now showing.
- */
- void onKeyguardShowingChanged(boolean showing);
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
index 99b32a6..db8d9d4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
@@ -39,9 +39,10 @@
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.compatui.CompatUIWindowManager.CompatUIHintsState;
import com.android.wm.shell.compatui.letterboxedu.LetterboxEduWindowManager;
+import com.android.wm.shell.sysui.KeyguardChangeListener;
+import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.transition.Transitions;
import java.lang.ref.WeakReference;
@@ -58,7 +59,7 @@
* activities are in compatibility mode.
*/
public class CompatUIController implements OnDisplaysChangedListener,
- DisplayImeController.ImePositionProcessor {
+ DisplayImeController.ImePositionProcessor, KeyguardChangeListener {
/** Callback for compat UI interaction. */
public interface CompatUICallback {
@@ -100,13 +101,13 @@
private final SparseArray<WeakReference<Context>> mDisplayContextCache = new SparseArray<>(0);
private final Context mContext;
+ private final ShellController mShellController;
private final DisplayController mDisplayController;
private final DisplayInsetsController mDisplayInsetsController;
private final DisplayImeController mImeController;
private final SyncTransactionQueue mSyncQueue;
private final ShellExecutor mMainExecutor;
private final Lazy<Transitions> mTransitionsLazy;
- private final CompatUIImpl mImpl = new CompatUIImpl();
private CompatUICallback mCallback;
@@ -118,6 +119,7 @@
private boolean mKeyguardShowing;
public CompatUIController(Context context,
+ ShellController shellController,
DisplayController displayController,
DisplayInsetsController displayInsetsController,
DisplayImeController imeController,
@@ -125,6 +127,7 @@
ShellExecutor mainExecutor,
Lazy<Transitions> transitionsLazy) {
mContext = context;
+ mShellController = shellController;
mDisplayController = displayController;
mDisplayInsetsController = displayInsetsController;
mImeController = imeController;
@@ -134,11 +137,7 @@
mDisplayController.addDisplayWindowListener(this);
mImeController.addPositionProcessor(this);
mCompatUIHintsState = new CompatUIHintsState();
- }
-
- /** Returns implementation of {@link CompatUI}. */
- public CompatUI asCompatUI() {
- return mImpl;
+ shellController.addKeyguardChangeListener(this);
}
/** Sets the callback for UI interactions. */
@@ -223,9 +222,10 @@
layout -> layout.updateVisibility(showOnDisplay(displayId)));
}
- @VisibleForTesting
- void onKeyguardShowingChanged(boolean showing) {
- mKeyguardShowing = showing;
+ @Override
+ public void onKeyguardVisibilityChanged(boolean visible, boolean occluded,
+ boolean animatingDismiss) {
+ mKeyguardShowing = visible;
// Hide the compat UIs when keyguard is showing.
forAllLayouts(layout -> layout.updateVisibility(showOnDisplay(layout.getDisplayId())));
}
@@ -373,19 +373,6 @@
}
}
- /**
- * The interface for calls from outside the Shell, within the host process.
- */
- @ExternalThread
- private class CompatUIImpl implements CompatUI {
- @Override
- public void onKeyguardShowingChanged(boolean showing) {
- mMainExecutor.execute(() -> {
- CompatUIController.this.onKeyguardShowingChanged(showing);
- });
- }
- }
-
/** An implementation of {@link OnInsetsChangedListener} for a given display id. */
private class PerDisplayOnInsetsChangedListener implements OnInsetsChangedListener {
final int mDisplayId;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index ed5e247..586eab0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -57,15 +57,12 @@
import com.android.wm.shell.common.annotations.ShellBackgroundThread;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.common.annotations.ShellSplashscreenThread;
-import com.android.wm.shell.compatui.CompatUI;
import com.android.wm.shell.compatui.CompatUIController;
import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
import com.android.wm.shell.displayareahelper.DisplayAreaHelperController;
-import com.android.wm.shell.draganddrop.DragAndDrop;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.freeform.FreeformTaskListener;
import com.android.wm.shell.fullscreen.FullscreenTaskListener;
-import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController;
import com.android.wm.shell.kidsmode.KidsModeTaskOrganizer;
import com.android.wm.shell.onehanded.OneHanded;
@@ -85,8 +82,6 @@
import com.android.wm.shell.startingsurface.phone.PhoneStartingWindowTypeAlgorithm;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInterface;
-import com.android.wm.shell.tasksurfacehelper.TaskSurfaceHelper;
-import com.android.wm.shell.tasksurfacehelper.TaskSurfaceHelperController;
import com.android.wm.shell.transition.ShellTransitions;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.unfold.ShellUnfoldProgressProvider;
@@ -173,12 +168,6 @@
@WMSingleton
@Provides
- static Optional<DragAndDrop> provideDragAndDrop(DragAndDropController dragAndDropController) {
- return Optional.of(dragAndDropController.asDragAndDrop());
- }
-
- @WMSingleton
- @Provides
static ShellTaskOrganizer provideShellTaskOrganizer(@ShellMainThread ShellExecutor mainExecutor,
Context context,
CompatUIController compatUI,
@@ -207,18 +196,14 @@
}
@WMSingleton
- @Provides static Optional<CompatUI> provideCompatUI(CompatUIController compatUIController) {
- return Optional.of(compatUIController.asCompatUI());
- }
-
- @WMSingleton
@Provides
static CompatUIController provideCompatUIController(Context context,
+ ShellController shellController,
DisplayController displayController, DisplayInsetsController displayInsetsController,
DisplayImeController imeController, SyncTransactionQueue syncQueue,
@ShellMainThread ShellExecutor mainExecutor, Lazy<Transitions> transitionsLazy) {
- return new CompatUIController(context, displayController, displayInsetsController,
- imeController, syncQueue, mainExecutor, transitionsLazy);
+ return new CompatUIController(context, shellController, displayController,
+ displayInsetsController, imeController, syncQueue, mainExecutor, transitionsLazy);
}
@WMSingleton
@@ -375,13 +360,6 @@
@WMSingleton
@Provides
- static Optional<HideDisplayCutout> provideHideDisplayCutout(
- Optional<HideDisplayCutoutController> hideDisplayCutoutController) {
- return hideDisplayCutoutController.map((controller) -> controller.asHideDisplayCutout());
- }
-
- @WMSingleton
- @Provides
static Optional<HideDisplayCutoutController> provideHideDisplayCutoutController(Context context,
ShellController shellController, DisplayController displayController,
@ShellMainThread ShellExecutor mainExecutor) {
@@ -416,23 +394,6 @@
}
//
- // Task to Surface communication
- //
-
- @WMSingleton
- @Provides
- static Optional<TaskSurfaceHelper> provideTaskSurfaceHelper(
- Optional<TaskSurfaceHelperController> taskSurfaceController) {
- return taskSurfaceController.map((controller) -> controller.asTaskSurfaceHelper());
- }
-
- @Provides
- static Optional<TaskSurfaceHelperController> provideTaskSurfaceHelperController(
- ShellTaskOrganizer taskOrganizer, @ShellMainThread ShellExecutor mainExecutor) {
- return Optional.ofNullable(new TaskSurfaceHelperController(taskOrganizer, mainExecutor));
- }
-
- //
// Pip (optional feature)
//
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index fb51473..0f33f4c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -225,6 +225,7 @@
@Provides
@DynamicOverride
static SplitScreenController provideSplitScreenController(
+ ShellController shellController,
ShellTaskOrganizer shellTaskOrganizer,
SyncTransactionQueue syncQueue, Context context,
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
@@ -234,7 +235,7 @@
DisplayInsetsController displayInsetsController, Transitions transitions,
TransactionPool transactionPool, IconProvider iconProvider,
Optional<RecentTasksController> recentTasks) {
- return new SplitScreenController(shellTaskOrganizer, syncQueue, context,
+ return new SplitScreenController(shellController, shellTaskOrganizer, syncQueue, context,
rootTaskDisplayAreaOrganizer, mainExecutor, displayController, displayImeController,
displayInsetsController, transitions, transactionPool, iconProvider,
recentTasks);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDrop.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDrop.java
deleted file mode 100644
index 0335187..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDrop.java
+++ /dev/null
@@ -1,26 +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.wm.shell.draganddrop;
-
-import com.android.wm.shell.common.annotations.ExternalThread;
-
-/**
- * Interface for telling DragAndDrop stuff.
- */
-@ExternalThread
-public interface DragAndDrop {
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
index 0d0961c..c5df53b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
@@ -81,11 +81,9 @@
private final IconProvider mIconProvider;
private SplitScreenController mSplitScreen;
private ShellExecutor mMainExecutor;
- private DragAndDropImpl mImpl;
private ArrayList<DragAndDropListener> mListeners = new ArrayList<>();
private final SparseArray<PerDisplay> mDisplayDropTargets = new SparseArray<>();
- private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
/**
* Listener called during drag events, currently just onDragStarted.
@@ -107,11 +105,6 @@
mLogger = new DragAndDropEventLogger(uiEventLogger);
mIconProvider = iconProvider;
mMainExecutor = mainExecutor;
- mImpl = new DragAndDropImpl();
- }
-
- public DragAndDrop asDragAndDrop() {
- return mImpl;
}
public void initialize(Optional<SplitScreenController> splitscreen) {
@@ -353,8 +346,4 @@
dragLayout = dl;
}
}
-
- private class DragAndDropImpl implements DragAndDrop {
- // TODO: To be removed
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutout.java
deleted file mode 100644
index dd1c8d6..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutout.java
+++ /dev/null
@@ -1,26 +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.wm.shell.hidedisplaycutout;
-
-import com.android.wm.shell.common.annotations.ExternalThread;
-
-/**
- * Interface to engage hide display cutout feature.
- */
-@ExternalThread
-public interface HideDisplayCutout {
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutController.java
index b091ab8..665b035 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutController.java
@@ -40,8 +40,6 @@
private final Context mContext;
private final ShellController mShellController;
private final HideDisplayCutoutOrganizer mOrganizer;
- private final ShellExecutor mMainExecutor;
- private final HideDisplayCutoutImpl mImpl = new HideDisplayCutoutImpl();
@VisibleForTesting
boolean mEnabled;
@@ -62,23 +60,18 @@
HideDisplayCutoutOrganizer organizer =
new HideDisplayCutoutOrganizer(context, displayController, mainExecutor);
- return new HideDisplayCutoutController(context, shellController, organizer, mainExecutor);
+ return new HideDisplayCutoutController(context, shellController, organizer);
}
HideDisplayCutoutController(Context context, ShellController shellController,
- HideDisplayCutoutOrganizer organizer, ShellExecutor mainExecutor) {
+ HideDisplayCutoutOrganizer organizer) {
mContext = context;
mShellController = shellController;
mOrganizer = organizer;
- mMainExecutor = mainExecutor;
updateStatus();
mShellController.addConfigurationChangeListener(this);
}
- public HideDisplayCutout asHideDisplayCutout() {
- return mImpl;
- }
-
@VisibleForTesting
void updateStatus() {
// The config value is used for controlling enabling/disabling status of the feature and is
@@ -112,8 +105,4 @@
pw.println(mEnabled);
mOrganizer.dump(pw);
}
-
- private class HideDisplayCutoutImpl implements HideDisplayCutout {
- // TODO: To be removed
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java
index ee99f327..76c0f41 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java
@@ -85,9 +85,4 @@
* Notifies when user switch complete
*/
void onUserSwitch(int userId);
-
- /**
- * Notifies when keyguard visibility changed
- */
- void onKeyguardVisibilityChanged(boolean showing);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index ea2d508..24f02ac 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -55,6 +55,7 @@
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.sysui.ConfigurationChangeListener;
+import com.android.wm.shell.sysui.KeyguardChangeListener;
import com.android.wm.shell.sysui.ShellController;
import java.io.PrintWriter;
@@ -63,7 +64,8 @@
* Manages and manipulates the one handed states, transitions, and gesture for phones.
*/
public class OneHandedController implements RemoteCallable<OneHandedController>,
- DisplayChangeController.OnDisplayChangingListener, ConfigurationChangeListener {
+ DisplayChangeController.OnDisplayChangingListener, ConfigurationChangeListener,
+ KeyguardChangeListener {
private static final String TAG = "OneHandedController";
private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE =
@@ -279,6 +281,7 @@
mState.addSListeners(mTutorialHandler);
mShellController.addConfigurationChangeListener(this);
+ mShellController.addKeyguardChangeListener(this);
}
public OneHanded asOneHanded() {
@@ -605,8 +608,11 @@
mTutorialHandler.onConfigurationChanged();
}
- private void onKeyguardVisibilityChanged(boolean showing) {
- mKeyguardShowing = showing;
+ @Override
+ public void onKeyguardVisibilityChanged(boolean visible, boolean occluded,
+ boolean animatingDismiss) {
+ mKeyguardShowing = visible;
+ stopOneHanded();
}
private void onUserSwitch(int newUserId) {
@@ -675,9 +681,12 @@
return;
}
+ if (mState.getState() == STATE_ACTIVE) {
+ mOneHandedUiEventLogger.writeEvent(
+ OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_ROTATION_OUT);
+ }
+
mDisplayAreaOrganizer.onRotateDisplay(mContext, toRotation, wct);
- mOneHandedUiEventLogger.writeEvent(
- OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_ROTATION_OUT);
}
/**
@@ -756,13 +765,6 @@
OneHandedController.this.onUserSwitch(userId);
});
}
-
- @Override
- public void onKeyguardVisibilityChanged(boolean showing) {
- mMainExecutor.execute(() -> {
- OneHandedController.this.onKeyguardVisibilityChanged(showing);
- });
- }
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
index 2ac1129..38631ce 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
@@ -101,23 +101,6 @@
default void removePipExclusionBoundsChangeListener(Consumer<Rect> listener) { }
/**
- * Called when the visibility of keyguard is changed.
- * @param showing {@code true} if keyguard is now showing, {@code false} otherwise.
- * @param animating {@code true} if system is animating between keyguard and surface behind,
- * this only makes sense when showing is {@code false}.
- */
- default void onKeyguardVisibilityChanged(boolean showing, boolean animating) { }
-
- /**
- * Called when the dismissing animation keyguard and surfaces behind is finished.
- * See also {@link #onKeyguardVisibilityChanged(boolean, boolean)}.
- *
- * TODO(b/206741900) deprecate this path once we're able to animate the PiP window as part of
- * keyguard dismiss animation.
- */
- default void onKeyguardDismissAnimationFinished() { }
-
- /**
* Dump the current state and information if need.
*
* @param pw The stream to dump information to.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 5ae4602..420d606 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -88,6 +88,7 @@
import com.android.wm.shell.pip.PipUtils;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.sysui.ConfigurationChangeListener;
+import com.android.wm.shell.sysui.KeyguardChangeListener;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.transition.Transitions;
@@ -102,7 +103,7 @@
* Manages the picture-in-picture (PIP) UI and states for Phones.
*/
public class PipController implements PipTransitionController.PipTransitionCallback,
- RemoteCallable<PipController>, ConfigurationChangeListener {
+ RemoteCallable<PipController>, ConfigurationChangeListener, KeyguardChangeListener {
private static final String TAG = "PipController";
private Context mContext;
@@ -527,6 +528,7 @@
});
mShellController.addConfigurationChangeListener(this);
+ mShellController.addKeyguardChangeListener(this);
}
@Override
@@ -661,21 +663,24 @@
* finished first to reset the visibility of PiP window.
* See also {@link #onKeyguardDismissAnimationFinished()}
*/
- private void onKeyguardVisibilityChanged(boolean keyguardShowing, boolean animating) {
+ @Override
+ public void onKeyguardVisibilityChanged(boolean visible, boolean occluded,
+ boolean animatingDismiss) {
if (!mPipTaskOrganizer.isInPip()) {
return;
}
- if (keyguardShowing) {
+ if (visible) {
mIsKeyguardShowingOrAnimating = true;
hidePipMenu(null /* onStartCallback */, null /* onEndCallback */);
mPipTaskOrganizer.setPipVisibility(false);
- } else if (!animating) {
+ } else if (!animatingDismiss) {
mIsKeyguardShowingOrAnimating = false;
mPipTaskOrganizer.setPipVisibility(true);
}
}
- private void onKeyguardDismissAnimationFinished() {
+ @Override
+ public void onKeyguardDismissAnimationFinished() {
if (mPipTaskOrganizer.isInPip()) {
mIsKeyguardShowingOrAnimating = false;
mPipTaskOrganizer.setPipVisibility(true);
@@ -996,18 +1001,6 @@
}
@Override
- public void onKeyguardVisibilityChanged(boolean showing, boolean animating) {
- mMainExecutor.execute(() -> {
- PipController.this.onKeyguardVisibilityChanged(showing, animating);
- });
- }
-
- @Override
- public void onKeyguardDismissAnimationFinished() {
- mMainExecutor.execute(PipController.this::onKeyguardDismissAnimationFinished);
- }
-
- @Override
public void dump(PrintWriter pw) {
try {
mMainExecutor.executeBlocking(() -> {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
index 29b6311..e73b799 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
@@ -77,12 +77,6 @@
return null;
}
- /**
- * Called when the visibility of the keyguard changes.
- * @param showing Indicates if the keyguard is now visible.
- */
- void onKeyguardVisibilityChanged(boolean showing);
-
/** Called when device waking up finished. */
void onFinishedWakingUp();
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 21bea46..53ec39d 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
@@ -80,6 +80,8 @@
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.splitscreen.SplitScreen.StageType;
+import com.android.wm.shell.sysui.KeyguardChangeListener;
+import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.transition.LegacyTransitions;
import com.android.wm.shell.transition.Transitions;
@@ -99,7 +101,7 @@
*/
// TODO(b/198577848): Implement split screen flicker test to consolidate CUJ of split screen.
public class SplitScreenController implements DragAndDropPolicy.Starter,
- RemoteCallable<SplitScreenController> {
+ RemoteCallable<SplitScreenController>, KeyguardChangeListener {
private static final String TAG = SplitScreenController.class.getSimpleName();
public static final int EXIT_REASON_UNKNOWN = 0;
@@ -127,6 +129,7 @@
@Retention(RetentionPolicy.SOURCE)
@interface ExitReason{}
+ private final ShellController mShellController;
private final ShellTaskOrganizer mTaskOrganizer;
private final SyncTransactionQueue mSyncQueue;
private final Context mContext;
@@ -147,7 +150,8 @@
// outside the bounds of the roots by being reparented into a higher level fullscreen container
private SurfaceControl mSplitTasksContainerLayer;
- public SplitScreenController(ShellTaskOrganizer shellTaskOrganizer,
+ public SplitScreenController(ShellController shellController,
+ ShellTaskOrganizer shellTaskOrganizer,
SyncTransactionQueue syncQueue, Context context,
RootTaskDisplayAreaOrganizer rootTDAOrganizer,
ShellExecutor mainExecutor, DisplayController displayController,
@@ -155,6 +159,7 @@
DisplayInsetsController displayInsetsController,
Transitions transitions, TransactionPool transactionPool, IconProvider iconProvider,
Optional<RecentTasksController> recentTasks) {
+ mShellController = shellController;
mTaskOrganizer = shellTaskOrganizer;
mSyncQueue = syncQueue;
mContext = context;
@@ -185,6 +190,7 @@
}
public void onOrganizerRegistered() {
+ mShellController.addKeyguardChangeListener(this);
if (mStageCoordinator == null) {
// TODO: Multi-display
mStageCoordinator = new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
@@ -283,8 +289,10 @@
mStageCoordinator.exitSplitScreen(toTopTaskId, exitReason);
}
- public void onKeyguardVisibilityChanged(boolean showing) {
- mStageCoordinator.onKeyguardVisibilityChanged(showing);
+ @Override
+ public void onKeyguardVisibilityChanged(boolean visible, boolean occluded,
+ boolean animatingDismiss) {
+ mStageCoordinator.onKeyguardVisibilityChanged(visible);
}
public void onFinishedWakingUp() {
@@ -658,13 +666,6 @@
}
@Override
- public void onKeyguardVisibilityChanged(boolean showing) {
- mMainExecutor.execute(() -> {
- SplitScreenController.this.onKeyguardVisibilityChanged(showing);
- });
- }
-
- @Override
public void onFinishedWakingUp() {
mMainExecutor.execute(() -> {
SplitScreenController.this.onFinishedWakingUp();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/KeyguardChangeListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/KeyguardChangeListener.java
new file mode 100644
index 0000000..1c0b358
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/KeyguardChangeListener.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.sysui;
+
+/**
+ * Callbacks for when the keyguard changes.
+ */
+public interface KeyguardChangeListener {
+ /**
+ * Notifies the Shell that the keyguard is showing (and if so, whether it is occluded).
+ */
+ default void onKeyguardVisibilityChanged(boolean visible, boolean occluded,
+ boolean animatingDismiss) {}
+
+ /**
+ * Notifies the Shell when the keyguard dismiss animation has finished.
+ *
+ * TODO(b/206741900) deprecate this path once we're able to animate the PiP window as part of
+ * keyguard dismiss animation.
+ */
+ default void onKeyguardDismissAnimationFinished() {}
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java
index 28a30f4..837acec 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java
@@ -47,7 +47,9 @@
private final ShellExecutor mMainExecutor;
private final ShellInterfaceImpl mImpl = new ShellInterfaceImpl();
- private final CopyOnWriteArrayList<ConfigurationChangeListener> mListeners =
+ private final CopyOnWriteArrayList<ConfigurationChangeListener> mConfigChangeListeners =
+ new CopyOnWriteArrayList<>();
+ private final CopyOnWriteArrayList<KeyguardChangeListener> mKeyguardChangeListeners =
new CopyOnWriteArrayList<>();
private Configuration mLastConfiguration;
@@ -68,15 +70,31 @@
* particular order.
*/
public void addConfigurationChangeListener(ConfigurationChangeListener listener) {
- mListeners.remove(listener);
- mListeners.add(listener);
+ mConfigChangeListeners.remove(listener);
+ mConfigChangeListeners.add(listener);
}
/**
* Removes an existing configuration listener.
*/
public void removeConfigurationChangeListener(ConfigurationChangeListener listener) {
- mListeners.remove(listener);
+ mConfigChangeListeners.remove(listener);
+ }
+
+ /**
+ * Adds a new Keyguard listener. The Keyguard change callbacks are not made in any
+ * particular order.
+ */
+ public void addKeyguardChangeListener(KeyguardChangeListener listener) {
+ mKeyguardChangeListeners.remove(listener);
+ mKeyguardChangeListeners.add(listener);
+ }
+
+ /**
+ * Removes an existing Keyguard listener.
+ */
+ public void removeKeyguardChangeListener(KeyguardChangeListener listener) {
+ mKeyguardChangeListeners.remove(listener);
}
@VisibleForTesting
@@ -102,7 +120,7 @@
// Update the last configuration and call listeners
mLastConfiguration.updateFrom(newConfig);
- for (ConfigurationChangeListener listener : mListeners) {
+ for (ConfigurationChangeListener listener : mConfigChangeListeners) {
listener.onConfigurationChanged(newConfig);
if (densityFontScaleChanged) {
listener.onDensityOrFontScaleChanged();
@@ -119,11 +137,26 @@
}
}
+ @VisibleForTesting
+ void onKeyguardVisibilityChanged(boolean visible, boolean occluded, boolean animatingDismiss) {
+ for (KeyguardChangeListener listener : mKeyguardChangeListeners) {
+ listener.onKeyguardVisibilityChanged(visible, occluded, animatingDismiss);
+ }
+ }
+
+ @VisibleForTesting
+ void onKeyguardDismissAnimationFinished() {
+ for (KeyguardChangeListener listener : mKeyguardChangeListeners) {
+ listener.onKeyguardDismissAnimationFinished();
+ }
+ }
+
public void dump(@NonNull PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
pw.println(prefix + TAG);
- pw.println(innerPrefix + "mListeners=" + mListeners.size());
+ pw.println(innerPrefix + "mConfigChangeListeners=" + mConfigChangeListeners.size());
pw.println(innerPrefix + "mLastConfiguration=" + mLastConfiguration);
+ pw.println(innerPrefix + "mKeyguardChangeListeners=" + mKeyguardChangeListeners.size());
}
/**
@@ -136,5 +169,19 @@
mMainExecutor.execute(() ->
ShellController.this.onConfigurationChanged(newConfiguration));
}
+
+ @Override
+ public void onKeyguardVisibilityChanged(boolean visible, boolean occluded,
+ boolean animatingDismiss) {
+ mMainExecutor.execute(() ->
+ ShellController.this.onKeyguardVisibilityChanged(visible, occluded,
+ animatingDismiss));
+ }
+
+ @Override
+ public void onKeyguardDismissAnimationFinished() {
+ mMainExecutor.execute(() ->
+ ShellController.this.onKeyguardDismissAnimationFinished());
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInterface.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInterface.java
index a2d072c..a15ce5d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInterface.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInterface.java
@@ -30,4 +30,16 @@
* Notifies the Shell that the configuration has changed.
*/
default void onConfigurationChanged(Configuration newConfiguration) {}
+
+ /**
+ * Notifies the Shell that the keyguard is showing (and if so, whether it is occluded) or not
+ * showing, and whether it is animating a dismiss.
+ */
+ default void onKeyguardVisibilityChanged(boolean visible, boolean occluded,
+ boolean animatingDismiss) {}
+
+ /**
+ * Notifies the Shell when the keyguard dismiss animation has finished.
+ */
+ default void onKeyguardDismissAnimationFinished() {}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/tasksurfacehelper/TaskSurfaceHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/tasksurfacehelper/TaskSurfaceHelper.java
deleted file mode 100644
index ad9dda6..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/tasksurfacehelper/TaskSurfaceHelper.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.wm.shell.tasksurfacehelper;
-
-import android.app.ActivityManager.RunningTaskInfo;
-import android.graphics.Rect;
-import android.view.SurfaceControl;
-
-import java.util.concurrent.Executor;
-import java.util.function.Consumer;
-
-/**
- * Interface to communicate with a Task's SurfaceControl.
- */
-public interface TaskSurfaceHelper {
-
- /** Sets the METADATA_GAME_MODE for the layer corresponding to the task **/
- default void setGameModeForTask(int taskId, int gameMode) {}
-
- /** Takes a screenshot for a task **/
- default void screenshotTask(RunningTaskInfo taskInfo, Rect crop, Executor executor,
- Consumer<SurfaceControl.ScreenshotHardwareBuffer> consumer) {}
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/tasksurfacehelper/TaskSurfaceHelperController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/tasksurfacehelper/TaskSurfaceHelperController.java
deleted file mode 100644
index 064d9d1..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/tasksurfacehelper/TaskSurfaceHelperController.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * 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.wm.shell.tasksurfacehelper;
-
-import android.app.ActivityManager.RunningTaskInfo;
-import android.graphics.Rect;
-import android.view.SurfaceControl;
-
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.common.ShellExecutor;
-
-import java.util.concurrent.Executor;
-import java.util.function.Consumer;
-
-/**
- * Intermediary controller that communicates with {@link ShellTaskOrganizer} to send commands
- * to SurfaceControl.
- */
-public class TaskSurfaceHelperController {
-
- private final ShellTaskOrganizer mTaskOrganizer;
- private final ShellExecutor mMainExecutor;
- private final TaskSurfaceHelperImpl mImpl = new TaskSurfaceHelperImpl();
-
- public TaskSurfaceHelperController(ShellTaskOrganizer taskOrganizer,
- ShellExecutor mainExecutor) {
- mTaskOrganizer = taskOrganizer;
- mMainExecutor = mainExecutor;
- }
-
- public TaskSurfaceHelper asTaskSurfaceHelper() {
- return mImpl;
- }
-
- /**
- * Sends a Transaction to set the game mode metadata on the
- * corresponding SurfaceControl
- */
- public void setGameModeForTask(int taskId, int gameMode) {
- mTaskOrganizer.setSurfaceMetadata(taskId, SurfaceControl.METADATA_GAME_MODE, gameMode);
- }
-
- /**
- * Take screenshot of the specified task.
- */
- public void screenshotTask(RunningTaskInfo taskInfo, Rect crop,
- Consumer<SurfaceControl.ScreenshotHardwareBuffer> consumer) {
- mTaskOrganizer.screenshotTask(taskInfo, crop, consumer);
- }
-
- private class TaskSurfaceHelperImpl implements TaskSurfaceHelper {
- @Override
- public void setGameModeForTask(int taskId, int gameMode) {
- mMainExecutor.execute(() -> {
- TaskSurfaceHelperController.this.setGameModeForTask(taskId, gameMode);
- });
- }
-
- @Override
- public void screenshotTask(RunningTaskInfo taskInfo, Rect crop, Executor executor,
- Consumer<SurfaceControl.ScreenshotHardwareBuffer> consumer) {
- mMainExecutor.execute(() -> {
- TaskSurfaceHelperController.this.screenshotTask(taskInfo, crop,
- (t) -> executor.execute(() -> consumer.accept(t)));
- });
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
index 596100d..828c13e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
@@ -53,6 +53,7 @@
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.compatui.letterboxedu.LetterboxEduWindowManager;
+import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.transition.Transitions;
import org.junit.Before;
@@ -78,6 +79,7 @@
private static final int TASK_ID = 12;
private CompatUIController mController;
+ private @Mock ShellController mMockShellController;
private @Mock DisplayController mMockDisplayController;
private @Mock DisplayInsetsController mMockDisplayInsetsController;
private @Mock DisplayLayout mMockDisplayLayout;
@@ -105,7 +107,7 @@
doReturn(TASK_ID).when(mMockLetterboxEduLayout).getTaskId();
doReturn(true).when(mMockLetterboxEduLayout).createLayout(anyBoolean());
doReturn(true).when(mMockLetterboxEduLayout).updateCompatInfo(any(), any(), anyBoolean());
- mController = new CompatUIController(mContext, mMockDisplayController,
+ mController = new CompatUIController(mContext, mMockShellController, mMockDisplayController,
mMockDisplayInsetsController, mMockImeController, mMockSyncQueue, mMockExecutor,
mMockTransitionsLazy) {
@Override
@@ -124,6 +126,11 @@
}
@Test
+ public void instantiateController_registerKeyguardChangeListener() {
+ verify(mMockShellController, times(1)).addKeyguardChangeListener(any());
+ }
+
+ @Test
public void testListenerRegistered() {
verify(mMockDisplayController).addDisplayWindowListener(mController);
verify(mMockImeController).addPositionProcessor(mController);
@@ -324,7 +331,7 @@
/* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN), mMockTaskListener);
// Verify that the restart button is hidden after keyguard becomes showing.
- mController.onKeyguardShowingChanged(true);
+ mController.onKeyguardVisibilityChanged(true, false, false);
verify(mMockCompatLayout).updateVisibility(false);
verify(mMockLetterboxEduLayout).updateVisibility(false);
@@ -340,7 +347,7 @@
false);
// Verify button is shown after keyguard becomes not showing.
- mController.onKeyguardShowingChanged(false);
+ mController.onKeyguardVisibilityChanged(false, false, false);
verify(mMockCompatLayout).updateVisibility(true);
verify(mMockLetterboxEduLayout).updateVisibility(true);
@@ -352,7 +359,7 @@
/* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN), mMockTaskListener);
mController.onImeVisibilityChanged(DISPLAY_ID, /* isShowing= */ true);
- mController.onKeyguardShowingChanged(true);
+ mController.onKeyguardVisibilityChanged(true, false, false);
verify(mMockCompatLayout, times(2)).updateVisibility(false);
verify(mMockLetterboxEduLayout, times(2)).updateVisibility(false);
@@ -360,7 +367,7 @@
clearInvocations(mMockCompatLayout, mMockLetterboxEduLayout);
// Verify button remains hidden after keyguard becomes not showing since IME is showing.
- mController.onKeyguardShowingChanged(false);
+ mController.onKeyguardVisibilityChanged(false, false, false);
verify(mMockCompatLayout).updateVisibility(false);
verify(mMockLetterboxEduLayout).updateVisibility(false);
@@ -378,7 +385,7 @@
/* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN), mMockTaskListener);
mController.onImeVisibilityChanged(DISPLAY_ID, /* isShowing= */ true);
- mController.onKeyguardShowingChanged(true);
+ mController.onKeyguardVisibilityChanged(true, false, false);
verify(mMockCompatLayout, times(2)).updateVisibility(false);
verify(mMockLetterboxEduLayout, times(2)).updateVisibility(false);
@@ -392,7 +399,7 @@
verify(mMockLetterboxEduLayout).updateVisibility(false);
// Verify button is shown after keyguard becomes not showing.
- mController.onKeyguardShowingChanged(false);
+ mController.onKeyguardVisibilityChanged(false, false, false);
verify(mMockCompatLayout).updateVisibility(true);
verify(mMockLetterboxEduLayout).updateVisibility(true);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutControllerTest.java
index 68e955e..dcc504a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutControllerTest.java
@@ -29,7 +29,6 @@
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.wm.shell.ShellTestCase;
-import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.sysui.ShellController;
import org.junit.Before;
@@ -49,8 +48,6 @@
private ShellController mShellController;
@Mock
private HideDisplayCutoutOrganizer mMockDisplayAreaOrganizer;
- @Mock
- private ShellExecutor mMockMainExecutor;
private HideDisplayCutoutController mHideDisplayCutoutController;
@@ -58,7 +55,7 @@
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mHideDisplayCutoutController = new HideDisplayCutoutController(
- mContext, mShellController, mMockDisplayAreaOrganizer, mMockMainExecutor);
+ mContext, mShellController, mMockDisplayAreaOrganizer);
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
index 958969d..dbf93ae 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
@@ -149,6 +149,11 @@
}
@Test
+ public void testControllerRegistersKeyguardChangeListener() {
+ verify(mMockShellController, times(1)).addKeyguardChangeListener(any());
+ }
+
+ @Test
public void testDefaultShouldNotInOneHanded() {
// Assert default transition state is STATE_NONE
assertThat(mSpiedTransitionState.getState()).isEqualTo(STATE_NONE);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index 827785b..f192514 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -123,6 +123,11 @@
}
@Test
+ public void instantiatePipController_registerKeyguardChangeListener() {
+ verify(mMockShellController, times(1)).addKeyguardChangeListener(any());
+ }
+
+ @Test
public void instantiatePipController_registersPipTransitionCallback() {
verify(mMockPipTransitionController).registerPipTransitionCallback(any());
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
index c10e4a1..c7a261f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
@@ -28,6 +28,9 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.app.ActivityManager;
import android.content.ComponentName;
@@ -44,10 +47,12 @@
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
+import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.recents.RecentTasksController;
+import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.transition.Transitions;
import org.junit.Before;
@@ -65,6 +70,7 @@
@RunWith(AndroidJUnit4.class)
public class SplitScreenControllerTests extends ShellTestCase {
+ @Mock ShellController mShellController;
@Mock ShellTaskOrganizer mTaskOrganizer;
@Mock SyncTransactionQueue mSyncQueue;
@Mock RootTaskDisplayAreaOrganizer mRootTDAOrganizer;
@@ -82,10 +88,17 @@
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- mSplitScreenController = spy(new SplitScreenController(mTaskOrganizer, mSyncQueue, mContext,
- mRootTDAOrganizer, mMainExecutor, mDisplayController, mDisplayImeController,
- mDisplayInsetsController, mTransitions, mTransactionPool, mIconProvider,
- mRecentTasks));
+ mSplitScreenController = spy(new SplitScreenController(mShellController, mTaskOrganizer,
+ mSyncQueue, mContext, mRootTDAOrganizer, mMainExecutor, mDisplayController,
+ mDisplayImeController, mDisplayInsetsController, mTransitions, mTransactionPool,
+ mIconProvider, mRecentTasks));
+ }
+
+ @Test
+ public void testControllerRegistersKeyguardChangeListener() {
+ when(mDisplayController.getDisplayLayout(anyInt())).thenReturn(new DisplayLayout());
+ mSplitScreenController.onOrganizerRegistered();
+ verify(mShellController, times(1)).addKeyguardChangeListener(any());
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sysui/ShellControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sysui/ShellControllerTest.java
index 6cc3ae8..1c0e46f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sysui/ShellControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sysui/ShellControllerTest.java
@@ -46,12 +46,14 @@
private ShellExecutor mExecutor;
private ShellController mController;
- private TestConfigurationChangeListener mListener;
+ private TestConfigurationChangeListener mConfigChangeListener;
+ private TestKeyguardChangeListener mKeyguardChangeListener;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mListener = new TestConfigurationChangeListener();
+ mKeyguardChangeListener = new TestKeyguardChangeListener();
+ mConfigChangeListener = new TestConfigurationChangeListener();
mController = new ShellController(mExecutor);
mController.onConfigurationChanged(getConfigurationCopy());
}
@@ -62,47 +64,97 @@
}
@Test
+ public void testAddKeyguardChangeListener_ensureCallback() {
+ mController.addKeyguardChangeListener(mKeyguardChangeListener);
+
+ mController.onKeyguardVisibilityChanged(true, false, false);
+ assertTrue(mKeyguardChangeListener.visibilityChanged == 1);
+ assertTrue(mKeyguardChangeListener.dismissAnimationFinished == 0);
+ }
+
+ @Test
+ public void testDoubleAddKeyguardChangeListener_ensureSingleCallback() {
+ mController.addKeyguardChangeListener(mKeyguardChangeListener);
+ mController.addKeyguardChangeListener(mKeyguardChangeListener);
+
+ mController.onKeyguardVisibilityChanged(true, false, false);
+ assertTrue(mKeyguardChangeListener.visibilityChanged == 1);
+ assertTrue(mKeyguardChangeListener.dismissAnimationFinished == 0);
+ }
+
+ @Test
+ public void testAddRemoveKeyguardChangeListener_ensureNoCallback() {
+ mController.addKeyguardChangeListener(mKeyguardChangeListener);
+ mController.removeKeyguardChangeListener(mKeyguardChangeListener);
+
+ mController.onKeyguardVisibilityChanged(true, false, false);
+ assertTrue(mKeyguardChangeListener.visibilityChanged == 0);
+ assertTrue(mKeyguardChangeListener.dismissAnimationFinished == 0);
+ }
+
+ @Test
+ public void testKeyguardVisibilityChanged() {
+ mController.addKeyguardChangeListener(mKeyguardChangeListener);
+
+ mController.onKeyguardVisibilityChanged(true, true, true);
+ assertTrue(mKeyguardChangeListener.visibilityChanged == 1);
+ assertTrue(mKeyguardChangeListener.lastAnimatingDismiss);
+ assertTrue(mKeyguardChangeListener.lastOccluded);
+ assertTrue(mKeyguardChangeListener.lastAnimatingDismiss);
+ assertTrue(mKeyguardChangeListener.dismissAnimationFinished == 0);
+ }
+
+ @Test
+ public void testKeyguardDismissAnimationFinished() {
+ mController.addKeyguardChangeListener(mKeyguardChangeListener);
+
+ mController.onKeyguardDismissAnimationFinished();
+ assertTrue(mKeyguardChangeListener.visibilityChanged == 0);
+ assertTrue(mKeyguardChangeListener.dismissAnimationFinished == 1);
+ }
+
+ @Test
public void testAddConfigurationChangeListener_ensureCallback() {
- mController.addConfigurationChangeListener(mListener);
+ mController.addConfigurationChangeListener(mConfigChangeListener);
Configuration newConfig = getConfigurationCopy();
newConfig.densityDpi = 200;
mController.onConfigurationChanged(newConfig);
- assertTrue(mListener.configChanges == 1);
+ assertTrue(mConfigChangeListener.configChanges == 1);
}
@Test
public void testDoubleAddConfigurationChangeListener_ensureSingleCallback() {
- mController.addConfigurationChangeListener(mListener);
- mController.addConfigurationChangeListener(mListener);
+ mController.addConfigurationChangeListener(mConfigChangeListener);
+ mController.addConfigurationChangeListener(mConfigChangeListener);
Configuration newConfig = getConfigurationCopy();
newConfig.densityDpi = 200;
mController.onConfigurationChanged(newConfig);
- assertTrue(mListener.configChanges == 1);
+ assertTrue(mConfigChangeListener.configChanges == 1);
}
@Test
public void testAddRemoveConfigurationChangeListener_ensureNoCallback() {
- mController.addConfigurationChangeListener(mListener);
- mController.removeConfigurationChangeListener(mListener);
+ mController.addConfigurationChangeListener(mConfigChangeListener);
+ mController.removeConfigurationChangeListener(mConfigChangeListener);
Configuration newConfig = getConfigurationCopy();
newConfig.densityDpi = 200;
mController.onConfigurationChanged(newConfig);
- assertTrue(mListener.configChanges == 0);
+ assertTrue(mConfigChangeListener.configChanges == 0);
}
@Test
public void testMultipleConfigurationChangeListeners() {
TestConfigurationChangeListener listener2 = new TestConfigurationChangeListener();
- mController.addConfigurationChangeListener(mListener);
+ mController.addConfigurationChangeListener(mConfigChangeListener);
mController.addConfigurationChangeListener(listener2);
Configuration newConfig = getConfigurationCopy();
newConfig.densityDpi = 200;
mController.onConfigurationChanged(newConfig);
- assertTrue(mListener.configChanges == 1);
+ assertTrue(mConfigChangeListener.configChanges == 1);
assertTrue(listener2.configChanges == 1);
}
@@ -115,7 +167,7 @@
}
};
mController.addConfigurationChangeListener(badListener);
- mController.addConfigurationChangeListener(mListener);
+ mController.addConfigurationChangeListener(mConfigChangeListener);
// Ensure we don't fail just because a listener was removed mid-callback
Configuration newConfig = getConfigurationCopy();
@@ -125,77 +177,77 @@
@Test
public void testDensityChangeCallback() {
- mController.addConfigurationChangeListener(mListener);
+ mController.addConfigurationChangeListener(mConfigChangeListener);
Configuration newConfig = getConfigurationCopy();
newConfig.densityDpi = 200;
mController.onConfigurationChanged(newConfig);
- assertTrue(mListener.configChanges == 1);
- assertTrue(mListener.densityChanges == 1);
- assertTrue(mListener.smallestWidthChanges == 0);
- assertTrue(mListener.themeChanges == 0);
- assertTrue(mListener.localeChanges == 0);
+ assertTrue(mConfigChangeListener.configChanges == 1);
+ assertTrue(mConfigChangeListener.densityChanges == 1);
+ assertTrue(mConfigChangeListener.smallestWidthChanges == 0);
+ assertTrue(mConfigChangeListener.themeChanges == 0);
+ assertTrue(mConfigChangeListener.localeChanges == 0);
}
@Test
public void testFontScaleChangeCallback() {
- mController.addConfigurationChangeListener(mListener);
+ mController.addConfigurationChangeListener(mConfigChangeListener);
Configuration newConfig = getConfigurationCopy();
newConfig.fontScale = 2;
mController.onConfigurationChanged(newConfig);
- assertTrue(mListener.configChanges == 1);
- assertTrue(mListener.densityChanges == 1);
- assertTrue(mListener.smallestWidthChanges == 0);
- assertTrue(mListener.themeChanges == 0);
- assertTrue(mListener.localeChanges == 0);
+ assertTrue(mConfigChangeListener.configChanges == 1);
+ assertTrue(mConfigChangeListener.densityChanges == 1);
+ assertTrue(mConfigChangeListener.smallestWidthChanges == 0);
+ assertTrue(mConfigChangeListener.themeChanges == 0);
+ assertTrue(mConfigChangeListener.localeChanges == 0);
}
@Test
public void testSmallestWidthChangeCallback() {
- mController.addConfigurationChangeListener(mListener);
+ mController.addConfigurationChangeListener(mConfigChangeListener);
Configuration newConfig = getConfigurationCopy();
newConfig.smallestScreenWidthDp = 100;
mController.onConfigurationChanged(newConfig);
- assertTrue(mListener.configChanges == 1);
- assertTrue(mListener.densityChanges == 0);
- assertTrue(mListener.smallestWidthChanges == 1);
- assertTrue(mListener.themeChanges == 0);
- assertTrue(mListener.localeChanges == 0);
+ assertTrue(mConfigChangeListener.configChanges == 1);
+ assertTrue(mConfigChangeListener.densityChanges == 0);
+ assertTrue(mConfigChangeListener.smallestWidthChanges == 1);
+ assertTrue(mConfigChangeListener.themeChanges == 0);
+ assertTrue(mConfigChangeListener.localeChanges == 0);
}
@Test
public void testThemeChangeCallback() {
- mController.addConfigurationChangeListener(mListener);
+ mController.addConfigurationChangeListener(mConfigChangeListener);
Configuration newConfig = getConfigurationCopy();
newConfig.assetsSeq++;
mController.onConfigurationChanged(newConfig);
- assertTrue(mListener.configChanges == 1);
- assertTrue(mListener.densityChanges == 0);
- assertTrue(mListener.smallestWidthChanges == 0);
- assertTrue(mListener.themeChanges == 1);
- assertTrue(mListener.localeChanges == 0);
+ assertTrue(mConfigChangeListener.configChanges == 1);
+ assertTrue(mConfigChangeListener.densityChanges == 0);
+ assertTrue(mConfigChangeListener.smallestWidthChanges == 0);
+ assertTrue(mConfigChangeListener.themeChanges == 1);
+ assertTrue(mConfigChangeListener.localeChanges == 0);
}
@Test
public void testNightModeChangeCallback() {
- mController.addConfigurationChangeListener(mListener);
+ mController.addConfigurationChangeListener(mConfigChangeListener);
Configuration newConfig = getConfigurationCopy();
newConfig.uiMode = Configuration.UI_MODE_NIGHT_YES;
mController.onConfigurationChanged(newConfig);
- assertTrue(mListener.configChanges == 1);
- assertTrue(mListener.densityChanges == 0);
- assertTrue(mListener.smallestWidthChanges == 0);
- assertTrue(mListener.themeChanges == 1);
- assertTrue(mListener.localeChanges == 0);
+ assertTrue(mConfigChangeListener.configChanges == 1);
+ assertTrue(mConfigChangeListener.densityChanges == 0);
+ assertTrue(mConfigChangeListener.smallestWidthChanges == 0);
+ assertTrue(mConfigChangeListener.themeChanges == 1);
+ assertTrue(mConfigChangeListener.localeChanges == 0);
}
@Test
public void testLocaleChangeCallback() {
- mController.addConfigurationChangeListener(mListener);
+ mController.addConfigurationChangeListener(mConfigChangeListener);
Configuration newConfig = getConfigurationCopy();
// Just change the locales to be different
@@ -205,11 +257,11 @@
newConfig.locale = Locale.CANADA;
}
mController.onConfigurationChanged(newConfig);
- assertTrue(mListener.configChanges == 1);
- assertTrue(mListener.densityChanges == 0);
- assertTrue(mListener.smallestWidthChanges == 0);
- assertTrue(mListener.themeChanges == 0);
- assertTrue(mListener.localeChanges == 1);
+ assertTrue(mConfigChangeListener.configChanges == 1);
+ assertTrue(mConfigChangeListener.densityChanges == 0);
+ assertTrue(mConfigChangeListener.smallestWidthChanges == 0);
+ assertTrue(mConfigChangeListener.themeChanges == 0);
+ assertTrue(mConfigChangeListener.localeChanges == 1);
}
private Configuration getConfigurationCopy() {
@@ -253,4 +305,27 @@
localeChanges++;
}
}
+
+ private class TestKeyguardChangeListener implements KeyguardChangeListener {
+ // Counts of number of times each of the callbacks are called
+ public int visibilityChanged;
+ public boolean lastVisibility;
+ public boolean lastOccluded;
+ public boolean lastAnimatingDismiss;
+ public int dismissAnimationFinished;
+
+ @Override
+ public void onKeyguardVisibilityChanged(boolean visible, boolean occluded,
+ boolean animatingDismiss) {
+ lastVisibility = visible;
+ lastOccluded = occluded;
+ lastAnimatingDismiss = animatingDismiss;
+ visibilityChanged++;
+ }
+
+ @Override
+ public void onKeyguardDismissAnimationFinished() {
+ dismissAnimationFinished++;
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/tasksurfacehelper/TaskSurfaceHelperControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/tasksurfacehelper/TaskSurfaceHelperControllerTest.java
deleted file mode 100644
index 7583418..0000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/tasksurfacehelper/TaskSurfaceHelperControllerTest.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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.wm.shell.tasksurfacehelper;
-
-import static org.mockito.Mockito.verify;
-
-import android.testing.AndroidTestingRunner;
-import android.view.SurfaceControl;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.ShellTestCase;
-import com.android.wm.shell.common.ShellExecutor;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(AndroidTestingRunner.class)
-@SmallTest
-public class TaskSurfaceHelperControllerTest extends ShellTestCase {
- private TaskSurfaceHelperController mTaskSurfaceHelperController;
- @Mock
- private ShellTaskOrganizer mMockTaskOrganizer;
- @Mock
- private ShellExecutor mMockShellExecutor;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- mTaskSurfaceHelperController = new TaskSurfaceHelperController(
- mMockTaskOrganizer, mMockShellExecutor);
- }
-
- @Test
- public void testSetGameModeForTask() {
- mTaskSurfaceHelperController.setGameModeForTask(/*taskId*/1, /*gameMode*/3);
- verify(mMockTaskOrganizer).setSurfaceMetadata(1, SurfaceControl.METADATA_GAME_MODE, 3);
- }
-}
diff --git a/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml b/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml
index 50f69d1..c629d96 100644
--- a/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml
+++ b/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml
@@ -71,6 +71,8 @@
<TextView
android:id="@+id/entity_header_second_summary"
style="@style/TextAppearance.EntityHeaderSummary"
+ android:singleLine="false"
+ android:maxLines="4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index f92cc8e..4f84c8c 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -246,9 +246,9 @@
<!-- Bluetooth settings. The user-visible string that is used whenever referring to the PAN profile (accessing Internet through remote device). [CHAR LIMIT=40] -->
<string name="bluetooth_profile_pan">Internet access</string>
<!-- Bluetooth settings. The user-visible string that is used whenever referring to the PBAP profile. [CHAR LIMIT=40] -->
- <string name="bluetooth_profile_pbap">Contact sharing</string>
+ <string name="bluetooth_profile_pbap">Contacts and call history sharing</string>
<!-- Bluetooth settings. The user-visible summary string that is used whenever referring to the PBAP profile (sharing contacts). [CHAR LIMIT=60] -->
- <string name="bluetooth_profile_pbap_summary">Use for contact sharing</string>
+ <string name="bluetooth_profile_pbap_summary">Use for contacts and call history sharing</string>
<!-- Bluetooth settings. The user-visible string that is used whenever referring to the PAN profile (sharing this device's Internet connection). [CHAR LIMIT=40] -->
<string name="bluetooth_profile_pan_nap">Internet connection sharing</string>
<!-- Bluetooth settings. The user-visible string that is used whenever referring to the map profile. -->
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index fbe3356..8ddd430 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -523,9 +523,10 @@
state: LaunchAnimator.State,
linearProgress: Float,
) {
- if (transactionApplierView.viewRootImpl == null) {
- // If the view root we synchronize with was detached, don't apply any transaction
- // (as [SyncRtSurfaceTransactionApplier.scheduleApply] would otherwise throw).
+ if (transactionApplierView.viewRootImpl == null || !window.leash.isValid) {
+ // Don't apply any transaction if the view root we synchronize with was detached or
+ // if the SurfaceControl associated with [window] is not valid, as
+ // [SyncRtSurfaceTransactionApplier.scheduleApply] would otherwise throw.
return
}
@@ -605,9 +606,10 @@
state: LaunchAnimator.State,
linearProgress: Float
) {
- if (transactionApplierView.viewRootImpl == null) {
- // If the view root we synchronize with was detached, don't apply any transaction
- // (as [SyncRtSurfaceTransactionApplier.scheduleApply] would otherwise throw).
+ if (transactionApplierView.viewRootImpl == null || !navigationBar.leash.isValid) {
+ // Don't apply any transaction if the view root we synchronize with was detached or
+ // if the SurfaceControl associated with [navigationBar] is not valid, as
+ // [SyncRtSurfaceTransactionApplier.scheduleApply] would otherwise throw.
return
}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
index 47f448d..eb000ad 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
@@ -49,17 +49,16 @@
* Note: Avoid instantiating this directly and call [ActivityLaunchAnimator.Controller.fromView]
* whenever possible instead.
*/
-open class GhostedViewLaunchAnimatorController(
+open class GhostedViewLaunchAnimatorController @JvmOverloads constructor(
/** The view that will be ghosted and from which the background will be extracted. */
private val ghostedView: View,
/** The [InteractionJankMonitor.CujType] associated to this animation. */
private val cujType: Int? = null,
- private var interactionJankMonitor: InteractionJankMonitor? = null
+ private var interactionJankMonitor: InteractionJankMonitor =
+ InteractionJankMonitor.getInstance(),
) : ActivityLaunchAnimator.Controller {
- constructor(view: View, type: Int) : this(view, type, null)
-
/** The container to which we will add the ghost view and expanding background. */
override var launchContainer = ghostedView.rootView as ViewGroup
private val launchContainerOverlay: ViewGroupOverlay
@@ -203,7 +202,7 @@
val matrix = ghostView?.animationMatrix ?: Matrix.IDENTITY_MATRIX
matrix.getValues(initialGhostViewMatrixValues)
- cujType?.let { interactionJankMonitor?.begin(ghostedView, it) }
+ cujType?.let { interactionJankMonitor.begin(ghostedView, it) }
}
override fun onLaunchAnimationProgress(
@@ -289,7 +288,7 @@
return
}
- cujType?.let { interactionJankMonitor?.end(it) }
+ cujType?.let { interactionJankMonitor.end(it) }
backgroundDrawable?.wrapped?.alpha = startBackgroundAlpha
diff --git a/packages/SystemUI/docs/user-file-manager.md b/packages/SystemUI/docs/user-file-manager.md
index 64f1694..52fa206 100644
--- a/packages/SystemUI/docs/user-file-manager.md
+++ b/packages/SystemUI/docs/user-file-manager.md
@@ -1,10 +1,30 @@
# UserFileManager
-This class is used to generate file paths and SharedPreferences that is compatible for multiple
+This class is used to generate file paths and SharedPreferences that is compatible for specific OS
users in SystemUI. Due to constraints in SystemUI, we can only read/write files as the system user.
Therefore, for secondary users, we want to store secondary user specific files into the system user
directory.
+
+## Usages
+
+Inject UserFileManager into your class.
+
+### fun getFile(fileName: String, userId: Int): File
+Add a file name and user id. You can retrieve the current user id from UserTracker. This will
+return a java.io File object that contains the file path to write/read to.
+
+i.e. `fileManager.getFile("example.xml", userTracker.userId)`
+
+### fun getSharedPreferences(fileName: String, mode: Int, userId: Int): SharedPreferences
+Add a file name, user id, and PreferencesMode. You can retrieve the current user id from
+UserTracker. This returns SharedPreferences object that is tied to the specific user. Note that if
+the SharedPreferences file does not exist, one will be created automatically. See
+[SharedPreferences documentation](https://developer.android.com/reference/android/content/Context#getSharedPreferences(java.lang.String,%20int))
+for more details.
+
+i.e. `fileManager.getSharedPreferences("prefs.xml", userTracker.userId, 0)`
+
## Handling User Removal
This class will listen for Intent.ACTION_USER_REMOVED and remove directories that no longer
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
index 3058d94..bef61b8 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
@@ -23,7 +23,9 @@
/**
* Plugin used to replace main clock in keyguard.
+ * @deprecated Migrating to ClockProviderPlugin
*/
+@Deprecated
@ProvidesInterface(action = ClockPlugin.ACTION, version = ClockPlugin.VERSION)
public interface ClockPlugin extends Plugin {
diff --git a/packages/SystemUI/res/layout/clipboard_overlay.xml b/packages/SystemUI/res/layout/clipboard_overlay.xml
index 99a5a2e..1a1fc75 100644
--- a/packages/SystemUI/res/layout/clipboard_overlay.xml
+++ b/packages/SystemUI/res/layout/clipboard_overlay.xml
@@ -115,6 +115,7 @@
android:autoSizeMinTextSize="@dimen/clipboard_overlay_min_font"
android:autoSizeMaxTextSize="@dimen/clipboard_overlay_max_font"
android:textColor="?attr/overlayButtonTextColor"
+ android:textColorLink="?attr/overlayButtonTextColor"
android:background="?androidprv:attr/colorAccentSecondary"
android:layout_width="@dimen/clipboard_preview_size"
android:layout_height="@dimen/clipboard_preview_size"/>
diff --git a/packages/SystemUI/res/layout/keyguard_status_bar.xml b/packages/SystemUI/res/layout/keyguard_status_bar.xml
index e47eed9..d27fa19 100644
--- a/packages/SystemUI/res/layout/keyguard_status_bar.xml
+++ b/packages/SystemUI/res/layout/keyguard_status_bar.xml
@@ -60,9 +60,8 @@
</com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer>
<FrameLayout android:id="@+id/system_icons_container"
- android:layout_width="0dp"
+ android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:layout_weight="1"
android:layout_marginEnd="@dimen/status_bar_padding_end"
android:gravity="center_vertical|end">
<include layout="@layout/system_icons" />
diff --git a/packages/SystemUI/res/layout/notification_icon_area.xml b/packages/SystemUI/res/layout/notification_icon_area.xml
index fa696cc..aadfae8 100644
--- a/packages/SystemUI/res/layout/notification_icon_area.xml
+++ b/packages/SystemUI/res/layout/notification_icon_area.xml
@@ -14,18 +14,9 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-<com.android.keyguard.AlphaOptimizedLinearLayout
+<com.android.systemui.statusbar.phone.NotificationIconContainer
xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/notification_icon_area_inner"
- android:layout_width="match_parent"
+ android:id="@+id/notificationIcons"
+ android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:clipChildren="false">
- <com.android.systemui.statusbar.phone.NotificationIconContainer
- android:id="@+id/notificationIcons"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_alignParentStart="true"
- android:gravity="center_vertical"
- android:orientation="horizontal"
- android:clipChildren="false"/>
-</com.android.keyguard.AlphaOptimizedLinearLayout>
\ No newline at end of file
+ android:clipChildren="false"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index deab1eb..e281511 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -47,52 +47,63 @@
android:paddingStart="@dimen/status_bar_padding_start"
android:paddingEnd="@dimen/status_bar_padding_end"
android:paddingTop="@dimen/status_bar_padding_top"
- android:orientation="horizontal"
- >
+ android:orientation="horizontal">
+
+ <!-- Container for the entire start half of the status bar. It will always use the same
+ width, independent of the number of visible children and sub-children. -->
<FrameLayout
+ android:id="@+id/status_bar_start_side_container"
android:layout_height="match_parent"
android:layout_width="0dp"
android:layout_weight="1">
- <include layout="@layout/heads_up_status_bar_layout" />
+ <!-- Container that is wrapped around the views on the start half of the status bar.
+ Its width will change with the number of visible children and sub-children.
+ It is useful when we want to know the visible bounds of the content. -->
+ <FrameLayout
+ android:id="@+id/status_bar_start_side_content"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:clipChildren="false">
- <!-- The alpha of the left side is controlled by PhoneStatusBarTransitions, and the
- individual views are controlled by StatusBarManager disable flags DISABLE_CLOCK and
- DISABLE_NOTIFICATION_ICONS, respectively -->
- <LinearLayout
- android:id="@+id/status_bar_left_side"
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:clipChildren="false"
- >
- <ViewStub
- android:id="@+id/operator_name"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout="@layout/operator_name" />
+ <include layout="@layout/heads_up_status_bar_layout" />
- <com.android.systemui.statusbar.policy.Clock
- android:id="@+id/clock"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:textAppearance="@style/TextAppearance.StatusBar.Clock"
- android:singleLine="true"
- android:paddingStart="@dimen/status_bar_left_clock_starting_padding"
- android:paddingEnd="@dimen/status_bar_left_clock_end_padding"
- android:gravity="center_vertical|start"
- />
+ <!-- The alpha of the start side is controlled by PhoneStatusBarTransitions, and the
+ individual views are controlled by StatusBarManager disable flags DISABLE_CLOCK
+ and DISABLE_NOTIFICATION_ICONS, respectively -->
+ <LinearLayout
+ android:id="@+id/status_bar_start_side_except_heads_up"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:clipChildren="false">
+ <ViewStub
+ android:id="@+id/operator_name"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout="@layout/operator_name" />
- <include layout="@layout/ongoing_call_chip" />
+ <com.android.systemui.statusbar.policy.Clock
+ android:id="@+id/clock"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:textAppearance="@style/TextAppearance.StatusBar.Clock"
+ android:singleLine="true"
+ android:paddingStart="@dimen/status_bar_left_clock_starting_padding"
+ android:paddingEnd="@dimen/status_bar_left_clock_end_padding"
+ android:gravity="center_vertical|start"
+ />
- <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
- android:id="@+id/notification_icon_area"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:orientation="horizontal"
- android:clipChildren="false"/>
+ <include layout="@layout/ongoing_call_chip" />
- </LinearLayout>
+ <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
+ android:id="@+id/notification_icon_area"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:orientation="horizontal"
+ android:clipChildren="false"/>
+
+ </LinearLayout>
+ </FrameLayout>
</FrameLayout>
<!-- Space should cover the notch (if it exists) and let other views lay out around it -->
@@ -103,42 +114,57 @@
android:gravity="center_horizontal|center_vertical"
/>
- <com.android.keyguard.AlphaOptimizedLinearLayout android:id="@+id/system_icon_area"
+ <!-- Container for the entire end half of the status bar. It will always use the same
+ width, independent of the number of visible children and sub-children. -->
+ <FrameLayout
+ android:id="@+id/status_bar_end_side_container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
- android:orientation="horizontal"
- android:gravity="center_vertical|end"
- >
+ android:clipChildren="false">
- <com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer
- android:id="@+id/user_switcher_container"
+ <!-- Container that is wrapped around the views on the end half of the
+ status bar. Its width will change with the number of visible children and
+ sub-children.
+ It is useful when we want know the visible bounds of the content.-->
+ <com.android.keyguard.AlphaOptimizedLinearLayout
+ android:id="@+id/status_bar_end_side_content"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center"
+ android:layout_height="match_parent"
+ android:layout_gravity="end"
android:orientation="horizontal"
- android:paddingTop="4dp"
- android:paddingBottom="4dp"
- android:paddingStart="8dp"
- android:paddingEnd="8dp"
- android:layout_marginEnd="16dp"
- android:background="@drawable/status_bar_user_chip_bg"
- android:visibility="visible" >
- <ImageView android:id="@+id/current_user_avatar"
- android:layout_width="@dimen/multi_user_avatar_keyguard_size"
- android:layout_height="@dimen/multi_user_avatar_keyguard_size"
- android:scaleType="centerInside"
- android:paddingEnd="4dp" />
+ android:gravity="center_vertical|end"
+ android:clipChildren="false">
- <TextView android:id="@+id/current_user_name"
+ <com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer
+ android:id="@+id/user_switcher_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textAppearance="@style/TextAppearance.StatusBar.Clock"
- />
- </com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer>
+ android:gravity="center"
+ android:orientation="horizontal"
+ android:paddingTop="4dp"
+ android:paddingBottom="4dp"
+ android:paddingStart="8dp"
+ android:paddingEnd="8dp"
+ android:layout_marginEnd="16dp"
+ android:background="@drawable/status_bar_user_chip_bg"
+ android:visibility="visible" >
+ <ImageView android:id="@+id/current_user_avatar"
+ android:layout_width="@dimen/multi_user_avatar_keyguard_size"
+ android:layout_height="@dimen/multi_user_avatar_keyguard_size"
+ android:scaleType="centerInside"
+ android:paddingEnd="4dp" />
- <include layout="@layout/system_icons" />
- </com.android.keyguard.AlphaOptimizedLinearLayout>
+ <TextView android:id="@+id/current_user_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="@style/TextAppearance.StatusBar.Clock"
+ />
+ </com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer>
+
+ <include layout="@layout/system_icons" />
+ </com.android.keyguard.AlphaOptimizedLinearLayout>
+ </FrameLayout>
</LinearLayout>
<ViewStub
diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp
index 9f790c6..114ea65 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/Android.bp
@@ -50,6 +50,7 @@
"SystemUIUnfoldLib",
"androidx.dynamicanimation_dynamicanimation",
"androidx.concurrent_concurrent-futures",
+ "gson-prebuilt-jar",
"dagger2",
"jsr330",
],
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockProviderPlugin.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockProviderPlugin.kt
new file mode 100644
index 0000000..916a557
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockProviderPlugin.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.android.systemui.shared.clocks
+
+import com.android.systemui.plugins.Plugin
+import com.android.systemui.plugins.annotations.ProvidesInterface
+import android.annotation.FloatRange
+import android.graphics.drawable.Drawable
+import android.view.View
+
+/** Identifies a clock design */
+typealias ClockId = String
+
+/** A Plugin which exposes the ClockProvider interface */
+@ProvidesInterface(action = ClockProviderPlugin.ACTION, version = ClockProviderPlugin.VERSION)
+interface ClockProviderPlugin : Plugin, ClockProvider {
+ companion object {
+ const val ACTION = "com.android.systemui.action.PLUGIN_CLOCK_PROVIDER"
+ const val VERSION = 1
+ }
+}
+
+/** Interface for building clocks and providing information about those clocks */
+interface ClockProvider {
+ /** Returns metadata for all clocks this provider knows about */
+ fun getClocks(): List<ClockMetadata>
+
+ /** Initializes and returns the target clock design */
+ fun createClock(id: ClockId): Clock
+
+ /** A static thumbnail for rendering in some examples */
+ fun getClockThumbnail(id: ClockId): Drawable?
+}
+
+/** Interface for controlling an active clock */
+interface Clock {
+ /** A small version of the clock, appropriate for smaller viewports */
+ val smallClock: View
+
+ /** A large version of the clock, appropriate when a bigger viewport is available */
+ val largeClock: View
+
+ /** Callback to update the clock view to the current time */
+ fun onTimeTick()
+
+ /** Sets the level of the AOD transition */
+ fun setAodFraction(@FloatRange(from = 0.0, to = 1.0) fraction: Float)
+}
+
+/** Some data about a clock design */
+data class ClockMetadata(
+ val clockId: ClockId,
+ val name: String
+)
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt
new file mode 100644
index 0000000..3245966
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.android.systemui.shared.clocks
+
+import android.content.Context
+import android.database.ContentObserver
+import android.graphics.drawable.Drawable
+import android.net.Uri
+import android.os.Handler
+import android.os.UserHandle
+import android.provider.Settings
+import android.util.Log
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.plugins.PluginListener
+import com.android.systemui.shared.plugins.PluginManager
+import com.google.gson.Gson
+import javax.inject.Inject
+
+private val TAG = ClockRegistry::class.simpleName
+private val DEBUG = true
+const val DEFAULT_CLOCK_ID = "DEFAULT"
+
+typealias ClockChangeListener = () -> Unit
+
+/** ClockRegistry aggregates providers and plugins */
+open class ClockRegistry @Inject constructor(
+ val context: Context,
+ val pluginManager: PluginManager,
+ @Main val handler: Handler
+) {
+ private val gson = Gson()
+ private val availableClocks = mutableMapOf<ClockId, ClockInfo>()
+ private val clockChangeListeners = mutableListOf<ClockChangeListener>()
+ private val settingObserver = object : ContentObserver(handler) {
+ override fun onChange(selfChange: Boolean, uris: Collection<Uri>, flags: Int, userId: Int) =
+ clockChangeListeners.forEach { it() }
+ }
+
+ private val pluginListener = object : PluginListener<ClockProviderPlugin> {
+ override fun onPluginConnected(plugin: ClockProviderPlugin, context: Context) {
+ val currentId = currentClockId
+ for (clock in plugin.getClocks()) {
+ val id = clock.clockId
+ val current = availableClocks[id]
+ if (current != null) {
+ Log.e(TAG, "Clock Id conflict: $id is registered by both " +
+ "${plugin::class.simpleName} and ${current.provider::class.simpleName}")
+ return
+ }
+
+ availableClocks[id] = ClockInfo(clock, plugin)
+
+ if (currentId == id) {
+ if (DEBUG) {
+ Log.i(TAG, "Current clock ($currentId) was connected")
+ }
+ clockChangeListeners.forEach { it() }
+ }
+ }
+ }
+
+ override fun onPluginDisconnected(plugin: ClockProviderPlugin) {
+ val currentId = currentClockId
+ for (clock in plugin.getClocks()) {
+ availableClocks.remove(clock.clockId)
+
+ if (currentId == clock.clockId) {
+ Log.w(TAG, "Current clock ($currentId) was disconnected")
+ clockChangeListeners.forEach { it() }
+ }
+ }
+ }
+ }
+
+ open var currentClockId: ClockId
+ get() {
+ val json = Settings.Secure.getString(context.contentResolver,
+ Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE)
+ return gson.fromJson(json, ClockSetting::class.java).clockId
+ }
+ set(value) {
+ val json = gson.toJson(ClockSetting(value, System.currentTimeMillis()))
+ Settings.Secure.putString(context.contentResolver,
+ Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE, json)
+ }
+
+ init {
+ pluginManager.addPluginListener(pluginListener, ClockProviderPlugin::class.java)
+ context.contentResolver.registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE),
+ false,
+ settingObserver,
+ UserHandle.USER_ALL)
+ }
+
+ fun getClocks(): List<ClockMetadata> = availableClocks.map { (_, clock) -> clock.metadata }
+
+ fun getClockThumbnail(clockId: ClockId): Drawable? =
+ availableClocks[clockId]?.provider?.getClockThumbnail(clockId)
+
+ fun createExampleClock(clockId: ClockId): Clock? = createClock(clockId)
+
+ fun registerClockChangeListener(listener: ClockChangeListener) =
+ clockChangeListeners.add(listener)
+
+ fun unregisterClockChangeListener(listener: ClockChangeListener) =
+ clockChangeListeners.remove(listener)
+
+ fun createCurrentClock(): Clock {
+ val clockId = currentClockId
+ if (!clockId.isNullOrEmpty()) {
+ val clock = createClock(clockId)
+ if (clock != null) {
+ return clock
+ } else {
+ Log.e(TAG, "Clock $clockId not found; using default")
+ }
+ }
+
+ return createClock(DEFAULT_CLOCK_ID)!!
+ }
+
+ private fun createClock(clockId: ClockId): Clock? =
+ availableClocks[clockId]?.provider?.createClock(clockId)
+
+ private data class ClockInfo(
+ val metadata: ClockMetadata,
+ val provider: ClockProvider
+ )
+
+ private data class ClockSetting(
+ val clockId: ClockId,
+ val _applied_timestamp: Long
+ )
+}
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
index 13f1db4a..0094820 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
@@ -65,14 +65,6 @@
}
}
- public void hideCurrentInputMethod() {
- try {
- mAnimationController.hideCurrentInputMethod();
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to set hide input method", e);
- }
- }
-
/**
* Sets the final surface transaction on a Task. This is used by Launcher to notify the system
* that animating Activity to PiP has completed and the associated task surface should be
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
index ff2a7a1..609846e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
@@ -369,10 +369,6 @@
if (mWrapped != null) mWrapped.setAnimationTargetsBehindSystemBars(behindSystemBars);
}
- @Override public void hideCurrentInputMethod() {
- mWrapped.hideCurrentInputMethod();
- }
-
@Override public void setFinishTaskTransaction(int taskId,
PictureInPictureSurfaceTransaction finishTransaction, SurfaceControl overlay) {
mPipTransaction = finishTransaction;
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
index 013cdac..9a0bfc1 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
@@ -53,8 +53,11 @@
/**
* Manages custom clock faces for AOD and lock screen.
+ *
+ * @deprecated Migrate to ClockRegistry
*/
@SysUISingleton
+@Deprecated
public final class ClockManager {
private static final String TAG = "ClockOptsProvider";
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java b/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java
index 08096b0..24fcf15 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java
@@ -96,16 +96,12 @@
.setSplitScreen(mWMComponent.getSplitScreen())
.setOneHanded(mWMComponent.getOneHanded())
.setBubbles(mWMComponent.getBubbles())
- .setHideDisplayCutout(mWMComponent.getHideDisplayCutout())
.setShellCommandHandler(mWMComponent.getShellCommandHandler())
.setTaskViewFactory(mWMComponent.getTaskViewFactory())
.setTransitions(mWMComponent.getTransitions())
.setStartingSurface(mWMComponent.getStartingSurface())
.setDisplayAreaHelper(mWMComponent.getDisplayAreaHelper())
- .setTaskSurfaceHelper(mWMComponent.getTaskSurfaceHelper())
.setRecentTasks(mWMComponent.getRecentTasks())
- .setCompatUI(mWMComponent.getCompatUI())
- .setDragAndDrop(mWMComponent.getDragAndDrop())
.setBackAnimation(mWMComponent.getBackAnimation());
} else {
// TODO: Call on prepareSysUIComponentBuilder but not with real components. Other option
@@ -116,16 +112,12 @@
.setSplitScreen(Optional.ofNullable(null))
.setOneHanded(Optional.ofNullable(null))
.setBubbles(Optional.ofNullable(null))
- .setHideDisplayCutout(Optional.ofNullable(null))
.setShellCommandHandler(Optional.ofNullable(null))
.setTaskViewFactory(Optional.ofNullable(null))
.setTransitions(new ShellTransitions() {})
.setDisplayAreaHelper(Optional.ofNullable(null))
.setStartingSurface(Optional.ofNullable(null))
- .setTaskSurfaceHelper(Optional.ofNullable(null))
.setRecentTasks(Optional.ofNullable(null))
- .setCompatUI(Optional.ofNullable(null))
- .setDragAndDrop(Optional.ofNullable(null))
.setBackAnimation(Optional.ofNullable(null));
}
mSysUIComponent = builder.build();
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index fb502e5..cf50f7f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -609,7 +609,7 @@
@NonNull SystemUIDialogManager dialogManager,
@NonNull LatencyTracker latencyTracker,
@NonNull ActivityLaunchAnimator activityLaunchAnimator,
- @NonNull Optional<AlternateUdfpsTouchProvider> aternateTouchProvider,
+ @NonNull Optional<AlternateUdfpsTouchProvider> alternateTouchProvider,
@BiometricsBackground Executor biometricsExecutor) {
mContext = context;
mExecution = execution;
@@ -639,7 +639,7 @@
mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
mLatencyTracker = latencyTracker;
mActivityLaunchAnimator = activityLaunchAnimator;
- mAlternateTouchProvider = aternateTouchProvider.orElse(null);
+ mAlternateTouchProvider = alternateTouchProvider.orElse(null);
mBiometricExecutor = biometricsExecutor;
mOrientationListener = new BiometricDisplayListener(
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
index bed553e..50ce9d4 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
@@ -20,13 +20,11 @@
import android.app.backup.BackupManager
import android.content.BroadcastReceiver
import android.content.ComponentName
-import android.content.ContentResolver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.database.ContentObserver
import android.net.Uri
-import android.os.Environment
import android.os.UserHandle
import android.service.controls.Control
import android.service.controls.actions.ControlAction
@@ -43,6 +41,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dump.DumpManager
+import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl.Companion.PREFS_CONTROLS_FILE
import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl.Companion.PREFS_CONTROLS_SEEDING_COMPLETED
@@ -61,6 +60,7 @@
private val bindingController: ControlsBindingController,
private val listingController: ControlsListingController,
private val broadcastDispatcher: BroadcastDispatcher,
+ private val userFileManager: UserFileManager,
optionalWrapper: Optional<ControlsFavoritePersistenceWrapper>,
dumpManager: DumpManager,
userTracker: UserTracker
@@ -84,15 +84,12 @@
override val currentUserId
get() = currentUser.identifier
- private val contentResolver: ContentResolver
- get() = context.contentResolver
-
private val persistenceWrapper: ControlsFavoritePersistenceWrapper
@VisibleForTesting
internal var auxiliaryPersistenceWrapper: AuxiliaryPersistenceWrapper
init {
- userStructure = UserStructure(context, currentUser)
+ userStructure = UserStructure(context, currentUser, userFileManager)
persistenceWrapper = optionalWrapper.orElseGet {
ControlsFavoritePersistenceWrapper(
@@ -111,7 +108,7 @@
private fun setValuesForUser(newUser: UserHandle) {
Log.d(TAG, "Changing to user: $newUser")
currentUser = newUser
- userStructure = UserStructure(context, currentUser)
+ userStructure = UserStructure(context, currentUser, userFileManager)
persistenceWrapper.changeFileAndBackupManager(
userStructure.file,
BackupManager(userStructure.userContext)
@@ -187,8 +184,11 @@
// When a component is uninstalled, allow seeding to happen again if the user
// reinstalls the app
- val prefs = userStructure.userContext.getSharedPreferences(
- PREFS_CONTROLS_FILE, Context.MODE_PRIVATE)
+ val prefs = userFileManager.getSharedPreferences(
+ PREFS_CONTROLS_FILE,
+ Context.MODE_PRIVATE,
+ userTracker.userId
+ )
val completedSeedingPackageSet = prefs.getStringSet(
PREFS_CONTROLS_SEEDING_COMPLETED, mutableSetOf<String>())
val servicePackageSet = serviceInfoSet.map { it.packageName }
@@ -575,18 +575,12 @@
}
}
-class UserStructure(context: Context, user: UserHandle) {
+class UserStructure(context: Context, user: UserHandle, userFileManager: UserFileManager) {
val userContext = context.createContextAsUser(user, 0)
-
- val file = Environment.buildPath(
- userContext.filesDir,
- ControlsFavoritePersistenceWrapper.FILE_NAME
- )
-
- val auxiliaryFile = Environment.buildPath(
- userContext.filesDir,
- AuxiliaryPersistenceWrapper.AUXILIARY_FILE_NAME
- )
+ val file = userFileManager.getFile(ControlsFavoritePersistenceWrapper.FILE_NAME,
+ user.identifier)
+ val auxiliaryFile = userFileManager.getFile(AuxiliaryPersistenceWrapper.AUXILIARY_FILE_NAME,
+ user.identifier)
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index adeafd5..fd7680f 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -41,17 +41,13 @@
import com.android.wm.shell.TaskViewFactory;
import com.android.wm.shell.back.BackAnimation;
import com.android.wm.shell.bubbles.Bubbles;
-import com.android.wm.shell.compatui.CompatUI;
import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
-import com.android.wm.shell.draganddrop.DragAndDrop;
-import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.recents.RecentTasks;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.startingsurface.StartingSurface;
import com.android.wm.shell.sysui.ShellInterface;
-import com.android.wm.shell.tasksurfacehelper.TaskSurfaceHelper;
import com.android.wm.shell.transition.ShellTransitions;
import java.util.Map;
@@ -100,9 +96,6 @@
Builder setTaskViewFactory(Optional<TaskViewFactory> t);
@BindsInstance
- Builder setHideDisplayCutout(Optional<HideDisplayCutout> h);
-
- @BindsInstance
Builder setShellCommandHandler(Optional<ShellCommandHandler> shellDump);
@BindsInstance
@@ -115,18 +108,9 @@
Builder setDisplayAreaHelper(Optional<DisplayAreaHelper> h);
@BindsInstance
- Builder setTaskSurfaceHelper(Optional<TaskSurfaceHelper> t);
-
- @BindsInstance
Builder setRecentTasks(Optional<RecentTasks> r);
@BindsInstance
- Builder setCompatUI(Optional<CompatUI> s);
-
- @BindsInstance
- Builder setDragAndDrop(Optional<DragAndDrop> d);
-
- @BindsInstance
Builder setBackAnimation(Optional<BackAnimation> b);
SysUIComponent build();
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
index b6003e9..e4c0325 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
@@ -29,20 +29,16 @@
import com.android.wm.shell.back.BackAnimation;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.common.annotations.ShellMainThread;
-import com.android.wm.shell.compatui.CompatUI;
import com.android.wm.shell.dagger.TvWMShellModule;
import com.android.wm.shell.dagger.WMShellModule;
import com.android.wm.shell.dagger.WMSingleton;
import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
-import com.android.wm.shell.draganddrop.DragAndDrop;
-import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.recents.RecentTasks;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.startingsurface.StartingSurface;
import com.android.wm.shell.sysui.ShellInterface;
-import com.android.wm.shell.tasksurfacehelper.TaskSurfaceHelper;
import com.android.wm.shell.transition.ShellTransitions;
import java.util.Optional;
@@ -104,9 +100,6 @@
Optional<Bubbles> getBubbles();
@WMSingleton
- Optional<HideDisplayCutout> getHideDisplayCutout();
-
- @WMSingleton
Optional<TaskViewFactory> getTaskViewFactory();
@WMSingleton
@@ -119,17 +112,8 @@
Optional<DisplayAreaHelper> getDisplayAreaHelper();
@WMSingleton
- Optional<TaskSurfaceHelper> getTaskSurfaceHelper();
-
- @WMSingleton
Optional<RecentTasks> getRecentTasks();
@WMSingleton
- Optional<CompatUI> getCompatUI();
-
- @WMSingleton
- Optional<DragAndDrop> getDragAndDrop();
-
- @WMSingleton
Optional<BackAnimation> getBackAnimation();
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 245ea21..46173b8 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -142,6 +142,9 @@
public static final ResourceBooleanFlag STATUS_BAR_USER_SWITCHER =
new ResourceBooleanFlag(602, R.bool.flag_user_switcher_chip);
+ public static final BooleanFlag STATUS_BAR_LETTERBOX_APPEARANCE =
+ new BooleanFlag(603, false);
+
/***************************************/
// 700 - dialer/calls
public static final BooleanFlag ONGOING_CALL_STATUS_BAR_CHIP =
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index aeff2d4..012d766 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -682,9 +682,22 @@
Drawable artwork;
boolean isArtworkBound;
Icon artworkIcon = data.getArtwork();
+ WallpaperColors wallpaperColors = null;
if (artworkIcon != null) {
- WallpaperColors wallpaperColors = WallpaperColors
- .fromBitmap(artworkIcon.getBitmap());
+ if (artworkIcon.getType() == Icon.TYPE_BITMAP
+ || artworkIcon.getType() == Icon.TYPE_ADAPTIVE_BITMAP) {
+ // Avoids extra processing if this is already a valid bitmap
+ wallpaperColors = WallpaperColors
+ .fromBitmap(artworkIcon.getBitmap());
+ } else {
+ Drawable artworkDrawable = artworkIcon.loadDrawable(mContext);
+ if (artworkDrawable != null) {
+ wallpaperColors = WallpaperColors
+ .fromDrawable(artworkIcon.loadDrawable(mContext));
+ }
+ }
+ }
+ if (wallpaperColors != null) {
mutableColorScheme = new ColorScheme(wallpaperColors, true, Style.CONTENT);
Drawable albumArt = getScaledBackground(artworkIcon, width, height);
GradientDrawable gradient = (GradientDrawable) mContext
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java b/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java
index e1b97a4..20c6c556 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java
@@ -21,6 +21,7 @@
import android.content.Intent;
import android.content.pm.LauncherApps;
import android.os.Bundle;
+import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
@@ -34,6 +35,7 @@
import com.android.internal.logging.UiEventLoggerImpl;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.people.PeopleSpaceUtils;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -43,6 +45,7 @@
import com.android.wm.shell.bubbles.Bubble;
import java.util.Optional;
+import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -58,6 +61,7 @@
private boolean mIsForTesting;
private IStatusBarService mIStatusBarService;
private CommandQueue mCommandQueue;
+ private Executor mBgExecutor;
private Bubble mBubble;
private NotificationEntry mEntryToBubble;
@@ -67,7 +71,8 @@
CommonNotifCollection commonNotifCollection,
Optional<BubblesManager> bubblesManagerOptional,
UserManager userManager,
- CommandQueue commandQueue
+ CommandQueue commandQueue,
+ @Background Executor bgExecutor
) {
super();
mVisibilityProvider = visibilityProvider;
@@ -91,6 +96,7 @@
mCommandQueue.removeCallback(this);
}
});
+ mBgExecutor = bgExecutor;
}
@Override
@@ -172,34 +178,36 @@
return;
}
- try {
- if (mIStatusBarService == null || mCommonNotifCollection == null) {
- if (DEBUG) {
- Log.d(TAG, "Skipping clear notification: null services, key: " + notifKey);
- }
- return;
+ if (mIStatusBarService == null || mCommonNotifCollection == null) {
+ if (DEBUG) {
+ Log.d(TAG, "Skipping clear notification: null services, key: " + notifKey);
}
-
- NotificationEntry entry = mCommonNotifCollection.getEntry(notifKey);
- if (entry == null || entry.getRanking() == null) {
- if (DEBUG) {
- Log.d(TAG, "Skipping clear notification: NotificationEntry or its Ranking"
- + " is null, key: " + notifKey);
- }
- return;
- }
-
- NotificationVisibility notifVisibility = mVisibilityProvider.obtain(entry, true);
- int rank = notifVisibility.rank;
-
- if (DEBUG) Log.d(TAG, "Clearing notification, key: " + notifKey + ", rank: " + rank);
- mIStatusBarService.onNotificationClear(
- packageName, userHandle.getIdentifier(), notifKey,
- NotificationStats.DISMISSAL_OTHER,
- NotificationStats.DISMISS_SENTIMENT_POSITIVE, notifVisibility);
- } catch (Exception e) {
- Log.e(TAG, "Exception cancelling notification:" + e);
+ return;
}
+
+ NotificationEntry entry = mCommonNotifCollection.getEntry(notifKey);
+ if (entry == null || entry.getRanking() == null) {
+ if (DEBUG) {
+ Log.d(TAG, "Skipping clear notification: NotificationEntry or its Ranking"
+ + " is null, key: " + notifKey);
+ }
+ return;
+ }
+
+ NotificationVisibility notifVisibility = mVisibilityProvider.obtain(entry, true);
+ int rank = notifVisibility.rank;
+
+ if (DEBUG) Log.d(TAG, "Clearing notification, key: " + notifKey + ", rank: " + rank);
+ mBgExecutor.execute(() -> {
+ try {
+ mIStatusBarService.onNotificationClear(
+ packageName, userHandle.getIdentifier(), notifKey,
+ NotificationStats.DISMISSAL_OTHER,
+ NotificationStats.DISMISS_SENTIMENT_POSITIVE, notifVisibility);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Exception cancelling notification:" + e);
+ }
+ });
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index 5bb3413..a837cbb 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -29,6 +29,7 @@
import android.media.MediaRecorder;
import android.net.Uri;
import android.os.Bundle;
+import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -40,6 +41,8 @@
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.LongRunning;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.screenrecord.ScreenMediaRecorder.ScreenMediaRecorderListener;
import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
@@ -51,9 +54,10 @@
/**
* A service which records the device screen and optionally microphone input.
*/
-public class RecordingService extends Service implements MediaRecorder.OnInfoListener {
+public class RecordingService extends Service implements ScreenMediaRecorderListener {
public static final int REQUEST_CODE = 2;
+ private static final int USER_ID_NOT_SPECIFIED = -1;
private static final int NOTIFICATION_RECORDING_ID = 4274;
private static final int NOTIFICATION_PROCESSING_ID = 4275;
private static final int NOTIFICATION_VIEW_ID = 4273;
@@ -73,6 +77,7 @@
private final RecordingController mController;
private final KeyguardDismissUtil mKeyguardDismissUtil;
+ private final Handler mMainHandler;
private ScreenRecordingAudioSource mAudioSource;
private boolean mShowTaps;
private boolean mOriginalShowTaps;
@@ -84,10 +89,12 @@
@Inject
public RecordingService(RecordingController controller, @LongRunning Executor executor,
- UiEventLogger uiEventLogger, NotificationManager notificationManager,
+ @Main Handler handler, UiEventLogger uiEventLogger,
+ NotificationManager notificationManager,
UserContextProvider userContextTracker, KeyguardDismissUtil keyguardDismissUtil) {
mController = controller;
mLongExecutor = executor;
+ mMainHandler = handler;
mUiEventLogger = uiEventLogger;
mNotificationManager = notificationManager;
mUserContextTracker = userContextTracker;
@@ -138,6 +145,7 @@
mRecorder = new ScreenMediaRecorder(
mUserContextTracker.getUserContext(),
+ mMainHandler,
currentUserId,
mAudioSource,
this
@@ -166,14 +174,8 @@
}
// Check user ID - we may be getting a stop intent after user switch, in which case
// we want to post the notifications for that user, which is NOT current user
- int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
- if (userId == -1) {
- userId = mUserContextTracker.getUserContext().getUserId();
- }
- Log.d(TAG, "notifying for user " + userId);
- stopRecording(userId);
- mNotificationManager.cancel(NOTIFICATION_RECORDING_ID);
- stopSelf();
+ int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_ID_NOT_SPECIFIED);
+ stopService(userId);
break;
case ACTION_SHARE:
@@ -378,15 +380,39 @@
return builder.build();
}
- private void stopRecording(int userId) {
+ private void stopService() {
+ stopService(USER_ID_NOT_SPECIFIED);
+ }
+
+ private void stopService(int userId) {
+ if (userId == USER_ID_NOT_SPECIFIED) {
+ userId = mUserContextTracker.getUserContext().getUserId();
+ }
+ Log.d(TAG, "notifying for user " + userId);
setTapsVisible(mOriginalShowTaps);
if (getRecorder() != null) {
- getRecorder().end();
- saveRecording(userId);
+ try {
+ getRecorder().end();
+ saveRecording(userId);
+ } catch (RuntimeException exception) {
+ // RuntimeException could happen if the recording stopped immediately after starting
+ // let's release the recorder and delete all temporary files in this case
+ getRecorder().release();
+ showErrorToast(R.string.screenrecord_start_error);
+ Log.e(TAG, "stopRecording called, but there was an error when ending"
+ + "recording");
+ exception.printStackTrace();
+ } catch (Throwable throwable) {
+ // Something unexpected happen, SystemUI will crash but let's delete
+ // the temporary files anyway
+ getRecorder().release();
+ throw new RuntimeException(throwable);
+ }
} else {
Log.e(TAG, "stopRecording called, but recorder was null");
}
updateState(false);
+ stopSelf();
}
private void saveRecording(int userId) {
@@ -446,4 +472,12 @@
Log.d(TAG, "Media recorder info: " + what);
onStartCommand(getStopIntent(this), 0, 0);
}
+
+ @Override
+ public void onStopped() {
+ if (mController.isRecording()) {
+ Log.d(TAG, "Stopping recording because the system requested the stop");
+ stopService();
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
index 2133cf6..d098b4b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
@@ -40,6 +40,7 @@
import android.media.projection.MediaProjection;
import android.media.projection.MediaProjectionManager;
import android.net.Uri;
+import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -51,16 +52,19 @@
import android.view.WindowManager;
import java.io.File;
+import java.io.Closeable;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Date;
+import java.util.List;
/**
* Recording screen and mic/internal audio
*/
-public class ScreenMediaRecorder {
+public class ScreenMediaRecorder extends MediaProjection.Callback {
private static final int TOTAL_NUM_TRACKS = 1;
private static final int VIDEO_FRAME_RATE = 30;
private static final int VIDEO_FRAME_RATE_TO_RESOLUTION_RATIO = 6;
@@ -81,14 +85,16 @@
private ScreenRecordingMuxer mMuxer;
private ScreenInternalAudioRecorder mAudio;
private ScreenRecordingAudioSource mAudioSource;
+ private final Handler mHandler;
private Context mContext;
- MediaRecorder.OnInfoListener mListener;
+ ScreenMediaRecorderListener mListener;
- public ScreenMediaRecorder(Context context,
+ public ScreenMediaRecorder(Context context, Handler handler,
int user, ScreenRecordingAudioSource audioSource,
- MediaRecorder.OnInfoListener listener) {
+ ScreenMediaRecorderListener listener) {
mContext = context;
+ mHandler = handler;
mUser = user;
mListener = listener;
mAudioSource = audioSource;
@@ -105,6 +111,7 @@
IBinder projection = proj.asBinder();
mMediaProjection = new MediaProjection(mContext,
IMediaProjection.Stub.asInterface(projection));
+ mMediaProjection.registerCallback(this, mHandler);
File cacheDir = mContext.getCacheDir();
cacheDir.mkdirs();
@@ -162,10 +169,15 @@
metrics.densityDpi,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
mInputSurface,
- null,
- null);
+ new VirtualDisplay.Callback() {
+ @Override
+ public void onStopped() {
+ onStop();
+ }
+ },
+ mHandler);
- mMediaRecorder.setOnInfoListener(mListener);
+ mMediaRecorder.setOnInfoListener((mr, what, extra) -> mListener.onInfo(mr, what, extra));
if (mAudioSource == INTERNAL ||
mAudioSource == MIC_AND_INTERNAL) {
mTempAudioFile = File.createTempFile("temp", ".aac",
@@ -259,21 +271,34 @@
}
/**
- * End screen recording
+ * End screen recording, throws an exception if stopping recording failed
*/
- void end() {
- mMediaRecorder.stop();
- mMediaRecorder.release();
- mInputSurface.release();
- mVirtualDisplay.release();
- mMediaProjection.stop();
+ void end() throws IOException {
+ Closer closer = new Closer();
+
+ // MediaRecorder might throw RuntimeException if stopped immediately after starting
+ // We should remove the recording in this case as it will be invalid
+ closer.register(mMediaRecorder::stop);
+ closer.register(mMediaRecorder::release);
+ closer.register(mInputSurface::release);
+ closer.register(mVirtualDisplay::release);
+ closer.register(mMediaProjection::stop);
+ closer.register(this::stopInternalAudioRecording);
+
+ closer.close();
+
mMediaRecorder = null;
mMediaProjection = null;
- stopInternalAudioRecording();
Log.d(TAG, "end recording");
}
+ @Override
+ public void onStop() {
+ Log.d(TAG, "The system notified about stopping the projection");
+ mListener.onStopped();
+ }
+
private void stopInternalAudioRecording() {
if (mAudioSource == INTERNAL || mAudioSource == MIC_AND_INTERNAL) {
mAudio.end();
@@ -337,6 +362,18 @@
}
/**
+ * Release the resources without saving the data
+ */
+ protected void release() {
+ if (mTempVideoFile != null) {
+ mTempVideoFile.delete();
+ }
+ if (mTempAudioFile != null) {
+ mTempAudioFile.delete();
+ }
+ }
+
+ /**
* Object representing the recording
*/
public class SavedRecording {
@@ -362,4 +399,66 @@
return mThumbnailBitmap;
}
}
+
+ interface ScreenMediaRecorderListener {
+ /**
+ * Called to indicate an info or a warning during recording.
+ * See {@link MediaRecorder.OnInfoListener} for the full description.
+ */
+ void onInfo(MediaRecorder mr, int what, int extra);
+
+ /**
+ * Called when the recording stopped by the system.
+ * For example, this might happen when doing partial screen sharing of an app
+ * and the app that is being captured is closed.
+ */
+ void onStopped();
+ }
+
+ /**
+ * Allows to register multiple {@link Closeable} objects and close them all by calling
+ * {@link Closer#close}. If there is an exception thrown during closing of one
+ * of the registered closeables it will continue trying closing the rest closeables.
+ * If there are one or more exceptions thrown they will be re-thrown at the end.
+ * In case of multiple exceptions only the first one will be thrown and all the rest
+ * will be printed.
+ */
+ private static class Closer implements Closeable {
+ private final List<Closeable> mCloseables = new ArrayList<>();
+
+ void register(Closeable closeable) {
+ mCloseables.add(closeable);
+ }
+
+ @Override
+ public void close() throws IOException {
+ Throwable throwable = null;
+
+ for (int i = 0; i < mCloseables.size(); i++) {
+ Closeable closeable = mCloseables.get(i);
+
+ try {
+ closeable.close();
+ } catch (Throwable e) {
+ if (throwable == null) {
+ throwable = e;
+ } else {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ if (throwable != null) {
+ if (throwable instanceof IOException) {
+ throw (IOException) throwable;
+ }
+
+ if (throwable instanceof RuntimeException) {
+ throw (RuntimeException) throwable;
+ }
+
+ throw (Error) throwable;
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/transition/ShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/shade/transition/ShadeTransitionController.kt
index 1c4911d..58acfb4 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/transition/ShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/transition/ShadeTransitionController.kt
@@ -7,6 +7,8 @@
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.qs.QS
import com.android.systemui.shade.NotificationPanelViewController
+import com.android.systemui.statusbar.StatusBarState
+import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionChangeEvent
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager
@@ -27,7 +29,8 @@
private val context: Context,
private val splitShadeOverScrollerFactory: SplitShadeOverScroller.Factory,
private val noOpOverScroller: NoOpOverScroller,
- private val scrimShadeTransitionController: ScrimShadeTransitionController
+ private val scrimShadeTransitionController: ScrimShadeTransitionController,
+ private val statusBarStateController: SysuiStatusBarStateController,
) {
lateinit var notificationPanelViewController: NotificationPanelViewController
@@ -43,7 +46,7 @@
}
private val shadeOverScroller: ShadeOverScroller
get() =
- if (inSplitShade && propertiesInitialized()) {
+ if (inSplitShade && isScreenUnlocked() && propertiesInitialized()) {
splitShadeOverScroller
} else {
noOpOverScroller
@@ -90,6 +93,7 @@
"""
ShadeTransitionController:
inSplitShade: $inSplitShade
+ isScreenUnlocked: ${isScreenUnlocked()}
currentPanelState: ${currentPanelState?.panelStateToString()}
lastPanelExpansionChangeEvent: $lastPanelExpansionChangeEvent
qs.isInitialized: ${this::qs.isInitialized}
@@ -97,4 +101,7 @@
nssl.isInitialized: ${this::notificationStackScrollLayoutController.isInitialized}
""".trimIndent())
}
+
+ private fun isScreenUnlocked() =
+ statusBarStateController.currentOrUpcomingState == StatusBarState.SHADE
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index c86bf93..852d5f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -41,6 +41,7 @@
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dumpable;
+import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.statusbar.NotificationLifetimeExtender;
import com.android.systemui.statusbar.NotificationListener;
@@ -73,6 +74,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.Executor;
import dagger.Lazy;
@@ -113,6 +115,7 @@
private final IStatusBarService mStatusBarService;
private final NotifLiveDataStoreImpl mNotifLiveDataStore;
private final DumpManager mDumpManager;
+ private final Executor mBgExecutor;
private final Set<NotificationEntry> mAllNotifications = new ArraySet<>();
private final Set<NotificationEntry> mReadOnlyAllNotifications =
@@ -159,7 +162,8 @@
LeakDetector leakDetector,
IStatusBarService statusBarService,
NotifLiveDataStoreImpl notifLiveDataStore,
- DumpManager dumpManager
+ DumpManager dumpManager,
+ @Background Executor bgExecutor
) {
mLogger = logger;
mGroupManager = groupManager;
@@ -170,6 +174,7 @@
mStatusBarService = statusBarService;
mNotifLiveDataStore = notifLiveDataStore;
mDumpManager = dumpManager;
+ mBgExecutor = bgExecutor;
}
/** Once called, the NEM will start processing notification events from system server. */
@@ -566,17 +571,19 @@
private void sendNotificationRemovalToServer(
StatusBarNotification notification,
DismissedByUserStats dismissedByUserStats) {
- try {
- mStatusBarService.onNotificationClear(
- notification.getPackageName(),
- notification.getUser().getIdentifier(),
- notification.getKey(),
- dismissedByUserStats.dismissalSurface,
- dismissedByUserStats.dismissalSentiment,
- dismissedByUserStats.notificationVisibility);
- } catch (RemoteException ex) {
- // system process is dead if we're here.
- }
+ mBgExecutor.execute(() -> {
+ try {
+ mStatusBarService.onNotificationClear(
+ notification.getPackageName(),
+ notification.getUser().getIdentifier(),
+ notification.getKey(),
+ dismissedByUserStats.dismissalSurface,
+ dismissedByUserStats.dismissalSentiment,
+ dismissedByUserStats.notificationVisibility);
+ } catch (RemoteException ex) {
+ // system process is dead if we're here.
+ }
+ });
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index 2c85fdd..351a4be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -70,6 +70,7 @@
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.Dumpable;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.dump.LogBufferEulogizer;
@@ -112,6 +113,7 @@
import java.util.Objects;
import java.util.Queue;
import java.util.Set;
+import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
@@ -146,6 +148,7 @@
private final NotifPipelineFlags mNotifPipelineFlags;
private final NotifCollectionLogger mLogger;
private final Handler mMainHandler;
+ private final Executor mBgExecutor;
private final LogBufferEulogizer mEulogizer;
private final DumpManager mDumpManager;
@@ -174,6 +177,7 @@
NotifPipelineFlags notifPipelineFlags,
NotifCollectionLogger logger,
@Main Handler mainHandler,
+ @Background Executor bgExecutor,
LogBufferEulogizer logBufferEulogizer,
DumpManager dumpManager) {
mStatusBarService = statusBarService;
@@ -181,6 +185,7 @@
mNotifPipelineFlags = notifPipelineFlags;
mLogger = logger;
mMainHandler = mainHandler;
+ mBgExecutor = bgExecutor;
mEulogizer = logBufferEulogizer;
mDumpManager = dumpManager;
}
@@ -294,18 +299,20 @@
entriesToLocallyDismiss.add(entry);
if (!isCanceled(entry)) {
// send message to system server if this notification hasn't already been cancelled
- try {
- mStatusBarService.onNotificationClear(
- entry.getSbn().getPackageName(),
- entry.getSbn().getUser().getIdentifier(),
- entry.getSbn().getKey(),
- stats.dismissalSurface,
- stats.dismissalSentiment,
- stats.notificationVisibility);
- } catch (RemoteException e) {
- // system process is dead if we're here.
- mLogger.logRemoteExceptionOnNotificationClear(entry, e);
- }
+ mBgExecutor.execute(() -> {
+ try {
+ mStatusBarService.onNotificationClear(
+ entry.getSbn().getPackageName(),
+ entry.getSbn().getUser().getIdentifier(),
+ entry.getSbn().getKey(),
+ stats.dismissalSurface,
+ stats.dismissalSentiment,
+ stats.notificationVisibility);
+ } catch (RemoteException e) {
+ // system process is dead if we're here.
+ mLogger.logRemoteExceptionOnNotificationClear(entry, e);
+ }
+ });
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index 4956a276..bf08fc7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -128,7 +128,8 @@
LeakDetector leakDetector,
IStatusBarService statusBarService,
NotifLiveDataStoreImpl notifLiveDataStore,
- DumpManager dumpManager) {
+ DumpManager dumpManager,
+ @Background Executor bgExecutor) {
return new NotificationEntryManager(
logger,
groupManager,
@@ -138,7 +139,8 @@
leakDetector,
statusBarService,
notifLiveDataStore,
- dumpManager);
+ dumpManager,
+ bgExecutor);
}
/** Provides an instance of {@link NotificationGutsManager} */
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 fff7b6a..2d6d846 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -1709,7 +1709,7 @@
// Wrap the animation controller to dismiss the shade and set
// mIsLaunchingActivityOverLockscreen during the animation.
ActivityLaunchAnimator.Controller delegate = wrapAnimationController(
- animationController, dismissShade);
+ animationController, dismissShade, /* isLaunchForActivity= */ true);
controller = new DelegateLaunchAnimatorController(delegate) {
@Override
public void onIntentStarted(boolean willAnimate) {
@@ -2457,7 +2457,7 @@
true /* isActivityIntent */);
ActivityLaunchAnimator.Controller animController =
animationController != null ? wrapAnimationController(animationController,
- dismissShade) : null;
+ dismissShade, /* isLaunchForActivity= */ true) : null;
// If we animate, we will dismiss the shade only once the animation is done. This is taken
// care of by the StatusBarLaunchAnimationController.
@@ -2535,9 +2535,25 @@
willLaunchResolverActivity, deferred /* deferred */, animate);
}
+ /**
+ * Return a {@link ActivityLaunchAnimator.Controller} wrapping {@code animationController} so
+ * that:
+ * - if it launches in the notification shade window and {@code dismissShade} is true, then
+ * the shade will be instantly dismissed at the end of the animation.
+ * - if it launches in status bar window, it will make the status bar window match the device
+ * size during the animation (that way, the animation won't be clipped by the status bar
+ * size).
+ *
+ * @param animationController the controller that is wrapped and will drive the main animation.
+ * @param dismissShade whether the notification shade will be dismissed at the end of the
+ * animation. This is ignored if {@code animationController} is not
+ * animating in the shade window.
+ * @param isLaunchForActivity whether the launch is for an activity.
+ */
@Nullable
private ActivityLaunchAnimator.Controller wrapAnimationController(
- ActivityLaunchAnimator.Controller animationController, boolean dismissShade) {
+ ActivityLaunchAnimator.Controller animationController, boolean dismissShade,
+ boolean isLaunchForActivity) {
View rootView = animationController.getLaunchContainer().getRootView();
Optional<ActivityLaunchAnimator.Controller> controllerFromStatusBar =
@@ -2551,7 +2567,7 @@
// If the view is not in the status bar, then we are animating a view in the shade.
// We have to make sure that we collapse it when the animation ends or is cancelled.
return new StatusBarLaunchAnimatorController(animationController, this,
- true /* isLaunchForActivity */);
+ isLaunchForActivity);
}
return animationController;
@@ -4083,8 +4099,9 @@
// We wrap animationCallback with a StatusBarLaunchAnimatorController so that the
// shade is collapsed after the animation (or when it is cancelled, aborted, etc).
ActivityLaunchAnimator.Controller controller =
- animationController != null ? new StatusBarLaunchAnimatorController(
- animationController, this, intent.isActivity()) : null;
+ animationController != null ? wrapAnimationController(
+ animationController, /* dismissShade= */ true, intent.isActivity())
+ : null;
mActivityLaunchAnimator.startPendingIntentWithAnimation(
controller, animate, intent.getCreatorPackage(),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 2dc3261..a2140c6ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License
*/
-
package com.android.systemui.statusbar.phone;
import static com.android.systemui.statusbar.phone.HeadsUpAppearanceController.CONTENT_FADE_DELAY;
@@ -31,6 +30,7 @@
import android.util.Property;
import android.view.ContextThemeWrapper;
import android.view.View;
+import android.view.ViewGroup;
import android.view.animation.Interpolator;
import androidx.annotation.VisibleForTesting;
@@ -40,7 +40,6 @@
import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
-import com.android.systemui.statusbar.AlphaOptimizedFrameLayout;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.stack.AnimationFilter;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
@@ -54,7 +53,7 @@
* A container for notification icons. It handles overflowing icons properly and positions them
* correctly on the screen.
*/
-public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
+public class NotificationIconContainer extends ViewGroup {
/**
* A float value indicating how much before the overflow start the icons should transform into
* a dot. A value of 0 means that they are exactly at the end and a value of 1 means it starts
@@ -232,6 +231,31 @@
}
@Override
+ public boolean hasOverlappingRendering() {
+ // Does the same as "AlphaOptimizedFrameLayout".
+ return false;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int childCount = getChildCount();
+ final int maxVisibleIcons = getMaxVisibleIcons(childCount);
+ final int width = MeasureSpec.getSize(widthMeasureSpec);
+ final int childWidthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.UNSPECIFIED);
+ int totalWidth = (int) (getActualPaddingStart() + getActualPaddingEnd());
+ for (int i = 0; i < childCount; i++) {
+ View child = getChildAt(i);
+ measureChild(child, childWidthSpec, heightMeasureSpec);
+ if (i <= maxVisibleIcons) {
+ totalWidth += child.getMeasuredWidth();
+ }
+ }
+ final int measuredWidth = resolveSize(totalWidth, widthMeasureSpec);
+ final int measuredHeight = MeasureSpec.getSize(heightMeasureSpec);
+ setMeasuredDimension(measuredWidth, measuredHeight);
+ }
+
+ @Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
float centerY = getHeight() / 2.0f;
// we layout all our children on the left at the top
@@ -408,8 +432,7 @@
float translationX = getActualPaddingStart();
int firstOverflowIndex = -1;
int childCount = getChildCount();
- int maxVisibleIcons = mOnLockScreen ? MAX_ICONS_ON_AOD :
- mIsStaticLayout ? MAX_STATIC_ICONS : childCount;
+ int maxVisibleIcons = getMaxVisibleIcons(childCount);
float layoutEnd = getLayoutEnd();
mVisualOverflowStart = 0;
mFirstVisibleIconState = null;
@@ -493,6 +516,11 @@
}
}
+ private int getMaxVisibleIcons(int childCount) {
+ return mOnLockScreen ? MAX_ICONS_ON_AOD :
+ mIsStaticLayout ? MAX_STATIC_ICONS : childCount;
+ }
+
private float getLayoutEnd() {
return getActualWidth() - getActualPaddingEnd();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
index 2052ee6..15c6dcf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
@@ -31,7 +31,7 @@
private final float mIconAlphaWhenOpaque;
- private View mLeftSide, mStatusIcons, mBattery;
+ private View mStartSide, mStatusIcons, mBattery;
private Animator mCurrentAnimation;
/**
@@ -41,7 +41,7 @@
super(backgroundView, R.drawable.status_background);
final Resources res = statusBarView.getContext().getResources();
mIconAlphaWhenOpaque = res.getFraction(R.dimen.status_bar_icon_drawing_alpha, 1, 1);
- mLeftSide = statusBarView.findViewById(R.id.status_bar_left_side);
+ mStartSide = statusBarView.findViewById(R.id.status_bar_start_side_except_heads_up);
mStatusIcons = statusBarView.findViewById(R.id.statusIcons);
mBattery = statusBarView.findViewById(R.id.battery);
applyModeBackground(-1, getMode(), false /*animate*/);
@@ -75,7 +75,7 @@
}
private void applyMode(int mode, boolean animate) {
- if (mLeftSide == null) return; // pre-init
+ if (mStartSide == null) return; // pre-init
float newAlpha = getNonBatteryClockAlphaFor(mode);
float newAlphaBC = getBatteryClockAlpha(mode);
if (mCurrentAnimation != null) {
@@ -84,7 +84,7 @@
if (animate) {
AnimatorSet anims = new AnimatorSet();
anims.playTogether(
- animateTransitionTo(mLeftSide, newAlpha),
+ animateTransitionTo(mStartSide, newAlpha),
animateTransitionTo(mStatusIcons, newAlpha),
animateTransitionTo(mBattery, newAlphaBC)
);
@@ -94,7 +94,7 @@
anims.start();
mCurrentAnimation = anims;
} else {
- mLeftSide.setAlpha(newAlpha);
+ mStartSide.setAlpha(newAlpha);
mStatusIcons.setAlpha(newAlpha);
mBattery.setAlpha(newAlphaBC);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
index 9da2ef73..f9c4c8f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
@@ -21,7 +21,6 @@
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
-
import com.android.systemui.R
import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator
import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherController
@@ -32,9 +31,7 @@
import com.android.systemui.util.ViewController
import com.android.systemui.util.kotlin.getOrNull
import com.android.systemui.util.view.ViewUtil
-
import java.util.Optional
-
import javax.inject.Inject
import javax.inject.Named
@@ -58,8 +55,8 @@
override fun onViewAttached() {
if (moveFromCenterAnimationController == null) return
- val statusBarLeftSide: View = mView.findViewById(R.id.status_bar_left_side)
- val systemIconArea: ViewGroup = mView.findViewById(R.id.system_icon_area)
+ val statusBarLeftSide: View = mView.findViewById(R.id.status_bar_start_side_except_heads_up)
+ val systemIconArea: ViewGroup = mView.findViewById(R.id.status_bar_end_side_content)
val viewsToAnimate = arrayOf(
statusBarLeftSide,
@@ -126,11 +123,11 @@
class StatusBarViewsCenterProvider : UnfoldMoveFromCenterAnimator.ViewCenterProvider {
override fun getViewCenter(view: View, outPoint: Point) =
when (view.id) {
- R.id.status_bar_left_side -> {
+ R.id.status_bar_start_side_except_heads_up -> {
// items aligned to the start, return start center point
getViewEdgeCenter(view, outPoint, isStart = true)
}
- R.id.system_icon_area -> {
+ R.id.status_bar_end_side_content -> {
// items aligned to the end, return end center point
getViewEdgeCenter(view, outPoint, isStart = false)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index 0e7da81..39bf92a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -102,7 +102,7 @@
private final KeyguardStateController mKeyguardStateController;
private final NotificationPanelViewController mNotificationPanelViewController;
private final NetworkController mNetworkController;
- private LinearLayout mSystemIconArea;
+ private LinearLayout mEndSideContent;
private View mClockView;
private View mOngoingCallChip;
private View mNotificationIconAreaInner;
@@ -232,16 +232,16 @@
mDarkIconManager.setShouldLog(true);
updateBlockedIcons();
mStatusBarIconController.addIconGroup(mDarkIconManager);
- mSystemIconArea = mStatusBar.findViewById(R.id.system_icon_area);
+ mEndSideContent = mStatusBar.findViewById(R.id.status_bar_end_side_content);
mClockView = mStatusBar.findViewById(R.id.clock);
mOngoingCallChip = mStatusBar.findViewById(R.id.ongoing_call_chip);
- showSystemIconArea(false);
+ showEndSideContent(false);
showClock(false);
initEmergencyCryptkeeperText();
initOperatorName();
initNotificationIconArea();
mSystemEventAnimator =
- new StatusBarSystemEventAnimator(mSystemIconArea, getResources());
+ new StatusBarSystemEventAnimator(mEndSideContent, getResources());
mCarrierConfigTracker.addCallback(mCarrierConfigCallback);
mCarrierConfigTracker.addDefaultDataSubscriptionChangedListener(mDefaultDataListener);
}
@@ -370,10 +370,10 @@
mDisabled2 = state2;
if ((diff1 & DISABLE_SYSTEM_INFO) != 0 || ((diff2 & DISABLE2_SYSTEM_ICONS) != 0)) {
if ((state1 & DISABLE_SYSTEM_INFO) != 0 || ((state2 & DISABLE2_SYSTEM_ICONS) != 0)) {
- hideSystemIconArea(animate);
+ hideEndSideContent(animate);
hideOperatorName(animate);
} else {
- showSystemIconArea(animate);
+ showEndSideContent(animate);
showOperatorName(animate);
}
}
@@ -474,15 +474,15 @@
return mStatusBarHideIconsForBouncerManager.getShouldHideStatusBarIconsForBouncer();
}
- private void hideSystemIconArea(boolean animate) {
- animateHide(mSystemIconArea, animate);
+ private void hideEndSideContent(boolean animate) {
+ animateHide(mEndSideContent, animate);
}
- private void showSystemIconArea(boolean animate) {
+ private void showEndSideContent(boolean animate) {
// Only show the system icon area if we are not currently animating
int state = mAnimationScheduler.getAnimationState();
if (state == IDLE || state == SHOWING_PERSISTENT_DOT) {
- animateShow(mSystemIconArea, animate);
+ animateShow(mEndSideContent, animate);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index e08a9d0..708a8ab 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -34,7 +34,6 @@
import android.app.NotificationManager;
import android.content.Context;
import android.content.pm.UserInfo;
-import android.content.res.Configuration;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index fa2af56..83b0022 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -55,9 +55,6 @@
import com.android.systemui.tracing.ProtoTracer;
import com.android.systemui.tracing.nano.SystemUiTraceProto;
import com.android.wm.shell.ShellCommandHandler;
-import com.android.wm.shell.compatui.CompatUI;
-import com.android.wm.shell.draganddrop.DragAndDrop;
-import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.nano.WmShellTraceProto;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.onehanded.OneHandedEventCallback;
@@ -110,10 +107,7 @@
private final Optional<Pip> mPipOptional;
private final Optional<SplitScreen> mSplitScreenOptional;
private final Optional<OneHanded> mOneHandedOptional;
- private final Optional<HideDisplayCutout> mHideDisplayCutoutOptional;
private final Optional<ShellCommandHandler> mShellCommandHandler;
- private final Optional<CompatUI> mCompatUIOptional;
- private final Optional<DragAndDrop> mDragAndDropOptional;
private final CommandQueue mCommandQueue;
private final ConfigurationController mConfigurationController;
@@ -127,10 +121,7 @@
private final Executor mSysUiMainExecutor;
private boolean mIsSysUiStateValid;
- private KeyguardUpdateMonitorCallback mSplitScreenKeyguardCallback;
- private KeyguardUpdateMonitorCallback mPipKeyguardCallback;
private KeyguardUpdateMonitorCallback mOneHandedKeyguardCallback;
- private KeyguardStateController.Callback mCompatUIKeyguardCallback;
private WakefulnessLifecycle.Observer mWakefulnessObserver;
@Inject
@@ -139,10 +130,7 @@
Optional<Pip> pipOptional,
Optional<SplitScreen> splitScreenOptional,
Optional<OneHanded> oneHandedOptional,
- Optional<HideDisplayCutout> hideDisplayCutoutOptional,
Optional<ShellCommandHandler> shellCommandHandler,
- Optional<CompatUI> sizeCompatUIOptional,
- Optional<DragAndDrop> dragAndDropOptional,
CommandQueue commandQueue,
ConfigurationController configurationController,
KeyguardStateController keyguardStateController,
@@ -164,12 +152,9 @@
mPipOptional = pipOptional;
mSplitScreenOptional = splitScreenOptional;
mOneHandedOptional = oneHandedOptional;
- mHideDisplayCutoutOptional = hideDisplayCutoutOptional;
mWakefulnessLifecycle = wakefulnessLifecycle;
mProtoTracer = protoTracer;
mShellCommandHandler = shellCommandHandler;
- mCompatUIOptional = sizeCompatUIOptional;
- mDragAndDropOptional = dragAndDropOptional;
mUserInfoController = userInfoController;
mSysUiMainExecutor = sysUiMainExecutor;
}
@@ -185,6 +170,22 @@
}
});
+ // Subscribe to keyguard changes
+ mKeyguardStateController.addCallback(new KeyguardStateController.Callback() {
+ @Override
+ public void onKeyguardShowingChanged() {
+ mShell.onKeyguardVisibilityChanged(mKeyguardStateController.isShowing(),
+ mKeyguardStateController.isOccluded(),
+ mKeyguardStateController.isAnimatingBetweenKeyguardAndSurfaceBehind());
+ }
+ });
+ mKeyguardUpdateMonitor.registerCallback(new KeyguardUpdateMonitorCallback() {
+ @Override
+ public void onKeyguardDismissAnimationFinished() {
+ mShell.onKeyguardDismissAnimationFinished();
+ }
+ });
+
// TODO: Consider piping config change and other common calls to a shell component to
// delegate internally
mProtoTracer.add(this);
@@ -192,7 +193,6 @@
mPipOptional.ifPresent(this::initPip);
mSplitScreenOptional.ifPresent(this::initSplitScreen);
mOneHandedOptional.ifPresent(this::initOneHanded);
- mCompatUIOptional.ifPresent(this::initCompatUi);
}
@VisibleForTesting
@@ -204,20 +204,6 @@
}
});
- mPipKeyguardCallback = new KeyguardUpdateMonitorCallback() {
- @Override
- public void onKeyguardVisibilityChanged(boolean showing) {
- pip.onKeyguardVisibilityChanged(showing,
- mKeyguardStateController.isAnimatingBetweenKeyguardAndSurfaceBehind());
- }
-
- @Override
- public void onKeyguardDismissAnimationFinished() {
- pip.onKeyguardDismissAnimationFinished();
- }
- };
- mKeyguardUpdateMonitor.registerCallback(mPipKeyguardCallback);
-
mSysUiState.addCallback(sysUiStateFlag -> {
mIsSysUiStateValid = (sysUiStateFlag & INVALID_SYSUI_STATE_MASK) == 0;
pip.onSystemUiStateChanged(mIsSysUiStateValid, sysUiStateFlag);
@@ -230,14 +216,6 @@
@VisibleForTesting
void initSplitScreen(SplitScreen splitScreen) {
- mSplitScreenKeyguardCallback = new KeyguardUpdateMonitorCallback() {
- @Override
- public void onKeyguardVisibilityChanged(boolean showing) {
- splitScreen.onKeyguardVisibilityChanged(showing);
- }
- };
- mKeyguardUpdateMonitor.registerCallback(mSplitScreenKeyguardCallback);
-
mWakefulnessLifecycle.addObserver(new WakefulnessLifecycle.Observer() {
@Override
public void onFinishedWakingUp() {
@@ -283,14 +261,9 @@
}
});
+ // TODO: Either move into ShellInterface or register a receiver on the Shell side directly
mOneHandedKeyguardCallback = new KeyguardUpdateMonitorCallback() {
@Override
- public void onKeyguardVisibilityChanged(boolean showing) {
- oneHanded.onKeyguardVisibilityChanged(showing);
- oneHanded.stopOneHanded();
- }
-
- @Override
public void onUserSwitchComplete(int userId) {
oneHanded.onUserSwitch(userId);
}
@@ -340,17 +313,6 @@
});
}
- @VisibleForTesting
- void initCompatUi(CompatUI sizeCompatUI) {
- mCompatUIKeyguardCallback = new KeyguardStateController.Callback() {
- @Override
- public void onKeyguardShowingChanged() {
- sizeCompatUI.onKeyguardShowingChanged(mKeyguardStateController.isShowing());
- }
- };
- mKeyguardStateController.addCallback(mCompatUIKeyguardCallback);
- }
-
@Override
public void writeToProto(SystemUiTraceProto proto) {
if (proto.wmShell == null) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
index 3c7ea4f..c31fd82 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
@@ -37,9 +37,14 @@
import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.dump.DumpManager
+import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import java.io.File
+import java.util.Optional
+import java.util.function.Consumer
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
@@ -50,20 +55,20 @@
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers
+import org.mockito.ArgumentMatchers.anyString
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.anyInt
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.inOrder
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
+import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
+import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
-import java.util.Optional
-import java.util.function.Consumer
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -85,6 +90,8 @@
private lateinit var listingController: ControlsListingController
@Mock(stubOnly = true)
private lateinit var userTracker: UserTracker
+ @Mock
+ private lateinit var userFileManager: UserFileManager
@Captor
private lateinit var structureInfoCaptor: ArgumentCaptor<StructureInfo>
@@ -153,6 +160,9 @@
canceller = DidRunRunnable()
`when`(bindingController.bindAndLoad(any(), any())).thenReturn(canceller)
+ `when`(userFileManager.getFile(anyString(), anyInt())).thenReturn(mock(File::class.java))
+ `when`(userFileManager.getSharedPreferences(anyString(), anyInt(), anyInt()))
+ .thenReturn(context.getSharedPreferences("test", Context.MODE_PRIVATE))
controller = ControlsControllerImpl(
wrapper,
@@ -161,6 +171,7 @@
bindingController,
listingController,
broadcastDispatcher,
+ userFileManager,
Optional.of(persistenceWrapper),
mock(DumpManager::class.java),
userTracker
@@ -217,6 +228,7 @@
bindingController,
listingController,
broadcastDispatcher,
+ userFileManager,
Optional.of(persistenceWrapper),
mock(DumpManager::class.java),
userTracker
@@ -911,6 +923,14 @@
assertTrue(controller.getFavoritesForStructure(TEST_COMPONENT_2, TEST_STRUCTURE).isEmpty())
}
+
+ @Test
+ fun testUserStructure() {
+ val userStructure = UserStructure(context, context.user, userFileManager)
+ verify(userFileManager, times(2))
+ .getFile(ControlsFavoritePersistenceWrapper.FILE_NAME, context.user.identifier)
+ assertThat(userStructure.file).isNotNull()
+ }
}
private class DidRunRunnable() : Runnable {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index c13c30b..1785022 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -561,6 +561,19 @@
}
@Test
+ fun bindAlbumView_artUsesResource() {
+ val albumArt = Icon.createWithResource(context, R.drawable.ic_android)
+ val state = mediaData.copy(artwork = albumArt)
+
+ player.attachPlayer(viewHolder)
+ player.bindPlayer(state, PACKAGE)
+ bgExecutor.runAllReady()
+ mainExecutor.runAllReady()
+
+ verify(albumView).setImageDrawable(any(Drawable::class.java))
+ }
+
+ @Test
fun bindAlbumView_setAfterExecutors() {
val bmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bmp)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/LaunchConversationActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/widget/LaunchConversationActivityTest.java
index 99f21ad..c8ebd12 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/widget/LaunchConversationActivityTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/widget/LaunchConversationActivityTest.java
@@ -48,6 +48,8 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.wmshell.BubblesManager;
import com.android.wm.shell.bubbles.Bubble;
@@ -106,6 +108,9 @@
private Intent mIntent;
+ private FakeSystemClock mFakeSystemClock = new FakeSystemClock();
+ private FakeExecutor mBgExecutor = new FakeExecutor(mFakeSystemClock);
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -114,7 +119,8 @@
mNotifCollection,
Optional.of(mBubblesManager),
mUserManager,
- mCommandQueue
+ mCommandQueue,
+ mBgExecutor
);
verify(mCommandQueue, times(1)).addCallback(mCallbacksCaptor.capture());
@@ -193,6 +199,7 @@
// Ensure callback removed
verify(mCommandQueue).removeCallback(any());
// Clear the notification for bubbles.
+ FakeExecutor.exhaustExecutors(mBgExecutor);
verify(mIStatusBarService, times(1)).onNotificationClear(any(),
anyInt(), any(), anyInt(), anyInt(), mNotificationVisibilityCaptor.capture());
// Do not select the bubble.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
index 91cafea..b05d9a3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
@@ -16,18 +16,21 @@
package com.android.systemui.screenrecord;
+import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.Intent;
+import android.os.Handler;
import android.os.RemoteException;
import android.testing.AndroidTestingRunner;
@@ -66,6 +69,8 @@
@Mock
private Executor mExecutor;
@Mock
+ private Handler mHandler;
+ @Mock
private UserContextProvider mUserContextTracker;
private KeyguardDismissUtil mKeyguardDismissUtil = new KeyguardDismissUtil() {
public void executeWhenUnlocked(ActivityStarter.OnDismissAction action,
@@ -79,8 +84,8 @@
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mRecordingService = Mockito.spy(new RecordingService(mController, mExecutor, mUiEventLogger,
- mNotificationManager, mUserContextTracker, mKeyguardDismissUtil));
+ mRecordingService = Mockito.spy(new RecordingService(mController, mExecutor, mHandler,
+ mUiEventLogger, mNotificationManager, mUserContextTracker, mKeyguardDismissUtil));
// Return actual context info
doReturn(mContext).when(mRecordingService).getApplicationContext();
@@ -143,4 +148,54 @@
// Then the state is set to not recording
verify(mController).updateState(false);
}
+
+ @Test
+ public void testOnSystemRequestedStop_recordingInProgress_endsRecording() throws IOException {
+ doReturn(true).when(mController).isRecording();
+
+ mRecordingService.onStopped();
+
+ verify(mScreenMediaRecorder).end();
+ }
+
+ @Test
+ public void testOnSystemRequestedStop_recordingInProgress_updatesState() {
+ doReturn(true).when(mController).isRecording();
+
+ mRecordingService.onStopped();
+
+ verify(mController).updateState(false);
+ }
+
+ @Test
+ public void testOnSystemRequestedStop_recordingIsNotInProgress_doesNotEndRecording()
+ throws IOException {
+ doReturn(false).when(mController).isRecording();
+
+ mRecordingService.onStopped();
+
+ verify(mScreenMediaRecorder, never()).end();
+ }
+
+ @Test
+ public void testOnSystemRequestedStop_recorderEndThrowsRuntimeException_releasesRecording()
+ throws IOException {
+ doReturn(true).when(mController).isRecording();
+ doThrow(new RuntimeException()).when(mScreenMediaRecorder).end();
+
+ mRecordingService.onStopped();
+
+ verify(mScreenMediaRecorder).release();
+ }
+
+ @Test
+ public void testOnSystemRequestedStop_recorderEndThrowsOOMError_releasesRecording()
+ throws IOException {
+ doReturn(true).when(mController).isRecording();
+ doThrow(new OutOfMemoryError()).when(mScreenMediaRecorder).end();
+
+ assertThrows(Throwable.class, () -> mRecordingService.onStopped());
+
+ verify(mScreenMediaRecorder).release();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ShadeTransitionControllerTest.kt
index d6faaee..b6f8326 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ShadeTransitionControllerTest.kt
@@ -7,6 +7,8 @@
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.qs.QS
import com.android.systemui.shade.NotificationPanelViewController
+import com.android.systemui.statusbar.StatusBarState
+import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionChangeEvent
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager
@@ -19,6 +21,7 @@
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyZeroInteractions
+import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
@RunWith(AndroidTestingRunner::class)
@@ -32,6 +35,7 @@
@Mock private lateinit var splitShadeOverScroller: SplitShadeOverScroller
@Mock private lateinit var scrimShadeTransitionController: ScrimShadeTransitionController
@Mock private lateinit var dumpManager: DumpManager
+ @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController
private lateinit var controller: ShadeTransitionController
@@ -50,7 +54,9 @@
context,
splitShadeOverScrollerFactory = { _, _ -> splitShadeOverScroller },
noOpOverScroller,
- scrimShadeTransitionController)
+ scrimShadeTransitionController,
+ statusBarStateController,
+ )
// Resetting as they are notified upon initialization.
reset(noOpOverScroller, splitShadeOverScroller)
@@ -80,6 +86,45 @@
}
@Test
+ fun onPanelStateChanged_inSplitShade_onKeyguard_forwardsToNoOpOverScroller() {
+ initLateProperties()
+ enableSplitShade()
+ setOnKeyguard()
+
+ startPanelExpansion()
+
+ verify(noOpOverScroller).onPanelStateChanged(STATE_OPENING)
+ verify(noOpOverScroller).onDragDownAmountChanged(DEFAULT_DRAG_DOWN_AMOUNT)
+ verifyZeroInteractions(splitShadeOverScroller)
+ }
+
+ @Test
+ fun onPanelStateChanged_inSplitShade_onLockedShade_forwardsToNoOpOverScroller() {
+ initLateProperties()
+ enableSplitShade()
+ setOnLockedShade()
+
+ startPanelExpansion()
+
+ verify(noOpOverScroller).onPanelStateChanged(STATE_OPENING)
+ verify(noOpOverScroller).onDragDownAmountChanged(DEFAULT_DRAG_DOWN_AMOUNT)
+ verifyZeroInteractions(splitShadeOverScroller)
+ }
+
+ @Test
+ fun onPanelExpansionChanged_inSplitShade_onUnlockedShade_forwardsToSplitShadeOverScroller() {
+ initLateProperties()
+ enableSplitShade()
+ setOnUnlockedShade()
+
+ startPanelExpansion()
+
+ verify(splitShadeOverScroller).onPanelStateChanged(STATE_OPENING)
+ verify(splitShadeOverScroller).onDragDownAmountChanged(DEFAULT_DRAG_DOWN_AMOUNT)
+ verifyZeroInteractions(noOpOverScroller)
+ }
+
+ @Test
fun onPanelStateChanged_notInSplitShade_forwardsToNoOpOverScroller() {
initLateProperties()
disableSplitShade()
@@ -129,6 +174,23 @@
)
}
+ private fun setOnKeyguard() {
+ setShadeState(StatusBarState.KEYGUARD)
+ }
+
+ private fun setOnLockedShade() {
+ setShadeState(StatusBarState.SHADE_LOCKED)
+ }
+
+ private fun setOnUnlockedShade() {
+ setShadeState(StatusBarState.SHADE)
+ }
+
+ private fun setShadeState(state: Int) {
+ whenever(statusBarStateController.state).thenReturn(state)
+ whenever(statusBarStateController.currentOrUpcomingState).thenReturn(state)
+ }
+
companion object {
private const val DEFAULT_DRAG_DOWN_AMOUNT = 123f
private val DEFAULT_EXPANSION_EVENT =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
new file mode 100644
index 0000000..aaa2357
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.shared.clocks
+
+import org.mockito.Mockito.`when` as whenever
+import android.content.Context
+import android.content.ContentResolver
+import android.graphics.drawable.Drawable
+import android.os.Handler
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.PluginListener
+import com.android.systemui.shared.plugins.PluginManager
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.eq
+import junit.framework.Assert.assertEquals
+import junit.framework.Assert.fail
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class ClockRegistryTest : SysuiTestCase() {
+
+ @JvmField @Rule val mockito = MockitoJUnit.rule()
+ @Mock private lateinit var mockContext: Context
+ @Mock private lateinit var mockPluginManager: PluginManager
+ @Mock private lateinit var mockClock: Clock
+ @Mock private lateinit var mockThumbnail: Drawable
+ @Mock private lateinit var mockHandler: Handler
+ @Mock private lateinit var mockContentResolver: ContentResolver
+ private lateinit var pluginListener: PluginListener<ClockProviderPlugin>
+ private lateinit var registry: ClockRegistry
+
+ private var settingValue: String = ""
+
+ companion object {
+ private fun failFactory(): Clock {
+ fail("Unexpected call to createClock")
+ return null!!
+ }
+
+ private fun failThumbnail(): Drawable? {
+ fail("Unexpected call to getThumbnail")
+ return null
+ }
+ }
+
+ private class FakeClockPlugin : ClockProviderPlugin {
+ private val metadata = mutableListOf<ClockMetadata>()
+ private val createCallbacks = mutableMapOf<ClockId, () -> Clock>()
+ private val thumbnailCallbacks = mutableMapOf<ClockId, () -> Drawable?>()
+
+ override fun getClocks() = metadata
+ override fun createClock(id: ClockId): Clock = createCallbacks[id]!!()
+ override fun getClockThumbnail(id: ClockId): Drawable? = thumbnailCallbacks[id]!!()
+
+ fun addClock(
+ id: ClockId,
+ name: String,
+ create: () -> Clock = ::failFactory,
+ getThumbnail: () -> Drawable? = ::failThumbnail
+ ) {
+ metadata.add(ClockMetadata(id, name))
+ createCallbacks[id] = create
+ thumbnailCallbacks[id] = getThumbnail
+ }
+ }
+
+ @Before
+ fun setUp() {
+ whenever(mockContext.contentResolver).thenReturn(mockContentResolver)
+
+ val captor = argumentCaptor<PluginListener<ClockProviderPlugin>>()
+ registry = object : ClockRegistry(mockContext, mockPluginManager, mockHandler) {
+ override var currentClockId: ClockId
+ get() = settingValue
+ set(value) { settingValue = value }
+ }
+ verify(mockPluginManager).addPluginListener(captor.capture(),
+ eq(ClockProviderPlugin::class.java))
+ pluginListener = captor.value
+ }
+
+ @Test
+ fun pluginRegistration_CorrectState() {
+ val plugin1 = FakeClockPlugin()
+ plugin1.addClock("clock_1", "clock 1")
+ plugin1.addClock("clock_2", "clock 2")
+
+ val plugin2 = FakeClockPlugin()
+ plugin2.addClock("clock_3", "clock 3")
+ plugin2.addClock("clock_4", "clock 4")
+
+ pluginListener.onPluginConnected(plugin1, mockContext)
+ pluginListener.onPluginConnected(plugin2, mockContext)
+ val list = registry.getClocks()
+ assertEquals(list, listOf(
+ ClockMetadata("clock_1", "clock 1"),
+ ClockMetadata("clock_2", "clock 2"),
+ ClockMetadata("clock_3", "clock 3"),
+ ClockMetadata("clock_4", "clock 4")
+ ))
+ }
+
+ @Test
+ fun clockIdConflict_ErrorWithoutCrash() {
+ val plugin1 = FakeClockPlugin()
+ plugin1.addClock("clock_1", "clock 1", { mockClock }, { mockThumbnail })
+ plugin1.addClock("clock_2", "clock 2", { mockClock }, { mockThumbnail })
+
+ val plugin2 = FakeClockPlugin()
+ plugin2.addClock("clock_1", "clock 1")
+ plugin2.addClock("clock_2", "clock 2")
+
+ pluginListener.onPluginConnected(plugin1, mockContext)
+ pluginListener.onPluginConnected(plugin2, mockContext)
+ val list = registry.getClocks()
+ assertEquals(list, listOf(
+ ClockMetadata("clock_1", "clock 1"),
+ ClockMetadata("clock_2", "clock 2")
+ ))
+
+ assertEquals(registry.createExampleClock("clock_1"), mockClock)
+ assertEquals(registry.createExampleClock("clock_2"), mockClock)
+ assertEquals(registry.getClockThumbnail("clock_1"), mockThumbnail)
+ assertEquals(registry.getClockThumbnail("clock_2"), mockThumbnail)
+ }
+
+ @Test
+ fun createCurrentClock_pluginConnected() {
+ val plugin1 = FakeClockPlugin()
+ plugin1.addClock("clock_1", "clock 1")
+ plugin1.addClock("clock_2", "clock 2")
+
+ settingValue = "clock_3"
+ val plugin2 = FakeClockPlugin()
+ plugin2.addClock("clock_3", "clock 3", { mockClock })
+ plugin2.addClock("clock_4", "clock 4")
+
+ pluginListener.onPluginConnected(plugin1, mockContext)
+ pluginListener.onPluginConnected(plugin2, mockContext)
+
+ val clock = registry.createCurrentClock()
+ assertEquals(clock, mockClock)
+ }
+
+ @Test
+ fun createDefaultClock_pluginDisconnected() {
+ val plugin1 = FakeClockPlugin()
+ plugin1.addClock(DEFAULT_CLOCK_ID, "default", { mockClock })
+ plugin1.addClock("clock_2", "clock 2")
+
+ settingValue = "clock_3"
+ val plugin2 = FakeClockPlugin()
+ plugin2.addClock("clock_3", "clock 3")
+ plugin2.addClock("clock_4", "clock 4")
+
+ pluginListener.onPluginConnected(plugin1, mockContext)
+ pluginListener.onPluginConnected(plugin2, mockContext)
+ pluginListener.onPluginDisconnected(plugin2)
+
+ val clock = registry.createCurrentClock()
+ assertEquals(clock, mockClock)
+ }
+
+ @Test
+ fun pluginRemoved_clockChanged() {
+ val plugin1 = FakeClockPlugin()
+ plugin1.addClock("clock_1", "clock 1")
+ plugin1.addClock("clock_2", "clock 2")
+
+ settingValue = "clock_3"
+ val plugin2 = FakeClockPlugin()
+ plugin2.addClock("clock_3", "clock 3", { mockClock })
+ plugin2.addClock("clock_4", "clock 4")
+
+ pluginListener.onPluginConnected(plugin1, mockContext)
+ pluginListener.onPluginConnected(plugin2, mockContext)
+
+ var changeCallCount = 0
+ registry.registerClockChangeListener({ changeCallCount++ })
+
+ pluginListener.onPluginDisconnected(plugin1)
+ assertEquals(0, changeCallCount)
+
+ pluginListener.onPluginDisconnected(plugin2)
+ assertEquals(1, changeCallCount)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index 16b0376..aeef6b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -19,6 +19,8 @@
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
import static android.service.notification.NotificationListenerService.REASON_CANCEL;
+import static android.service.notification.NotificationStats.DISMISSAL_SHADE;
+import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
import static com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON;
@@ -41,6 +43,7 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
@@ -50,6 +53,7 @@
import android.content.Intent;
import android.graphics.drawable.Icon;
import android.os.Handler;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.NotificationListenerService.RankingMap;
@@ -91,7 +95,9 @@
import com.android.systemui.statusbar.notification.row.RowInflaterTask;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.leak.LeakDetector;
+import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
import org.junit.Test;
@@ -138,9 +144,14 @@
@Mock private NotificationMediaManager mNotificationMediaManager;
@Mock private NotificationRowBinder mNotificationRowBinder;
@Mock private NotificationListener mNotificationListener;
+ @Mock private IStatusBarService mStatusBarService;
+
+ private FakeSystemClock mFakeSystemClock = new FakeSystemClock();
+ private FakeExecutor mBgExecutor = new FakeExecutor(mFakeSystemClock);
private int mId;
private NotificationEntry mEntry;
+ private DismissedByUserStats mStats;
private StatusBarNotification mSbn;
private NotificationEntryManager mEntryManager;
@@ -191,6 +202,7 @@
Handler.createAsync(TestableLooper.get(this).getLooper()));
mEntry = createNotification();
+ mStats = defaultStats(mEntry);
mSbn = mEntry.getSbn();
when(mNotifPipelineFlags.isNewPipelineEnabled()).thenReturn(false);
@@ -201,9 +213,10 @@
() -> mNotificationRowBinder,
() -> mRemoteInputManager,
mLeakDetector,
- mock(IStatusBarService.class),
+ mStatusBarService,
NotifLiveDataStoreMocksKt.createNotifLiveDataStoreImplMock(),
- mock(DumpManager.class)
+ mock(DumpManager.class),
+ mBgExecutor
);
mEntryManager.initialize(
mNotificationListener,
@@ -316,6 +329,31 @@
}
@Test
+ public void testPerformRemoveNotification_sendRemovalToServer() throws RemoteException {
+ // GIVEN an entry manager with a notification
+ mEntryManager.addActiveNotificationForTest(mEntry);
+
+ // GIVEN interceptor that doesn't intercept
+ when(mRemoveInterceptor.onNotificationRemoveRequested(
+ eq(mEntry.getKey()), argThat(matchEntryOnKey()), anyInt()))
+ .thenReturn(false);
+
+ // WHEN the notification entry is removed
+ mEntryManager.performRemoveNotification(mSbn, mStats, REASON_CANCEL);
+
+ // THEN notification removal is sent to the server
+ FakeExecutor.exhaustExecutors(mBgExecutor);
+ verify(mStatusBarService).onNotificationClear(
+ mSbn.getPackageName(),
+ mSbn.getUser().getIdentifier(),
+ mSbn.getKey(),
+ mStats.dismissalSurface,
+ mStats.dismissalSentiment,
+ mStats.notificationVisibility);
+ verifyNoMoreInteractions(mStatusBarService);
+ }
+
+ @Test
public void testRemoveNotification_onEntryRemoveNotFiredIfEntryDoesntExist() {
mEntryManager.removeNotification("not_a_real_key", mRankingMap, UNDEFINED_DISMISS_REASON);
@@ -573,23 +611,6 @@
any(NotificationVisibility.class), anyBoolean(), eq(UNDEFINED_DISMISS_REASON));
}
- private NotificationEntry createNotification() {
- Notification.Builder n = new Notification.Builder(mContext, "id")
- .setSmallIcon(R.drawable.ic_person)
- .setContentTitle("Title")
- .setContentText("Text");
-
- return new NotificationEntryBuilder()
- .setPkg(TEST_PACKAGE_NAME)
- .setOpPkg(TEST_PACKAGE_NAME)
- .setUid(TEST_UID)
- .setId(mId++)
- .setNotification(n.build())
- .setChannel(new NotificationChannel("id", "", IMPORTANCE_DEFAULT))
- .setUser(new UserHandle(ActivityManager.getCurrentUser()))
- .build();
- }
-
/* Tests annexed from NotificationDataTest go here */
@Test
@@ -713,4 +734,28 @@
return mManagedNotifs.contains(notificationKey);
}
}
+
+ private NotificationEntry createNotification() {
+ Notification.Builder n = new Notification.Builder(mContext, "id")
+ .setSmallIcon(R.drawable.ic_person)
+ .setContentTitle("Title")
+ .setContentText("Text");
+
+ return new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_NAME)
+ .setOpPkg(TEST_PACKAGE_NAME)
+ .setUid(TEST_UID)
+ .setId(mId++)
+ .setNotification(n.build())
+ .setChannel(new NotificationChannel("id", "", IMPORTANCE_DEFAULT))
+ .setUser(new UserHandle(ActivityManager.getCurrentUser()))
+ .build();
+ }
+
+ private static DismissedByUserStats defaultStats(NotificationEntry entry) {
+ return new DismissedByUserStats(
+ DISMISSAL_SHADE,
+ DISMISS_SENTIMENT_NEUTRAL,
+ NotificationVisibility.obtain(entry.getKey(), 7, 2, true));
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
index ef763d9..4df99be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
@@ -92,6 +92,7 @@
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionLogger;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
+import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
@@ -146,6 +147,7 @@
private NoManSimulator mNoMan;
private FakeSystemClock mClock = new FakeSystemClock();
+ private FakeExecutor mBgExecutor = new FakeExecutor(mClock);
@Before
public void setUp() {
@@ -162,6 +164,7 @@
mNotifPipelineFlags,
mLogger,
mMainHandler,
+ mBgExecutor,
mEulogizer,
mock(DumpManager.class));
mCollection.attach(mGroupCoalescer);
@@ -461,6 +464,8 @@
DismissedByUserStats stats = defaultStats(entry2);
mCollection.dismissNotification(entry2, defaultStats(entry2));
+ FakeExecutor.exhaustExecutors(mBgExecutor);
+
// THEN we send the dismissal to system server
verify(mStatusBarService).onNotificationClear(
notif2.sbn.getPackageName(),
@@ -674,6 +679,8 @@
mInterceptor1.onEndInterceptionCallback.onEndDismissInterception(mInterceptor1, entry,
stats);
+ FakeExecutor.exhaustExecutors(mBgExecutor);
+
// THEN we send the dismissal to system server
verify(mStatusBarService).onNotificationClear(
eq(notif.sbn.getPackageName()),
@@ -1211,6 +1218,7 @@
new Pair<>(entry2, defaultStats(entry2))));
// THEN we send the dismissals to system server
+ FakeExecutor.exhaustExecutors(mBgExecutor);
verify(mStatusBarService).onNotificationClear(
notif1.sbn.getPackageName(),
notif1.sbn.getUser().getIdentifier(),
@@ -1577,6 +1585,7 @@
// WHEN finally dismissing
onDismiss.run();
+ FakeExecutor.exhaustExecutors(mBgExecutor);
verify(mStatusBarService).onNotificationClear(any(), anyInt(), eq(notifEvent.key),
anyInt(), anyInt(), any());
verifyNoMoreInteractions(mStatusBarService);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
index 251ac7d..bf7549a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
@@ -194,7 +194,8 @@
mLeakDetector,
mock(IStatusBarService.class),
NotifLiveDataStoreMocksKt.createNotifLiveDataStoreImplMock(),
- mock(DumpManager.class)
+ mock(DumpManager.class),
+ mBgExecutor
);
mEntryManager.initialize(
mNotificationListener,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index 3f14494..681e998 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -124,7 +124,7 @@
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
- assertEquals(View.VISIBLE, getSystemIconAreaView().getVisibility());
+ assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
assertEquals(View.VISIBLE, getClockView().getVisibility());
}
@@ -134,11 +134,11 @@
fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_SYSTEM_INFO, 0, false);
- assertEquals(View.INVISIBLE, getSystemIconAreaView().getVisibility());
+ assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
- assertEquals(View.VISIBLE, getSystemIconAreaView().getVisibility());
+ assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
}
@Test
@@ -234,7 +234,7 @@
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
- assertEquals(View.VISIBLE, getSystemIconAreaView().getVisibility());
+ assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
assertEquals(View.VISIBLE, getClockView().getVisibility());
}
@@ -246,7 +246,7 @@
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
- assertEquals(View.VISIBLE, getSystemIconAreaView().getVisibility());
+ assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
assertEquals(View.VISIBLE, getClockView().getVisibility());
}
@@ -257,12 +257,12 @@
when(mNotificationPanelViewController.hasCustomClock()).thenReturn(true);
// Make sure they start out as visible
- assertEquals(View.VISIBLE, getSystemIconAreaView().getVisibility());
+ assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
assertEquals(View.VISIBLE, getClockView().getVisibility());
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
- assertEquals(View.INVISIBLE, getSystemIconAreaView().getVisibility());
+ assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
assertEquals(View.GONE, getClockView().getVisibility());
}
@@ -273,14 +273,14 @@
when(mNotificationPanelViewController.hasCustomClock()).thenReturn(true);
// Make sure they start out as visible
- assertEquals(View.VISIBLE, getSystemIconAreaView().getVisibility());
+ assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
assertEquals(View.VISIBLE, getClockView().getVisibility());
fragment.onDozingChanged(true);
// When this callback is triggered, we want to make sure the clock and system info
// visibilities are recalculated. Since dozing=true, they shouldn't be visible.
- assertEquals(View.INVISIBLE, getSystemIconAreaView().getVisibility());
+ assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
assertEquals(View.GONE, getClockView().getVisibility());
}
@@ -419,7 +419,7 @@
return mFragment.getView().findViewById(R.id.clock);
}
- private View getSystemIconAreaView() {
- return mFragment.getView().findViewById(R.id.system_icon_area);
+ private View getEndSideContentView() {
+ return mFragment.getView().findViewById(R.id.status_bar_end_side_content);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
index 2b37b9e..72ade26 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
@@ -24,12 +24,10 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.model.SysUiState;
-import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -37,9 +35,6 @@
import com.android.systemui.tracing.ProtoTracer;
import com.android.wm.shell.ShellCommandHandler;
import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.compatui.CompatUI;
-import com.android.wm.shell.draganddrop.DragAndDrop;
-import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.onehanded.OneHandedEventCallback;
import com.android.wm.shell.onehanded.OneHandedTransitionCallback;
@@ -71,31 +66,25 @@
@Mock ConfigurationController mConfigurationController;
@Mock KeyguardStateController mKeyguardStateController;
@Mock KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- @Mock NavigationModeController mNavigationModeController;
@Mock ScreenLifecycle mScreenLifecycle;
@Mock SysUiState mSysUiState;
@Mock Pip mPip;
@Mock SplitScreen mSplitScreen;
@Mock OneHanded mOneHanded;
- @Mock HideDisplayCutout mHideDisplayCutout;
@Mock WakefulnessLifecycle mWakefulnessLifecycle;
@Mock ProtoTracer mProtoTracer;
@Mock ShellCommandHandler mShellCommandHandler;
- @Mock CompatUI mCompatUI;
@Mock UserInfoController mUserInfoController;
@Mock ShellExecutor mSysUiMainExecutor;
- @Mock DragAndDrop mDragAndDrop;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mWMShell = new WMShell(mContext, mShellInterface, Optional.of(mPip),
- Optional.of(mSplitScreen), Optional.of(mOneHanded), Optional.of(mHideDisplayCutout),
- Optional.of(mShellCommandHandler), Optional.of(mCompatUI),
- Optional.of(mDragAndDrop),
- mCommandQueue, mConfigurationController, mKeyguardStateController,
- mKeyguardUpdateMonitor, mScreenLifecycle, mSysUiState,
+ Optional.of(mSplitScreen), Optional.of(mOneHanded),
+ Optional.of(mShellCommandHandler), mCommandQueue, mConfigurationController,
+ mKeyguardStateController, mKeyguardUpdateMonitor, mScreenLifecycle, mSysUiState,
mProtoTracer, mWakefulnessLifecycle, mUserInfoController, mSysUiMainExecutor);
}
@@ -107,27 +96,12 @@
}
@Test
- public void initSplitScreen_registersCallbacks() {
- mWMShell.initSplitScreen(mSplitScreen);
-
- verify(mKeyguardUpdateMonitor).registerCallback(any(KeyguardUpdateMonitorCallback.class));
- }
-
- @Test
public void initOneHanded_registersCallbacks() {
mWMShell.initOneHanded(mOneHanded);
- verify(mKeyguardUpdateMonitor).registerCallback(any(KeyguardUpdateMonitorCallback.class));
verify(mCommandQueue).addCallback(any(CommandQueue.Callbacks.class));
verify(mScreenLifecycle).addObserver(any(ScreenLifecycle.Observer.class));
verify(mOneHanded).registerTransitionCallback(any(OneHandedTransitionCallback.class));
verify(mOneHanded).registerEventCallback(any(OneHandedEventCallback.class));
}
-
- @Test
- public void initCompatUI_registersCallbacks() {
- mWMShell.initCompatUi(mCompatUI);
-
- verify(mKeyguardStateController).addCallback(any(KeyguardStateController.Callback.class));
- }
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 0040ea9..90a47a4 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -10373,6 +10373,11 @@
@Override
public void setAccessibilityServiceUids(IntArray uids) {
+ // TODO(b/233287010): Fix voice interaction and a11y concurrency in audio policy service
+ if (isPlatformAutomotive()) {
+ return;
+ }
+
synchronized (mAccessibilityServiceUidsLock) {
if (uids.size() == 0) {
mAccessibilityServiceUids = null;
diff --git a/services/core/java/com/android/server/biometrics/log/BiometricLogger.java b/services/core/java/com/android/server/biometrics/log/BiometricLogger.java
index ad24cf0..262be08 100644
--- a/services/core/java/com/android/server/biometrics/log/BiometricLogger.java
+++ b/services/core/java/com/android/server/biometrics/log/BiometricLogger.java
@@ -28,8 +28,10 @@
import android.hardware.biometrics.common.OperationContext;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
+import android.util.Log;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.biometrics.Utils;
@@ -41,6 +43,10 @@
public static final String TAG = "BiometricLogger";
public static final boolean DEBUG = false;
+ private static final Object sLock = new Object();
+
+ @GuardedBy("sLock")
+ private static int sAlsCounter;
private final int mStatsModality;
private final int mStatsAction;
@@ -345,13 +351,33 @@
if (!mLightSensorEnabled) {
mLightSensorEnabled = true;
mLastAmbientLux = 0;
- mSensorManager.registerListener(mLightSensorListener, lightSensor,
- SensorManager.SENSOR_DELAY_NORMAL);
+ int localAlsCounter;
+ synchronized (sLock) {
+ localAlsCounter = sAlsCounter++;
+ }
+
+ if (localAlsCounter == 0) {
+ mSensorManager.registerListener(mLightSensorListener, lightSensor,
+ SensorManager.SENSOR_DELAY_NORMAL);
+ } else {
+ Slog.e(TAG, "Ignoring request to subscribe to ALSProbe due to non-zero ALS"
+ + " counter: " + localAlsCounter);
+ Slog.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
}
} else {
mLightSensorEnabled = false;
mLastAmbientLux = 0;
mSensorManager.unregisterListener(mLightSensorListener);
+ int localAlsCounter;
+ synchronized (sLock) {
+ localAlsCounter = --sAlsCounter;
+ }
+ if (localAlsCounter != 0) {
+ Slog.e(TAG, "Non-zero ALS counter after unsubscribing from ALSProbe: "
+ + localAlsCounter);
+ Slog.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
}
}
}
diff --git a/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java b/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java
index e222c64..d238dae 100644
--- a/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java
+++ b/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java
@@ -27,8 +27,6 @@
import android.view.SurfaceControl;
import android.view.WindowManager;
-import com.android.server.policy.WindowManagerPolicy;
-
/**
* An internal implementation of an {@link InputMonitor} that uses a spy window.
*
@@ -69,9 +67,7 @@
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
t.setInputWindowInfo(mInputSurface, mWindowHandle);
- // Gesture monitor should be above handwriting event surface, hence setting it to
- // WindowManagerPolicy.INPUT_DISPLAY_OVERLAY_LAYER + 1
- t.setLayer(mInputSurface, WindowManagerPolicy.INPUT_DISPLAY_OVERLAY_LAYER + 1);
+ t.setLayer(mInputSurface, Integer.MAX_VALUE);
t.setPosition(mInputSurface, 0, 0);
t.setCrop(mInputSurface, null /* crop to parent surface */);
t.show(mInputSurface);
diff --git a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
index 5438faa..8180e66 100644
--- a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
+++ b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
@@ -27,8 +27,6 @@
import android.view.SurfaceControl;
import android.view.WindowManager;
-import com.android.server.policy.WindowManagerPolicy;
-
final class HandwritingEventReceiverSurface {
public static final String TAG = HandwritingEventReceiverSurface.class.getSimpleName();
@@ -38,8 +36,7 @@
// is above gesture monitors, then edge-back and swipe-up gestures won't work when this surface
// is intercepting.
// TODO(b/217538817): Specify the ordering in WM by usage.
- private static final int HANDWRITING_SURFACE_LAYER =
- WindowManagerPolicy.INPUT_DISPLAY_OVERLAY_LAYER;
+ private static final int HANDWRITING_SURFACE_LAYER = Integer.MAX_VALUE - 1;
private final InputWindowHandle mWindowHandle;
private final InputChannel mClientChannel;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 9486a45..e589080 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2459,11 +2459,11 @@
SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), (userId, r, muteOnReturn) -> {
try {
if (DBG) {
- Slog.d(TAG, "Reposting " + r.getKey());
+ Slog.d(TAG, "Reposting " + r.getKey() + " " + muteOnReturn);
}
enqueueNotificationInternal(r.getSbn().getPackageName(), r.getSbn().getOpPkg(),
r.getSbn().getUid(), r.getSbn().getInitialPid(), r.getSbn().getTag(),
- r.getSbn().getId(), r.getSbn().getNotification(), userId, true);
+ r.getSbn().getId(), r.getSbn().getNotification(), userId, muteOnReturn);
} catch (Exception e) {
Slog.e(TAG, "Cannot un-snooze notification", e);
}
diff --git a/services/core/java/com/android/server/pm/ScanPackageUtils.java b/services/core/java/com/android/server/pm/ScanPackageUtils.java
index 0dc188b..46f0dbc 100644
--- a/services/core/java/com/android/server/pm/ScanPackageUtils.java
+++ b/services/core/java/com/android/server/pm/ScanPackageUtils.java
@@ -427,8 +427,7 @@
pkgSetting.setLastModifiedTime(scanFileTime);
// TODO(b/135203078): Remove, move to constructor
pkgSetting.setPkg(parsedPackage)
- .setFlags(PackageInfoUtils.appInfoFlags(parsedPackage, pkgSetting))
- .setPrivateFlags(
+ .setPkgFlags(PackageInfoUtils.appInfoFlags(parsedPackage, pkgSetting),
PackageInfoUtils.appInfoPrivateFlags(parsedPackage, pkgSetting));
if (parsedPackage.getLongVersionCode() != pkgSetting.getVersionCode()) {
pkgSetting.setLongVersionCode(parsedPackage.getLongVersionCode());
diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java
index b952f80..61a251e 100644
--- a/services/core/java/com/android/server/pm/SettingBase.java
+++ b/services/core/java/com/android/server/pm/SettingBase.java
@@ -146,6 +146,17 @@
return this;
}
+ /**
+ * Unconditionally set both mPkgFlags and mPkgPrivateFlags.
+ * Should not be used outside pkgSetting initialization or update.
+ */
+ SettingBase setPkgFlags(int flags, int privateFlags) {
+ this.mPkgFlags = flags;
+ this.mPkgPrivateFlags = privateFlags;
+ onChanged();
+ return this;
+ }
+
public int getFlags() {
return mPkgFlags;
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 6400502..7437b14 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -987,8 +987,7 @@
// Update new package state.
.setLastModifiedTime(codePath.lastModified())
.setDomainSetId(domainSetId);
- pkgSetting.setFlags(pkgFlags)
- .setPrivateFlags(pkgPrivateFlags);
+ pkgSetting.setPkgFlags(pkgFlags, pkgPrivateFlags);
} else {
pkgSetting = new PackageSetting(pkgName, realPkgName, codePath,
legacyNativeLibraryPath, primaryCpuAbi, secondaryCpuAbi,
@@ -1175,15 +1174,15 @@
.setUsesStaticLibrariesVersions(null);
}
- // These two flags are preserved from the existing PackageSetting. Copied from prior code,
- // unclear if this is actually necessary.
- boolean wasExternalStorage = (pkgSetting.getFlags()
- & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
- if (wasExternalStorage) {
- pkgFlags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE;
- } else {
- pkgFlags &= ~ApplicationInfo.FLAG_EXTERNAL_STORAGE;
- }
+ // If what we are scanning is a system (and possibly privileged) package,
+ // then make it so, regardless of whether it was previously installed only
+ // in the data partition. Reset first.
+ int newPkgFlags = pkgSetting.getFlags();
+ newPkgFlags &= ~ApplicationInfo.FLAG_SYSTEM;
+ newPkgFlags |= pkgFlags & ApplicationInfo.FLAG_SYSTEM;
+ // Only set pkgFlags.
+ pkgSetting.setPkgFlags(newPkgFlags, pkgSetting.getPrivateFlags());
+
boolean wasRequiredForSystemUser = (pkgSetting.getPrivateFlags()
& ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER) != 0;
if (wasRequiredForSystemUser) {
@@ -1191,9 +1190,7 @@
} else {
pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER;
}
-
- pkgSetting.setFlags(pkgFlags)
- .setPrivateFlags(pkgPrivateFlags);
+ pkgSetting.setPrivateFlags(pkgPrivateFlags);
}
/**
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 9bc0553..e8a3dcd 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -155,10 +155,6 @@
int FINISH_LAYOUT_REDO_ANIM = 0x0008;
/** Layer for the screen off animation */
int COLOR_FADE_LAYER = 0x40000001;
- /** Layer for Input overlays for capturing inputs for gesture detection, etc. */
- int INPUT_DISPLAY_OVERLAY_LAYER = 0x7f000000;
- /** Layer for Screen Decoration: The top most visible layer just below input overlay layers */
- int SCREEN_DECOR_DISPLAY_OVERLAY_LAYER = INPUT_DISPLAY_OVERLAY_LAYER - 1;
/**
* Register shortcuts for window manager to dispatch.
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index b7ddbd0..33cdd2e 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -265,7 +265,7 @@
.setContainerLayer()
.setName(name)
.setCallsite("createSurfaceForGestureMonitor")
- .setParent(dc.getOverlayLayer())
+ .setParent(dc.getSurfaceControl())
.build();
}
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 08bf7bc..53f1fe6 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -352,10 +352,6 @@
}
}
- // TODO(b/166736352): Remove this method without the need to expose to launcher.
- @Override
- public void hideCurrentInputMethod() { }
-
@Override
public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) {
synchronized (mService.mGlobalLock) {
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index d09068b..8cad165 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -173,11 +173,6 @@
if (isSizeChanged) {
mRoundedCornerOverlay = displayContent.findRoundedCornerOverlays();
- } else {
- // Exclude rounded corner overlay from screenshot buffer. Rounded
- // corner overlay windows are un-rotated during rotation animation
- // for a seamless transition.
- builder.setExcludeLayers(displayContent.findRoundedCornerOverlays());
}
SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index d31dfee..9d6e250 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -8262,7 +8262,7 @@
.setContainerLayer()
.setName("IME Handwriting Surface")
.setCallsite("getHandwritingSurfaceForDisplay")
- .setParent(dc.getOverlayLayer())
+ .setParent(dc.getSurfaceControl())
.build();
}
}
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 437c934..bbb21f8 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -362,7 +362,7 @@
@Override
void assignLayer(SurfaceControl.Transaction t, int layer) {
if (mRoundedCornerOverlay) {
- super.assignLayer(t, WindowManagerPolicy.SCREEN_DECOR_DISPLAY_OVERLAY_LAYER);
+ super.assignLayer(t, WindowManagerPolicy.COLOR_FADE_LAYER + 1);
} else {
super.assignLayer(t, layer);
}
@@ -372,7 +372,7 @@
SurfaceControl.Builder makeSurface() {
final SurfaceControl.Builder builder = super.makeSurface();
if (mRoundedCornerOverlay) {
- builder.setParent(getDisplayContent().getOverlayLayer());
+ builder.setParent(null);
}
return builder;
}