diff options
97 files changed, 1956 insertions, 1230 deletions
diff --git a/api/current.txt b/api/current.txt index eeaabf661e73..8522034f7bd3 100644 --- a/api/current.txt +++ b/api/current.txt @@ -53041,6 +53041,7 @@ package android.view.contentcapture { method @NonNull public android.view.autofill.AutofillId newAutofillId(@NonNull android.view.autofill.AutofillId, long); method @NonNull public final android.view.ViewStructure newViewStructure(@NonNull android.view.View); method @NonNull public final android.view.ViewStructure newVirtualViewStructure(@NonNull android.view.autofill.AutofillId, long); + method public final void notifySessionLifecycle(boolean); method public final void notifyViewAppeared(@NonNull android.view.ViewStructure); method public final void notifyViewDisappeared(@NonNull android.view.autofill.AutofillId); method public final void notifyViewTextChanged(@NonNull android.view.autofill.AutofillId, @Nullable CharSequence); diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp index 10ac4a182f87..476fae37899d 100644 --- a/cmds/statsd/src/matchers/matcher_util.cpp +++ b/cmds/statsd/src/matchers/matcher_util.cpp @@ -358,9 +358,10 @@ bool matchesSimple(const UidMap& uidMap, const FieldValueMatcher& matcher, bool matchesSimple(const UidMap& uidMap, const SimpleAtomMatcher& simpleMatcher, const LogEvent& event) { - if (simpleMatcher.field_value_matcher_size() <= 0) { - return event.GetTagId() == simpleMatcher.atom_id(); + if (event.GetTagId() != simpleMatcher.atom_id()) { + return false; } + for (const auto& matcher : simpleMatcher.field_value_matcher()) { if (!matchesSimple(uidMap, matcher, event.getValues(), 0, event.getValues().size(), 0)) { return false; diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp index 70f0f6f75a59..441d3c896467 100644 --- a/cmds/statsd/tests/LogEntryMatcher_test.cpp +++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp @@ -330,6 +330,7 @@ TEST(AtomMatcherTest, TestUidFieldMatcher) { EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event)); // Tag found in kAtomsWithUidField and has matching uid + simpleMatcher->set_atom_id(TAG_ID_2); EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2)); // Tag found in kAtomsWithUidField but has non-matching uid diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java index c74daa8eadfc..3933e81c732a 100644 --- a/core/java/android/content/pm/LauncherApps.java +++ b/core/java/android/content/pm/LauncherApps.java @@ -519,9 +519,9 @@ public class LauncherApps { * <li>The app is a system app.</li> * <li>The app doesn't request any <a href="/guide/topics/permissions/overview">permissions</a>. * </li> - * <li>The <code><application></code> tag in the app's manifest doesn't contain any child - * elements that represent - * <a href="/guide/components/fundamentals#DeclaringComponents">app components</a>.</li> + * <li>The app doesn't have a <em>launcher activity</em> that is enabled by default. A launcher + * activity has an intent containing the <code>ACTION_MAIN</code> action and the + * <code>CATEGORY_LAUNCHER</code> category.</li> * </ul> * * <p>Additionally, the system hides synthesized activities for some or all apps in the diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index 30e59590022c..76e728a11e83 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -182,6 +182,12 @@ public class Process { */ public static final int NETWORK_STACK_UID = 1073; + /** + * Defines the UID/GID for fs-verity certificate ownership in keystore. + * @hide + */ + public static final int FSVERITY_CERT_UID = 1075; + /** {@hide} */ public static final int NOBODY_UID = 9999; diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java index 86651060a394..1c50d73c4953 100644 --- a/core/java/android/text/TextLine.java +++ b/core/java/android/text/TextLine.java @@ -276,6 +276,7 @@ public class TextLine { final int runCount = mDirections.getRunCount(); for (int runIndex = 0; runIndex < runCount; runIndex++) { final int runStart = mDirections.getRunStart(runIndex); + if (runStart > mLen) break; final int runLimit = Math.min(runStart + mDirections.getRunLength(runIndex), mLen); final boolean runIsRtl = mDirections.isRunRtl(runIndex); @@ -360,6 +361,7 @@ public class TextLine { float h = 0; for (int runIndex = 0; runIndex < mDirections.getRunCount(); runIndex++) { final int runStart = mDirections.getRunStart(runIndex); + if (runStart > mLen) break; final int runLimit = Math.min(runStart + mDirections.getRunLength(runIndex), mLen); final boolean runIsRtl = mDirections.isRunRtl(runIndex); @@ -417,6 +419,7 @@ public class TextLine { float h = 0; for (int runIndex = 0; runIndex < mDirections.getRunCount(); runIndex++) { final int runStart = mDirections.getRunStart(runIndex); + if (runStart > mLen) break; final int runLimit = Math.min(runStart + mDirections.getRunLength(runIndex), mLen); final boolean runIsRtl = mDirections.isRunRtl(runIndex); diff --git a/core/java/android/view/IPinnedStackController.aidl b/core/java/android/view/IPinnedStackController.aidl index d2dcb568ef6c..f1d152ba29af 100644 --- a/core/java/android/view/IPinnedStackController.aidl +++ b/core/java/android/view/IPinnedStackController.aidl @@ -16,6 +16,8 @@ package android.view; +import android.graphics.Rect; + /** * An interface to the PinnedStackController to update it of state changes, and to query * information based on the current state. @@ -30,15 +32,17 @@ interface IPinnedStackController { oneway void setIsMinimized(boolean isMinimized); /** - * Notifies the controller of the current min edge size, this is needed to allow the system to - * properly calculate the aspect ratio of the expanded PIP. The given {@param minEdgeSize} is - * always bounded to be larger than the default minEdgeSize, so the caller can call this method - * with 0 to reset to the default size. + * @return what WM considers to be the current device rotation. */ - oneway void setMinEdgeSize(int minEdgeSize); + int getDisplayRotation(); /** - * @return what WM considers to be the current device rotation. + * Notifies the controller to actually start the PiP animation. + * The bounds would be calculated based on the last save reentry fraction internally. + * {@param destinationBounds} is the stack bounds of the final PiP window + * and {@param sourceRectHint} is the source bounds hint used when entering picture-in-picture, + * expect the same bound passed via IPinnedStackListener#onPrepareAnimation. + * {@param animationDuration} suggests the animation duration transitioning to PiP window. */ - int getDisplayRotation(); + void startAnimation(in Rect destinationBounds, in Rect sourceRectHint, int animationDuration); } diff --git a/core/java/android/view/IPinnedStackListener.aidl b/core/java/android/view/IPinnedStackListener.aidl index 2da353b1f0ee..806d81e39cca 100644 --- a/core/java/android/view/IPinnedStackListener.aidl +++ b/core/java/android/view/IPinnedStackListener.aidl @@ -16,8 +16,10 @@ package android.view; +import android.content.ComponentName; import android.content.pm.ParceledListSlice; import android.graphics.Rect; +import android.view.DisplayInfo; import android.view.IPinnedStackController; /** @@ -36,18 +38,13 @@ oneway interface IPinnedStackListener { /** * Called when the window manager has detected a change that would cause the movement bounds * to be changed (ie. after configuration change, aspect ratio change, etc). It then provides - * the components that allow the listener to calculate the movement bounds itself. The - * {@param normalBounds} are also the default bounds that the PiP would be entered in its - * current state with the aspect ratio applied. The {@param animatingBounds} are provided - * to indicate the current target bounds of the pinned stack (the final bounds if animating, - * the current bounds if not), which may be helpful in calculating dependent animation bounds. - * - * The {@param displayRotation} is provided so that the client can verify when making certain - * calls that it will not provide stale information based on an old display rotation (ie. if - * the WM has changed in the mean time but the client has not received onMovementBoundsChanged). + * the components that allow the listener to calculate the movement bounds itself. + * The {@param animatingBounds} are provided to indicate the current target bounds of the + * pinned stack (the final bounds if animating, the current bounds if not), + * which may be helpful in calculating dependent animation bounds. */ - void onMovementBoundsChanged(in Rect insetBounds, in Rect normalBounds, in Rect animatingBounds, - boolean fromImeAdjustment, boolean fromShelfAdjustment, int displayRotation); + void onMovementBoundsChanged(in Rect animatingBounds, boolean fromImeAdjustment, + boolean fromShelfAdjustment); /** * Called when window manager decides to adjust the pinned stack bounds because of the IME, or @@ -76,4 +73,47 @@ oneway interface IPinnedStackListener { * is first registered to allow the listener to synchronized its state with the controller. */ void onActionsChanged(in ParceledListSlice actions); + + /** + * Called by the window manager to notify the listener to save the reentry fraction, + * typically when an Activity leaves PiP (picture-in-picture) mode to fullscreen. + * {@param componentName} represents the application component of PiP window + * while {@param bounds} is the current PiP bounds used to calculate the + * reentry snap fraction. + */ + void onSaveReentrySnapFraction(in ComponentName componentName, in Rect bounds); + + /** + * Called by the window manager to notify the listener to reset saved reentry fraction, + * typically when an Activity enters PiP (picture-in-picture) mode from fullscreen. + * {@param componentName} represents the application component of PiP window. + */ + void onResetReentrySnapFraction(in ComponentName componentName); + + /** + * Called when the window manager has detected change on DisplayInfo, or + * when the listener is first registered to allow the listener to synchronized its state with + * the controller. + */ + void onDisplayInfoChanged(in DisplayInfo displayInfo); + + /** + * Called by the window manager at the beginning of a configuration update cascade + * since the metrics from these resources are used for bounds calculations. + */ + void onConfigurationChanged(); + + /** + * Called by the window manager when the aspect ratio is reset. + */ + void onAspectRatioChanged(float aspectRatio); + + /** + * Called by the window manager to notify the listener to prepare for PiP animation. + * Internally, the target bounds would be calculated from the given {@param aspectRatio} + * and {@param bounds}, the saved reentry snap fraction also contributes. + * Caller would wait for a IPinnedStackController#startAnimation callback to actually + * start the animation, see details in IPinnedStackController. + */ + void onPrepareAnimation(in Rect sourceRectHint, float aspectRatio, in Rect bounds); } diff --git a/core/java/android/view/SyncRtSurfaceTransactionApplier.java b/core/java/android/view/SyncRtSurfaceTransactionApplier.java index 85457cb48218..1b6c5752217e 100644 --- a/core/java/android/view/SyncRtSurfaceTransactionApplier.java +++ b/core/java/android/view/SyncRtSurfaceTransactionApplier.java @@ -30,6 +30,14 @@ import java.util.function.Consumer; */ public class SyncRtSurfaceTransactionApplier { + public static final int FLAG_ALL = 0xffffffff; + public static final int FLAG_ALPHA = 1; + public static final int FLAG_MATRIX = 1 << 1; + public static final int FLAG_WINDOW_CROP = 1 << 2; + public static final int FLAG_LAYER = 1 << 3; + public static final int FLAG_CORNER_RADIUS = 1 << 4; + public static final int FLAG_VISIBILITY = 1 << 5; + private final Surface mTargetSurface; private final ViewRootImpl mTargetViewRootImpl; private final float[] mTmpFloat9 = new float[9]; @@ -72,15 +80,27 @@ public class SyncRtSurfaceTransactionApplier { } public static void applyParams(Transaction t, SurfaceParams params, float[] tmpFloat9) { - t.setMatrix(params.surface, params.matrix, tmpFloat9); - t.setWindowCrop(params.surface, params.windowCrop); - t.setAlpha(params.surface, params.alpha); - t.setLayer(params.surface, params.layer); - t.setCornerRadius(params.surface, params.cornerRadius); - if (params.visible) { - t.show(params.surface); - } else { - t.hide(params.surface); + if ((params.flags & FLAG_MATRIX) != 0) { + t.setMatrix(params.surface, params.matrix, tmpFloat9); + } + if ((params.flags & FLAG_WINDOW_CROP) != 0) { + t.setWindowCrop(params.surface, params.windowCrop); + } + if ((params.flags & FLAG_ALPHA) != 0) { + t.setAlpha(params.surface, params.alpha); + } + if ((params.flags & FLAG_LAYER) != 0) { + t.setLayer(params.surface, params.layer); + } + if ((params.flags & FLAG_CORNER_RADIUS) != 0) { + t.setCornerRadius(params.surface, params.cornerRadius); + } + if ((params.flags & FLAG_VISIBILITY) != 0) { + if (params.visible) { + t.show(params.surface); + } else { + t.hide(params.surface); + } } } @@ -115,6 +135,105 @@ public class SyncRtSurfaceTransactionApplier { public static class SurfaceParams { + public static class Builder { + final SurfaceControl surface; + int flags; + float alpha; + float cornerRadius; + Matrix matrix; + Rect windowCrop; + int layer; + boolean visible; + + /** + * @param surface The surface to modify. + */ + public Builder(SurfaceControl surface) { + this.surface = surface; + } + + /** + * @param alpha The alpha value to apply to the surface. + * @return this Builder + */ + public Builder withAlpha(float alpha) { + this.alpha = alpha; + flags |= FLAG_ALPHA; + return this; + } + + /** + * @param matrix The matrix to apply to the surface. + * @return this Builder + */ + public Builder withMatrix(Matrix matrix) { + this.matrix = matrix; + flags |= FLAG_MATRIX; + return this; + } + + /** + * @param windowCrop The window crop to apply to the surface. + * @return this Builder + */ + public Builder withWindowCrop(Rect windowCrop) { + this.windowCrop = windowCrop; + flags |= FLAG_WINDOW_CROP; + return this; + } + + /** + * @param layer The layer to assign the surface. + * @return this Builder + */ + public Builder withLayer(int layer) { + this.layer = layer; + flags |= FLAG_LAYER; + return this; + } + + /** + * @param radius the Radius for rounded corners to apply to the surface. + * @return this Builder + */ + public Builder withCornerRadius(float radius) { + this.cornerRadius = radius; + flags |= FLAG_CORNER_RADIUS; + return this; + } + + /** + * @param visible The visibility to apply to the surface. + * @return this Builder + */ + public Builder withVisibility(boolean visible) { + this.visible = visible; + flags |= FLAG_VISIBILITY; + return this; + } + + /** + * @return a new SurfaceParams instance + */ + public SurfaceParams build() { + return new SurfaceParams(surface, flags, alpha, matrix, windowCrop, layer, + cornerRadius, visible); + } + } + + private SurfaceParams(SurfaceControl surface, int params, float alpha, Matrix matrix, + Rect windowCrop, int layer, float cornerRadius, boolean visible) { + this.flags = params; + this.surface = surface; + this.alpha = alpha; + this.matrix = new Matrix(matrix); + this.windowCrop = new Rect(windowCrop); + this.layer = layer; + this.cornerRadius = cornerRadius; + this.visible = visible; + } + + /** * Constructs surface parameters to be applied when the current view state gets pushed to * RenderThread. @@ -123,9 +242,16 @@ public class SyncRtSurfaceTransactionApplier { * @param alpha Alpha to apply. * @param matrix Matrix to apply. * @param windowCrop Crop to apply. + * @param layer The layer to apply. + * @param cornerRadius The corner radius to apply. + * @param visible The visibility to apply. + * + * @deprecated Use {@link SurfaceParams.Builder} to create an instance. */ + @Deprecated public SurfaceParams(SurfaceControl surface, float alpha, Matrix matrix, Rect windowCrop, int layer, float cornerRadius, boolean visible) { + this.flags = FLAG_ALL; this.surface = surface; this.alpha = alpha; this.matrix = new Matrix(matrix); @@ -135,6 +261,8 @@ public class SyncRtSurfaceTransactionApplier { this.visible = visible; } + private final int flags; + @VisibleForTesting public final SurfaceControl surface; diff --git a/core/java/android/view/accessibility/AccessibilityCache.java b/core/java/android/view/accessibility/AccessibilityCache.java index 484d9a1d173b..dc8bf9b5fbae 100644 --- a/core/java/android/view/accessibility/AccessibilityCache.java +++ b/core/java/android/view/accessibility/AccessibilityCache.java @@ -71,7 +71,9 @@ public class AccessibilityCache { private boolean mIsAllWindowsCached; - private final SparseArray<AccessibilityWindowInfo> mWindowCache = + // The SparseArray of all {@link AccessibilityWindowInfo}s on all displays. + // The key of outer SparseArray is display ID and the key of inner SparseArray is window ID. + private final SparseArray<SparseArray<AccessibilityWindowInfo>> mWindowCacheByDisplay = new SparseArray<>(); private final SparseArray<LongSparseArray<AccessibilityNodeInfo>> mNodeCache = @@ -84,34 +86,66 @@ public class AccessibilityCache { mAccessibilityNodeRefresher = nodeRefresher; } - public void setWindows(List<AccessibilityWindowInfo> windows) { + /** + * Sets all {@link AccessibilityWindowInfo}s of all displays into the cache. + * The key of SparseArray is display ID. + * + * @param windowsOnAllDisplays The accessibility windows of all displays. + */ + public void setWindowsOnAllDisplays( + SparseArray<List<AccessibilityWindowInfo>> windowsOnAllDisplays) { synchronized (mLock) { if (DEBUG) { Log.i(LOG_TAG, "Set windows"); } - clearWindowCache(); - if (windows == null) { + clearWindowCacheLocked(); + if (windowsOnAllDisplays == null) { return; } - final int windowCount = windows.size(); - for (int i = 0; i < windowCount; i++) { - final AccessibilityWindowInfo window = windows.get(i); - addWindow(window); + + final int displayCounts = windowsOnAllDisplays.size(); + for (int i = 0; i < displayCounts; i++) { + final List<AccessibilityWindowInfo> windowsOfDisplay = + windowsOnAllDisplays.valueAt(i); + + if (windowsOfDisplay == null) { + continue; + } + + final int displayId = windowsOnAllDisplays.keyAt(i); + final int windowCount = windowsOfDisplay.size(); + for (int j = 0; j < windowCount; j++) { + addWindowByDisplayLocked(displayId, windowsOfDisplay.get(j)); + } } mIsAllWindowsCached = true; } } + /** + * Sets an {@link AccessibilityWindowInfo} into the cache. + * + * @param window The accessibility window. + */ public void addWindow(AccessibilityWindowInfo window) { synchronized (mLock) { if (DEBUG) { - Log.i(LOG_TAG, "Caching window: " + window.getId()); + Log.i(LOG_TAG, "Caching window: " + window.getId() + " at display Id [ " + + window.getDisplayId() + " ]"); } - final int windowId = window.getId(); - mWindowCache.put(windowId, new AccessibilityWindowInfo(window)); + addWindowByDisplayLocked(window.getDisplayId(), window); } } + private void addWindowByDisplayLocked(int displayId, AccessibilityWindowInfo window) { + SparseArray<AccessibilityWindowInfo> windows = mWindowCacheByDisplay.get(displayId); + if (windows == null) { + windows = new SparseArray<>(); + mWindowCacheByDisplay.put(displayId, windows); + } + final int windowId = window.getId(); + windows.put(windowId, new AccessibilityWindowInfo(window)); + } /** * Notifies the cache that the something in the UI changed. As a result * the cache will either refresh some nodes or evict some nodes. @@ -236,44 +270,82 @@ public class AccessibilityCache { } } - public List<AccessibilityWindowInfo> getWindows() { + /** + * Gets all {@link AccessibilityWindowInfo}s of all displays from the cache. + * + * @return All cached {@link AccessibilityWindowInfo}s of all displays + * or null if such not found. The key of SparseArray is display ID. + */ + public SparseArray<List<AccessibilityWindowInfo>> getWindowsOnAllDisplays() { synchronized (mLock) { if (!mIsAllWindowsCached) { return null; } + final SparseArray<List<AccessibilityWindowInfo>> returnWindows = new SparseArray<>(); + final int displayCounts = mWindowCacheByDisplay.size(); - final int windowCount = mWindowCache.size(); - if (windowCount > 0) { - // Careful to return the windows in a decreasing layer order. - SparseArray<AccessibilityWindowInfo> sortedWindows = mTempWindowArray; - sortedWindows.clear(); + if (displayCounts > 0) { + for (int i = 0; i < displayCounts; i++) { + final int displayId = mWindowCacheByDisplay.keyAt(i); + final SparseArray<AccessibilityWindowInfo> windowsOfDisplay = + mWindowCacheByDisplay.valueAt(i); - for (int i = 0; i < windowCount; i++) { - AccessibilityWindowInfo window = mWindowCache.valueAt(i); - sortedWindows.put(window.getLayer(), window); - } + if (windowsOfDisplay == null) { + continue; + } - // It's possible in transient conditions for two windows to share the same - // layer, which results in sortedWindows being smaller than mWindowCache - final int sortedWindowCount = sortedWindows.size(); - List<AccessibilityWindowInfo> windows = new ArrayList<>(sortedWindowCount); - for (int i = sortedWindowCount - 1; i >= 0; i--) { - AccessibilityWindowInfo window = sortedWindows.valueAt(i); - windows.add(new AccessibilityWindowInfo(window)); - sortedWindows.removeAt(i); - } + final int windowCount = windowsOfDisplay.size(); + if (windowCount > 0) { + // Careful to return the windows in a decreasing layer order. + SparseArray<AccessibilityWindowInfo> sortedWindows = mTempWindowArray; + sortedWindows.clear(); - return windows; + for (int j = 0; j < windowCount; j++) { + AccessibilityWindowInfo window = windowsOfDisplay.valueAt(j); + sortedWindows.put(window.getLayer(), window); + } + + // It's possible in transient conditions for two windows to share the same + // layer, which results in sortedWindows being smaller than + // mWindowCacheByDisplay + final int sortedWindowCount = sortedWindows.size(); + List<AccessibilityWindowInfo> windows = + new ArrayList<>(sortedWindowCount); + for (int j = sortedWindowCount - 1; j >= 0; j--) { + AccessibilityWindowInfo window = sortedWindows.valueAt(j); + windows.add(new AccessibilityWindowInfo(window)); + sortedWindows.removeAt(j); + } + returnWindows.put(displayId, windows); + } + } + return returnWindows; } return null; } } + /** + * Gets an {@link AccessibilityWindowInfo} by windowId. + * + * @param windowId The id of the window. + * + * @return The {@link AccessibilityWindowInfo} or null if such not found. + */ public AccessibilityWindowInfo getWindow(int windowId) { synchronized (mLock) { - AccessibilityWindowInfo window = mWindowCache.get(windowId); - if (window != null) { - return new AccessibilityWindowInfo(window); + final int displayCounts = mWindowCacheByDisplay.size(); + for (int i = 0; i < displayCounts; i++) { + final SparseArray<AccessibilityWindowInfo> windowsOfDisplay = + mWindowCacheByDisplay.valueAt(i); + if (windowsOfDisplay == null) { + continue; + } + + AccessibilityWindowInfo window = windowsOfDisplay.get(windowId); + if (window != null) { + return new AccessibilityWindowInfo(window); + } } return null; } @@ -358,7 +430,7 @@ public class AccessibilityCache { if (DEBUG) { Log.i(LOG_TAG, "clear()"); } - clearWindowCache(); + clearWindowCacheLocked(); final int nodesForWindowCount = mNodeCache.size(); for (int i = nodesForWindowCount - 1; i >= 0; i--) { final int windowId = mNodeCache.keyAt(i); @@ -370,8 +442,23 @@ public class AccessibilityCache { } } - private void clearWindowCache() { - mWindowCache.clear(); + private void clearWindowCacheLocked() { + if (DEBUG) { + Log.i(LOG_TAG, "clearWindowCacheLocked"); + } + final int displayCounts = mWindowCacheByDisplay.size(); + + if (displayCounts > 0) { + for (int i = displayCounts - 1; i >= 0; i--) { + final int displayId = mWindowCacheByDisplay.keyAt(i); + final SparseArray<AccessibilityWindowInfo> windows = + mWindowCacheByDisplay.get(displayId); + if (windows != null) { + windows.clear(); + } + mWindowCacheByDisplay.remove(displayId); + } + } mIsAllWindowsCached = false; } @@ -444,32 +531,41 @@ public class AccessibilityCache { public void checkIntegrity() { synchronized (mLock) { // Get the root. - if (mWindowCache.size() <= 0 && mNodeCache.size() == 0) { + if (mWindowCacheByDisplay.size() <= 0 && mNodeCache.size() == 0) { return; } AccessibilityWindowInfo focusedWindow = null; AccessibilityWindowInfo activeWindow = null; - final int windowCount = mWindowCache.size(); - for (int i = 0; i < windowCount; i++) { - AccessibilityWindowInfo window = mWindowCache.valueAt(i); + final int displayCounts = mWindowCacheByDisplay.size(); + for (int i = 0; i < displayCounts; i++) { + final SparseArray<AccessibilityWindowInfo> windowsOfDisplay = + mWindowCacheByDisplay.valueAt(i); - // Check for one active window. - if (window.isActive()) { - if (activeWindow != null) { - Log.e(LOG_TAG, "Duplicate active window:" + window); - } else { - activeWindow = window; - } + if (windowsOfDisplay == null) { + continue; } - // Check for one focused window. - if (window.isFocused()) { - if (focusedWindow != null) { - Log.e(LOG_TAG, "Duplicate focused window:" + window); - } else { - focusedWindow = window; + final int windowCount = windowsOfDisplay.size(); + for (int j = 0; j < windowCount; j++) { + final AccessibilityWindowInfo window = windowsOfDisplay.valueAt(j); + + // Check for one active window. + if (window.isActive()) { + if (activeWindow != null) { + Log.e(LOG_TAG, "Duplicate active window:" + window); + } else { + activeWindow = window; + } + } + // Check for one focused window. + if (window.isFocused()) { + if (focusedWindow != null) { + Log.e(LOG_TAG, "Duplicate focused window:" + window); + } else { + focusedWindow = window; + } } } } diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java index 4db6f4f808f2..d9fa9f24f1ae 100644 --- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java +++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java @@ -28,6 +28,7 @@ import android.os.SystemClock; import android.util.Log; import android.util.LongSparseArray; import android.util.SparseArray; +import android.view.Display; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; @@ -267,12 +268,14 @@ public final class AccessibilityInteractionClient try { IAccessibilityServiceConnection connection = getConnection(connectionId); if (connection != null) { - List<AccessibilityWindowInfo> windows = sAccessibilityCache.getWindows(); - if (windows != null) { + SparseArray<List<AccessibilityWindowInfo>> allWindows = + sAccessibilityCache.getWindowsOnAllDisplays(); + List<AccessibilityWindowInfo> windows; + if (allWindows != null) { if (DEBUG) { Log.i(LOG_TAG, "Windows cache hit"); } - return windows; + return allWindows.valueAt(Display.DEFAULT_DISPLAY); } if (DEBUG) { Log.i(LOG_TAG, "Windows cache miss"); @@ -284,7 +287,9 @@ public final class AccessibilityInteractionClient Binder.restoreCallingIdentity(identityToken); } if (windows != null) { - sAccessibilityCache.setWindows(windows); + allWindows = new SparseArray<>(); + allWindows.put(Display.DEFAULT_DISPLAY, windows); + sAccessibilityCache.setWindowsOnAllDisplays(allWindows); return windows; } } else { diff --git a/core/java/android/view/contentcapture/ChildContentCaptureSession.java b/core/java/android/view/contentcapture/ChildContentCaptureSession.java index b3b0b72c8799..5e02de451fa3 100644 --- a/core/java/android/view/contentcapture/ChildContentCaptureSession.java +++ b/core/java/android/view/contentcapture/ChildContentCaptureSession.java @@ -89,6 +89,11 @@ final class ChildContentCaptureSession extends ContentCaptureSession { } @Override + public void internalNotifySessionLifecycle(boolean started) { + getMainCaptureSession().notifySessionLifecycle(mId, started); + } + + @Override boolean isContentCaptureEnabled() { return getMainCaptureSession().isContentCaptureEnabled(); } diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java index 625fcda76563..cf08c18b019a 100644 --- a/core/java/android/view/contentcapture/ContentCaptureSession.java +++ b/core/java/android/view/contentcapture/ContentCaptureSession.java @@ -439,6 +439,19 @@ public abstract class ContentCaptureSession implements AutoCloseable { public abstract void internalNotifyViewTreeEvent(boolean started); /** + * Notifies the Content Capture Service that a session has paused/resumed. + * + * @param started whether session has resumed. + */ + public final void notifySessionLifecycle(boolean started) { + if (!isContentCaptureEnabled()) return; + + internalNotifySessionLifecycle(started); + } + + abstract void internalNotifySessionLifecycle(boolean started); + + /** * Creates a {@link ViewStructure} for a "standard" view. * * <p>This method should be called after a visible view is laid out; the view then must populate diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java index 1e7440bd5a43..349ef09cf059 100644 --- a/core/java/android/view/contentcapture/MainContentCaptureSession.java +++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java @@ -583,6 +583,11 @@ public final class MainContentCaptureSession extends ContentCaptureSession { } @Override + public void internalNotifySessionLifecycle(boolean started) { + notifySessionLifecycle(mId, started); + } + + @Override boolean isContentCaptureEnabled() { return super.isContentCaptureEnabled() && mManager.isContentCaptureEnabled(); } @@ -637,10 +642,9 @@ public final class MainContentCaptureSession extends ContentCaptureSession { sendEvent(new ContentCaptureEvent(sessionId, type), FORCE_FLUSH); } - /** Public because is also used by ViewRootImpl */ - public void notifySessionLifecycle(boolean started) { + void notifySessionLifecycle(int sessionId, boolean started) { final int type = started ? TYPE_SESSION_RESUMED : TYPE_SESSION_PAUSED; - sendEvent(new ContentCaptureEvent(mId, type), FORCE_FLUSH); + sendEvent(new ContentCaptureEvent(sessionId, type), FORCE_FLUSH); } void notifyContextUpdated(int sessionId, @Nullable ContentCaptureContext context) { diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index cac75cfd8432..57ce28e5059a 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -2561,7 +2561,8 @@ public class Editor { * @return True when the TextView isFocused and has a valid zero-length selection (cursor). */ private boolean shouldBlink() { - if (!isCursorVisible() || !mTextView.isFocused()) return false; + if (!isCursorVisible() || !mTextView.isFocused() || + !mTextView.isVisibleToUser()) return false; final int start = mTextView.getSelectionStart(); if (start < 0) return false; diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java index 1a22a70eed36..6bce6517a85d 100644 --- a/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java +++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java @@ -29,6 +29,8 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.util.SparseArray; +import android.view.Display; import android.view.View; import androidx.test.filters.LargeTest; @@ -51,12 +53,17 @@ import java.util.List; public class AccessibilityCacheTest { private static final int WINDOW_ID_1 = 0xBEEF; private static final int WINDOW_ID_2 = 0xFACE; + private static final int WINDOW_ID_3 = 0xABCD; + private static final int WINDOW_ID_4 = 0xDCBA; private static final int SINGLE_VIEW_ID = 0xCAFE; private static final int OTHER_VIEW_ID = 0xCAB2; private static final int PARENT_VIEW_ID = 0xFED4; private static final int CHILD_VIEW_ID = 0xFEED; private static final int OTHER_CHILD_VIEW_ID = 0xACE2; private static final int MOCK_CONNECTION_ID = 1; + private static final int SECONDARY_DISPLAY_ID = Display.DEFAULT_DISPLAY + 1; + private static final int DEFAULT_WINDOW_LAYER = 0; + private static final int SPECIFIC_WINDOW_LAYER = 5; AccessibilityCache mAccessibilityCache; AccessibilityCache.AccessibilityNodeRefresher mAccessibilityNodeRefresher; @@ -70,7 +77,7 @@ public class AccessibilityCacheTest { @After public void tearDown() { - // Make sure we're recycling all of our window and node infos + // Make sure we're recycling all of our window and node infos. mAccessibilityCache.clear(); AccessibilityInteractionClient.getInstance().clearCache(); } @@ -78,7 +85,7 @@ public class AccessibilityCacheTest { @Test public void testEmptyCache_returnsNull() { assertNull(mAccessibilityCache.getNode(0, 0)); - assertNull(mAccessibilityCache.getWindows()); + assertNull(mAccessibilityCache.getWindowsOnAllDisplays()); assertNull(mAccessibilityCache.getWindow(0)); } @@ -114,10 +121,11 @@ public class AccessibilityCacheTest { try { windowInfo = AccessibilityWindowInfo.obtain(); windowInfo.setId(WINDOW_ID_1); + windowInfo.setDisplayId(Display.DEFAULT_DISPLAY); mAccessibilityCache.addWindow(windowInfo); // Make a copy copyOfInfo = AccessibilityWindowInfo.obtain(windowInfo); - windowInfo.setId(WINDOW_ID_2); // Simulate recycling and reusing the original info + windowInfo.setId(WINDOW_ID_2); // Simulate recycling and reusing the original info. windowFromCache = mAccessibilityCache.getWindow(WINDOW_ID_1); assertEquals(copyOfInfo, windowFromCache); } finally { @@ -129,39 +137,40 @@ public class AccessibilityCacheTest { @Test public void addWindowThenClear_noLongerInCache() { - putWindowWithIdInCache(WINDOW_ID_1); + putWindowWithWindowIdAndDisplayIdInCache(WINDOW_ID_1, Display.DEFAULT_DISPLAY, + DEFAULT_WINDOW_LAYER); mAccessibilityCache.clear(); assertNull(mAccessibilityCache.getWindow(WINDOW_ID_1)); } @Test public void addWindowGetOtherId_returnsNull() { - putWindowWithIdInCache(WINDOW_ID_1); + putWindowWithWindowIdAndDisplayIdInCache(WINDOW_ID_1, Display.DEFAULT_DISPLAY, + DEFAULT_WINDOW_LAYER); assertNull(mAccessibilityCache.getWindow(WINDOW_ID_1 + 1)); } @Test public void addWindowThenGetWindows_returnsNull() { - putWindowWithIdInCache(WINDOW_ID_1); - assertNull(mAccessibilityCache.getWindows()); + putWindowWithWindowIdAndDisplayIdInCache(WINDOW_ID_1, Display.DEFAULT_DISPLAY, + DEFAULT_WINDOW_LAYER); + assertNull(mAccessibilityCache.getWindowsOnAllDisplays()); } @Test public void setWindowsThenGetWindows_returnsInDecreasingLayerOrder() { - AccessibilityWindowInfo windowInfo1 = null, windowInfo2 = null; - AccessibilityWindowInfo window1Out = null, window2Out = null; + AccessibilityWindowInfo windowInfo1 = null; + AccessibilityWindowInfo windowInfo2 = null; + AccessibilityWindowInfo window1Out = null; + AccessibilityWindowInfo window2Out = null; List<AccessibilityWindowInfo> windowsOut = null; try { - windowInfo1 = AccessibilityWindowInfo.obtain(); - windowInfo1.setId(WINDOW_ID_1); - windowInfo1.setLayer(5); - windowInfo2 = AccessibilityWindowInfo.obtain(); - windowInfo2.setId(WINDOW_ID_2); - windowInfo2.setLayer(windowInfo1.getLayer() + 1); + windowInfo1 = obtainAccessibilityWindowInfo(WINDOW_ID_1, SPECIFIC_WINDOW_LAYER); + windowInfo2 = obtainAccessibilityWindowInfo(WINDOW_ID_2, windowInfo1.getLayer() + 1); List<AccessibilityWindowInfo> windowsIn = Arrays.asList(windowInfo1, windowInfo2); - mAccessibilityCache.setWindows(windowsIn); + setWindowsByDisplay(Display.DEFAULT_DISPLAY, windowsIn); - windowsOut = mAccessibilityCache.getWindows(); + windowsOut = getWindowsByDisplay(Display.DEFAULT_DISPLAY); window1Out = mAccessibilityCache.getWindow(WINDOW_ID_1); window2Out = mAccessibilityCache.getWindow(WINDOW_ID_2); @@ -182,8 +191,151 @@ public class AccessibilityCacheTest { } @Test + public void setWindowsAndAddWindow_thenGetWindows_returnsInDecreasingLayerOrder() { + AccessibilityWindowInfo windowInfo1 = null; + AccessibilityWindowInfo windowInfo2 = null; + AccessibilityWindowInfo window1Out = null; + AccessibilityWindowInfo window2Out = null; + AccessibilityWindowInfo window3Out = null; + List<AccessibilityWindowInfo> windowsOut = null; + try { + windowInfo1 = obtainAccessibilityWindowInfo(WINDOW_ID_1, SPECIFIC_WINDOW_LAYER); + windowInfo2 = obtainAccessibilityWindowInfo(WINDOW_ID_2, windowInfo1.getLayer() + 2); + List<AccessibilityWindowInfo> windowsIn = Arrays.asList(windowInfo1, windowInfo2); + setWindowsByDisplay(Display.DEFAULT_DISPLAY, windowsIn); + + putWindowWithWindowIdAndDisplayIdInCache(WINDOW_ID_3, Display.DEFAULT_DISPLAY, + windowInfo1.getLayer() + 1); + + windowsOut = getWindowsByDisplay(Display.DEFAULT_DISPLAY); + window1Out = mAccessibilityCache.getWindow(WINDOW_ID_1); + window2Out = mAccessibilityCache.getWindow(WINDOW_ID_2); + window3Out = mAccessibilityCache.getWindow(WINDOW_ID_3); + + assertEquals(3, windowsOut.size()); + assertEquals(windowInfo2, windowsOut.get(0)); + assertEquals(windowInfo1, windowsOut.get(2)); + assertEquals(windowInfo1, window1Out); + assertEquals(windowInfo2, window2Out); + assertEquals(window3Out, windowsOut.get(1)); + } finally { + window1Out.recycle(); + window2Out.recycle(); + window3Out.recycle(); + windowInfo1.recycle(); + windowInfo2.recycle(); + for (AccessibilityWindowInfo windowInfo : windowsOut) { + windowInfo.recycle(); + } + } + } + + @Test + public void + setWindowsAtFirstDisplay_thenAddWindowAtSecondDisplay_returnWindowLayerOrderUnchange() { + AccessibilityWindowInfo windowInfo1 = null; + AccessibilityWindowInfo windowInfo2 = null; + AccessibilityWindowInfo window1Out = null; + AccessibilityWindowInfo window2Out = null; + List<AccessibilityWindowInfo> windowsOut = null; + try { + // Sets windows to default display. + windowInfo1 = obtainAccessibilityWindowInfo(WINDOW_ID_1, SPECIFIC_WINDOW_LAYER); + windowInfo2 = obtainAccessibilityWindowInfo(WINDOW_ID_2, windowInfo1.getLayer() + 2); + List<AccessibilityWindowInfo> windowsIn = Arrays.asList(windowInfo1, windowInfo2); + setWindowsByDisplay(Display.DEFAULT_DISPLAY, windowsIn); + // Adds one window to second display. + putWindowWithWindowIdAndDisplayIdInCache(WINDOW_ID_3, SECONDARY_DISPLAY_ID, + windowInfo1.getLayer() + 1); + + windowsOut = getWindowsByDisplay(Display.DEFAULT_DISPLAY); + window1Out = mAccessibilityCache.getWindow(WINDOW_ID_1); + window2Out = mAccessibilityCache.getWindow(WINDOW_ID_2); + + assertEquals(2, windowsOut.size()); + assertEquals(windowInfo2, windowsOut.get(0)); + assertEquals(windowInfo1, windowsOut.get(1)); + assertEquals(windowInfo1, window1Out); + assertEquals(windowInfo2, window2Out); + } finally { + window1Out.recycle(); + window2Out.recycle(); + windowInfo1.recycle(); + windowInfo2.recycle(); + for (AccessibilityWindowInfo windowInfo : windowsOut) { + windowInfo.recycle(); + } + } + } + + @Test + public void setWindowsAtTwoDisplays_thenGetWindows_returnsInDecreasingLayerOrder() { + AccessibilityWindowInfo windowInfo1 = null; + AccessibilityWindowInfo windowInfo2 = null; + AccessibilityWindowInfo window1Out = null; + AccessibilityWindowInfo window2Out = null; + AccessibilityWindowInfo windowInfo3 = null; + AccessibilityWindowInfo windowInfo4 = null; + AccessibilityWindowInfo window3Out = null; + AccessibilityWindowInfo window4Out = null; + List<AccessibilityWindowInfo> windowsOut1 = null; + List<AccessibilityWindowInfo> windowsOut2 = null; + try { + // Prepares all windows for default display. + windowInfo1 = obtainAccessibilityWindowInfo(WINDOW_ID_1, SPECIFIC_WINDOW_LAYER); + windowInfo2 = obtainAccessibilityWindowInfo(WINDOW_ID_2, windowInfo1.getLayer() + 1); + List<AccessibilityWindowInfo> windowsIn1 = Arrays.asList(windowInfo1, windowInfo2); + // Prepares all windows for second display. + windowInfo3 = obtainAccessibilityWindowInfo(WINDOW_ID_3, windowInfo1.getLayer() + 2); + windowInfo4 = obtainAccessibilityWindowInfo(WINDOW_ID_4, windowInfo1.getLayer() + 3); + List<AccessibilityWindowInfo> windowsIn2 = Arrays.asList(windowInfo3, windowInfo4); + // Sets all windows of all displays into A11y cache. + SparseArray<List<AccessibilityWindowInfo>> allWindows = new SparseArray<>(); + allWindows.put(Display.DEFAULT_DISPLAY, windowsIn1); + allWindows.put(SECONDARY_DISPLAY_ID, windowsIn2); + mAccessibilityCache.setWindowsOnAllDisplays(allWindows); + // Gets windows at default display. + windowsOut1 = getWindowsByDisplay(Display.DEFAULT_DISPLAY); + window1Out = mAccessibilityCache.getWindow(WINDOW_ID_1); + window2Out = mAccessibilityCache.getWindow(WINDOW_ID_2); + + assertEquals(2, windowsOut1.size()); + assertEquals(windowInfo2, windowsOut1.get(0)); + assertEquals(windowInfo1, windowsOut1.get(1)); + assertEquals(windowInfo1, window1Out); + assertEquals(windowInfo2, window2Out); + // Gets windows at seocnd display. + windowsOut2 = getWindowsByDisplay(SECONDARY_DISPLAY_ID); + window3Out = mAccessibilityCache.getWindow(WINDOW_ID_3); + window4Out = mAccessibilityCache.getWindow(WINDOW_ID_4); + + assertEquals(2, windowsOut2.size()); + assertEquals(windowInfo4, windowsOut2.get(0)); + assertEquals(windowInfo3, windowsOut2.get(1)); + assertEquals(windowInfo3, window3Out); + assertEquals(windowInfo4, window4Out); + } finally { + window1Out.recycle(); + window2Out.recycle(); + windowInfo1.recycle(); + windowInfo2.recycle(); + window3Out.recycle(); + window4Out.recycle(); + windowInfo3.recycle(); + windowInfo4.recycle(); + for (AccessibilityWindowInfo windowInfo : windowsOut1) { + windowInfo.recycle(); + } + for (AccessibilityWindowInfo windowInfo : windowsOut2) { + windowInfo.recycle(); + } + } + } + + @Test public void addWindowThenStateChangedEvent_noLongerInCache() { - putWindowWithIdInCache(WINDOW_ID_1); + putWindowWithWindowIdAndDisplayIdInCache(WINDOW_ID_1, Display.DEFAULT_DISPLAY, + DEFAULT_WINDOW_LAYER); mAccessibilityCache.onAccessibilityEvent( AccessibilityEvent.obtain(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED)); assertNull(mAccessibilityCache.getWindow(WINDOW_ID_1)); @@ -191,7 +343,8 @@ public class AccessibilityCacheTest { @Test public void addWindowThenWindowsChangedEvent_noLongerInCache() { - putWindowWithIdInCache(WINDOW_ID_1); + putWindowWithWindowIdAndDisplayIdInCache(WINDOW_ID_1, Display.DEFAULT_DISPLAY, + DEFAULT_WINDOW_LAYER); mAccessibilityCache.onAccessibilityEvent( AccessibilityEvent.obtain(AccessibilityEvent.TYPE_WINDOWS_CHANGED)); assertNull(mAccessibilityCache.getWindow(WINDOW_ID_1)); @@ -622,9 +775,16 @@ public class AccessibilityCacheTest { } } - private void putWindowWithIdInCache(int id) { + private AccessibilityWindowInfo obtainAccessibilityWindowInfo(int windowId, int layer) { AccessibilityWindowInfo windowInfo = AccessibilityWindowInfo.obtain(); - windowInfo.setId(id); + windowInfo.setId(windowId); + windowInfo.setLayer(layer); + return windowInfo; + } + + private void putWindowWithWindowIdAndDisplayIdInCache(int windowId, int displayId, int layer) { + AccessibilityWindowInfo windowInfo = obtainAccessibilityWindowInfo(windowId, layer); + windowInfo.setDisplayId(displayId); mAccessibilityCache.addWindow(windowInfo); windowInfo.recycle(); } @@ -713,4 +873,20 @@ public class AccessibilityCacheTest { } } } + + private void setWindowsByDisplay(int displayId, List<AccessibilityWindowInfo> windows) { + SparseArray<List<AccessibilityWindowInfo>> allWindows = new SparseArray<>(); + allWindows.put(displayId, windows); + mAccessibilityCache.setWindowsOnAllDisplays(allWindows); + } + + private List<AccessibilityWindowInfo> getWindowsByDisplay(int displayId) { + final SparseArray<List<AccessibilityWindowInfo>> allWindows = + mAccessibilityCache.getWindowsOnAllDisplays(); + + if (allWindows != null && allWindows.size() > 0) { + return allWindows.get(displayId); + } + return null; + } } diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java index 81ce15a4d8d2..c5da54936653 100644 --- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java +++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java @@ -162,6 +162,11 @@ public class ContentCaptureSessionTest { } @Override + public void internalNotifySessionLifecycle(boolean started) { + throw new UnsupportedOperationException("Should not have been called"); + } + + @Override public void updateContentCaptureContext(ContentCaptureContext context) { throw new UnsupportedOperationException("should not have been called"); } diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java index 8c0108dace69..602fe3ec12fd 100644 --- a/packages/Shell/src/com/android/shell/BugreportProgressService.java +++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java @@ -1264,9 +1264,7 @@ public class BugreportProgressService extends Service { } return new Notification.Builder(context, NOTIFICATION_CHANNEL_ID) .addExtras(sNotificationBundle) - .setSmallIcon( - isTv(context) ? R.drawable.ic_bug_report_black_24dp - : com.android.internal.R.drawable.stat_sys_adb) + .setSmallIcon(R.drawable.ic_bug_report_black_24dp) .setLocalOnly(true) .setColor(context.getColor( com.android.internal.R.color.system_notification_accent_color)) diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index d674be4c8fc0..37fefc2d37d7 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -76,6 +76,16 @@ android_library { plugins: ["dagger2-compiler-2.19"], } +filegroup { + name: "SystemUI-tests-utils", + srcs: [ + "tests/src/com/android/systemui/statusbar/NotificationEntryBuilder.java", + "tests/src/com/android/systemui/statusbar/RankingBuilder.java", + "tests/src/com/android/systemui/statusbar/SbnBuilder.java", + ], + path: "tests/src", +} + android_library { name: "SystemUI-tests", manifest: "tests/AndroidManifest.xml", diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java index 60435d0dec35..d62c1d411cff 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java @@ -22,7 +22,7 @@ import com.android.systemui.plugins.annotations.ProvidesInterface; /** * Allows for additional sensors to be retrieved from - * {@link com.android.systemui.util.AsyncSensorManager}. + * {@link com.android.systemui.util.sensors.AsyncSensorManager}. */ @ProvidesInterface(action = SensorManagerPlugin.ACTION, version = SensorManagerPlugin.VERSION) public interface SensorManagerPlugin extends Plugin { diff --git a/packages/SystemUI/res/layout/auth_biometric_contents.xml b/packages/SystemUI/res/layout/auth_biometric_contents.xml index 925e4fad103d..a1006a8396e0 100644 --- a/packages/SystemUI/res/layout/auth_biometric_contents.xml +++ b/packages/SystemUI/res/layout/auth_biometric_contents.xml @@ -42,7 +42,6 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingHorizontal="24dp" - android:paddingBottom="48dp" android:paddingTop="8dp" android:gravity="@integer/biometric_dialog_text_gravity" android:textSize="16sp" @@ -52,6 +51,7 @@ android:id="@+id/biometric_icon" android:layout_width="@dimen/biometric_dialog_biometric_icon_size" android:layout_height="@dimen/biometric_dialog_biometric_icon_size" + android:paddingTop="48dp" android:layout_gravity="center_horizontal" android:scaleType="fitXY" /> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/PinnedStackListenerForwarder.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/PinnedStackListenerForwarder.java index 3ae2df5b97bf..2797042ac160 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/PinnedStackListenerForwarder.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/PinnedStackListenerForwarder.java @@ -16,9 +16,10 @@ package com.android.systemui.shared.system; +import android.content.ComponentName; import android.content.pm.ParceledListSlice; import android.graphics.Rect; -import android.os.RemoteException; +import android.view.DisplayInfo; import android.view.IPinnedStackController; import android.view.IPinnedStackListener; @@ -32,62 +33,132 @@ import java.util.List; * previously set listener. */ public class PinnedStackListenerForwarder extends IPinnedStackListener.Stub { - private List<IPinnedStackListener> mListeners = new ArrayList<>(); + private List<PinnedStackListener> mListeners = new ArrayList<>(); /** Adds a listener to receive updates from the WindowManagerService. */ - public void addListener(IPinnedStackListener listener) { + public void addListener(PinnedStackListener listener) { mListeners.add(listener); } /** Removes a listener so it will no longer receive updates from the WindowManagerService. */ - public void removeListener(IPinnedStackListener listener) { + public void removeListener(PinnedStackListener listener) { mListeners.remove(listener); } @Override - public void onListenerRegistered(IPinnedStackController controller) throws RemoteException { - for (IPinnedStackListener listener : mListeners) { + public void onListenerRegistered(IPinnedStackController controller) { + for (PinnedStackListener listener : mListeners) { listener.onListenerRegistered(controller); } } @Override - public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds, Rect animatingBounds, - boolean fromImeAdjustment, boolean fromShelfAdjustment, int displayRotation) - throws RemoteException { - for (IPinnedStackListener listener : mListeners) { - listener.onMovementBoundsChanged( - insetBounds, normalBounds, animatingBounds, - fromImeAdjustment, fromShelfAdjustment, displayRotation); + public void onMovementBoundsChanged(Rect animatingBounds, boolean fromImeAdjustment, + boolean fromShelfAdjustment) { + for (PinnedStackListener listener : mListeners) { + listener.onMovementBoundsChanged(animatingBounds, fromImeAdjustment, + fromShelfAdjustment); } } @Override - public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) throws RemoteException { - for (IPinnedStackListener listener : mListeners) { + public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) { + for (PinnedStackListener listener : mListeners) { listener.onImeVisibilityChanged(imeVisible, imeHeight); } } @Override - public void onShelfVisibilityChanged(boolean shelfVisible, int shelfHeight) - throws RemoteException { - for (IPinnedStackListener listener : mListeners) { + public void onShelfVisibilityChanged(boolean shelfVisible, int shelfHeight) { + for (PinnedStackListener listener : mListeners) { listener.onShelfVisibilityChanged(shelfVisible, shelfHeight); } } @Override - public void onMinimizedStateChanged(boolean isMinimized) throws RemoteException { - for (IPinnedStackListener listener : mListeners) { + public void onMinimizedStateChanged(boolean isMinimized) { + for (PinnedStackListener listener : mListeners) { listener.onMinimizedStateChanged(isMinimized); } } @Override - public void onActionsChanged(ParceledListSlice actions) throws RemoteException { - for (IPinnedStackListener listener : mListeners) { + public void onActionsChanged(ParceledListSlice actions) { + for (PinnedStackListener listener : mListeners) { listener.onActionsChanged(actions); } } + + @Override + public void onSaveReentrySnapFraction(ComponentName componentName, Rect bounds) { + for (PinnedStackListener listener : mListeners) { + listener.onSaveReentrySnapFraction(componentName, bounds); + } + } + + @Override + public void onResetReentrySnapFraction(ComponentName componentName) { + for (PinnedStackListener listener : mListeners) { + listener.onResetReentrySnapFraction(componentName); + } + } + + @Override + public void onDisplayInfoChanged(DisplayInfo displayInfo) { + for (PinnedStackListener listener : mListeners) { + listener.onDisplayInfoChanged(displayInfo); + } + } + + @Override + public void onConfigurationChanged() { + for (PinnedStackListener listener : mListeners) { + listener.onConfigurationChanged(); + } + } + + @Override + public void onAspectRatioChanged(float aspectRatio) { + for (PinnedStackListener listener : mListeners) { + listener.onAspectRatioChanged(aspectRatio); + } + } + + @Override + public void onPrepareAnimation(Rect sourceRectHint, float aspectRatio, Rect bounds) { + for (PinnedStackListener listener : mListeners) { + listener.onPrepareAnimation(sourceRectHint, aspectRatio, bounds); + } + } + + /** + * A counterpart of {@link IPinnedStackListener} with empty implementations. + * Subclasses can ignore those methods they do not intend to take action upon. + */ + public static class PinnedStackListener { + public void onListenerRegistered(IPinnedStackController controller) {} + + public void onMovementBoundsChanged(Rect animatingBounds, boolean fromImeAdjustment, + boolean fromShelfAdjustment) {} + + public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {} + + public void onShelfVisibilityChanged(boolean shelfVisible, int shelfHeight) {} + + public void onMinimizedStateChanged(boolean isMinimized) {} + + public void onActionsChanged(ParceledListSlice actions) {} + + public void onSaveReentrySnapFraction(ComponentName componentName, Rect bounds) {} + + public void onResetReentrySnapFraction(ComponentName componentName) {} + + public void onDisplayInfoChanged(DisplayInfo displayInfo) {} + + public void onConfigurationChanged() {} + + public void onAspectRatioChanged(float aspectRatio) {} + + public void onPrepareAnimation(Rect sourceRectHint, float aspectRatio, Rect bounds) {} + } } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java index 794c30a7c7c1..9f1a1fafeec6 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java @@ -27,12 +27,12 @@ import android.graphics.Rect; import android.os.Handler; import android.os.RemoteException; import android.util.Log; -import android.view.IPinnedStackListener; import android.view.WindowManager; import android.view.WindowManagerGlobal; import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture; import com.android.systemui.shared.recents.view.RecentsTransition; +import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener; public class WindowManagerWrapper { @@ -212,7 +212,7 @@ public class WindowManagerWrapper { * Adds a pinned stack listener, which will receive updates from the window manager service * along with any other pinned stack listeners that were added via this method. */ - public void addPinnedStackListener(IPinnedStackListener listener) throws RemoteException { + public void addPinnedStackListener(PinnedStackListener listener) throws RemoteException { mPinnedStackListenerForwarder.addListener(listener); WindowManagerGlobal.getWindowManagerService().registerPinnedStackListener( DEFAULT_DISPLAY, mPinnedStackListenerForwarder); @@ -221,7 +221,7 @@ public class WindowManagerWrapper { /** * Removes a pinned stack listener. */ - public void removePinnedStackListener(IPinnedStackListener listener) { + public void removePinnedStackListener(PinnedStackListener listener) { mPinnedStackListenerForwarder.removeListener(listener); } } diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index bd5b9c724eb3..ca6803d480c0 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -15,6 +15,7 @@ package com.android.systemui; import android.annotation.Nullable; +import android.app.AlarmManager; import android.app.INotificationManager; import android.content.res.Configuration; import android.hardware.SensorPrivacyManager; @@ -110,10 +111,10 @@ import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.tuner.TunablePadding.TunablePaddingService; import com.android.systemui.tuner.TunerService; -import com.android.systemui.util.AsyncSensorManager; import com.android.systemui.util.leak.GarbageMonitor; import com.android.systemui.util.leak.LeakDetector; import com.android.systemui.util.leak.LeakReporter; +import com.android.systemui.util.sensors.AsyncSensorManager; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -314,6 +315,7 @@ public class Dependency { @Inject Lazy<INotificationManager> mINotificationManager; @Inject Lazy<FalsingManager> mFalsingManager; @Inject Lazy<SysUiState> mSysUiStateFlagsContainer; + @Inject Lazy<AlarmManager> mAlarmManager; @Inject public Dependency() { @@ -508,6 +510,7 @@ public class Dependency { mProviders.put(INotificationManager.class, mINotificationManager::get); mProviders.put(FalsingManager.class, mFalsingManager::get); mProviders.put(SysUiState.class, mSysUiStateFlagsContainer::get); + mProviders.put(AlarmManager.class, mAlarmManager::get); // TODO(b/118592525): to support multi-display , we start to add something which is // per-display, while others may be global. I think it's time to add diff --git a/packages/SystemUI/src/com/android/systemui/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/DependencyProvider.java index d46a86cc728f..239cbfe38975 100644 --- a/packages/SystemUI/src/com/android/systemui/DependencyProvider.java +++ b/packages/SystemUI/src/com/android/systemui/DependencyProvider.java @@ -23,6 +23,7 @@ import static com.android.systemui.Dependency.MAIN_LOOPER_NAME; import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME; import android.annotation.Nullable; +import android.app.AlarmManager; import android.app.INotificationManager; import android.content.Context; import android.hardware.SensorPrivacyManager; @@ -230,4 +231,11 @@ public class DependencyProvider { @Named(MAIN_HANDLER_NAME) Handler mainHandler) { return new DeviceProvisionedControllerImpl(context, mainHandler); } + + /** */ + @Singleton + @Provides + public AlarmManager provideAlarmManager(Context context) { + return context.getSystemService(AlarmManager.class); + } } diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/SystemUIModule.java index ff4eb83bd796..38f2f5e8a3a1 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIModule.java @@ -24,7 +24,7 @@ import com.android.systemui.assist.AssistModule; import com.android.systemui.model.SysUiState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.phone.KeyguardLiftController; -import com.android.systemui.util.AsyncSensorManager; +import com.android.systemui.util.sensors.AsyncSensorManager; import javax.inject.Singleton; diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java index e4d2005c8867..73bbce9c5b35 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java @@ -608,7 +608,10 @@ public abstract class AuthBiometricView extends LinearLayout { MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST)); } - totalHeight += child.getMeasuredHeight(); + + if (child.getVisibility() != View.GONE) { + totalHeight += child.getMeasuredHeight(); + } } // Use the new width so it's centered horizontally diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java index 67fc3e32883f..8211c6e94566 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java @@ -48,7 +48,6 @@ import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.pm.ActivityInfo; -import android.content.pm.ParceledListSlice; import android.content.res.Configuration; import android.graphics.Rect; import android.os.RemoteException; @@ -61,8 +60,6 @@ import android.util.Log; import android.util.Pair; import android.util.SparseSetArray; import android.view.Display; -import android.view.IPinnedStackController; -import android.view.IPinnedStackListener; import android.view.ViewGroup; import android.widget.FrameLayout; @@ -76,6 +73,7 @@ import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.PinnedStackListenerForwarder; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.shared.system.WindowManagerWrapper; import com.android.systemui.statusbar.NotificationLockscreenUserManager; @@ -926,7 +924,9 @@ public class BubbleController implements ConfigurationController.ConfigurationLi @Override public void onSingleTaskDisplayDrawn(int displayId) { - final Bubble expandedBubble = getExpandedBubble(mContext); + final Bubble expandedBubble = mStackView != null + ? mStackView.getExpandedBubble() + : null; if (expandedBubble != null && expandedBubble.getDisplayId() == displayId) { expandedBubble.setContentVisibility(true); } @@ -934,7 +934,9 @@ public class BubbleController implements ConfigurationController.ConfigurationLi @Override public void onSingleTaskDisplayEmpty(int displayId) { - final Bubble expandedBubble = getExpandedBubble(mContext); + final Bubble expandedBubble = mStackView != null + ? mStackView.getExpandedBubble() + : null; if (expandedBubble == null) { return; } @@ -993,32 +995,12 @@ public class BubbleController implements ConfigurationController.ConfigurationLi } /** PinnedStackListener that dispatches IME visibility updates to the stack. */ - private class BubblesImeListener extends IPinnedStackListener.Stub { - - @Override - public void onListenerRegistered(IPinnedStackController controller) throws RemoteException { - } - - @Override - public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds, - Rect animatingBounds, boolean fromImeAdjustment, boolean fromShelfAdjustment, - int displayRotation) throws RemoteException {} - + private class BubblesImeListener extends PinnedStackListenerForwarder.PinnedStackListener { @Override public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) { if (mStackView != null && mStackView.getBubbleCount() > 0) { mStackView.post(() -> mStackView.onImeVisibilityChanged(imeVisible, imeHeight)); } } - - @Override - public void onShelfVisibilityChanged(boolean shelfVisible, int shelfHeight) - throws RemoteException {} - - @Override - public void onMinimizedStateChanged(boolean isMinimized) throws RemoteException {} - - @Override - public void onActionsChanged(ParceledListSlice actions) throws RemoteException {} } } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java index c2b0fe4ab2d9..20742d6d2358 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java @@ -43,7 +43,7 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.util.AsyncSensorManager; +import com.android.systemui.util.sensors.AsyncSensorManager; import java.io.PrintWriter; diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java index 85bc22bab36f..914258f48b46 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java @@ -20,6 +20,7 @@ import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHT import static com.android.systemui.Dependency.MAIN_HANDLER_NAME; import android.content.Context; +import android.hardware.SensorManager; import android.net.Uri; import android.os.Handler; import android.provider.DeviceConfig; @@ -35,7 +36,7 @@ import com.android.systemui.plugins.FalsingPlugin; import com.android.systemui.plugins.PluginListener; import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.util.DeviceConfigProxy; -import com.android.systemui.util.ProximitySensor; +import com.android.systemui.util.sensors.ProximitySensor; import java.io.PrintWriter; @@ -66,6 +67,7 @@ public class FalsingManagerProxy implements FalsingManager { DeviceConfigProxy deviceConfig) { mProximitySensor = proximitySensor; mProximitySensor.setTag(PROXIMITY_SENSOR_TAG); + mProximitySensor.setSensorDelay(SensorManager.SENSOR_DELAY_GAME); mDeviceConfig = deviceConfig; mDeviceConfigListener = properties -> onDeviceConfigPropertiesChanged(context, properties.getNamespace()); diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java index 3f5cae678d01..0aa66af1701c 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java @@ -30,7 +30,7 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.classifier.Classifier; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.util.DeviceConfigProxy; -import com.android.systemui.util.ProximitySensor; +import com.android.systemui.util.sensors.ProximitySensor; import java.io.PrintWriter; import java.util.ArrayList; diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingClassifier.java index bf397518de46..53ca78355b12 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingClassifier.java @@ -19,7 +19,7 @@ package com.android.systemui.classifier.brightline; import android.view.MotionEvent; import com.android.systemui.classifier.Classifier; -import com.android.systemui.util.ProximitySensor; +import com.android.systemui.util.sensors.ProximitySensor; import java.util.List; diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java index eeca409866a8..f0feb4ee791d 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java @@ -23,7 +23,7 @@ import android.provider.DeviceConfig; import android.view.MotionEvent; import com.android.systemui.util.DeviceConfigProxy; -import com.android.systemui.util.ProximitySensor; +import com.android.systemui.util.sensors.ProximitySensor; /** diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java index c3672868ba32..bb8c7f1dabf8 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java @@ -33,7 +33,7 @@ import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.statusbar.phone.BiometricUnlockController; import com.android.systemui.statusbar.phone.DozeParameters; -import com.android.systemui.util.AsyncSensorManager; +import com.android.systemui.util.sensors.AsyncSensorManager; import com.android.systemui.util.wakelock.DelayedWakeLock; import com.android.systemui.util.wakelock.WakeLock; @@ -45,7 +45,7 @@ public class DozeFactory { /** Creates a DozeMachine with its parts for {@code dozeService}. */ public DozeMachine assembleMachine(DozeService dozeService, FalsingManager falsingManager) { Context context = dozeService; - SensorManager sensorManager = Dependency.get(AsyncSensorManager.class); + AsyncSensorManager sensorManager = Dependency.get(AsyncSensorManager.class); AlarmManager alarmManager = context.getSystemService(AlarmManager.class); DockManager dockManager = Dependency.get(DockManager.class); WakefulnessLifecycle wakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class); @@ -91,7 +91,7 @@ public class DozeFactory { params.getPolicy()); } - private DozeTriggers createDozeTriggers(Context context, SensorManager sensorManager, + private DozeTriggers createDozeTriggers(Context context, AsyncSensorManager sensorManager, DozeHost host, AlarmManager alarmManager, AmbientDisplayConfiguration config, DozeParameters params, Handler handler, WakeLock wakeLock, DozeMachine machine, DockManager dockManager) { diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java index 026a62528c8d..67eefc5588e3 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java @@ -26,7 +26,6 @@ import android.content.ContentResolver; import android.content.Context; import android.database.ContentObserver; import android.hardware.Sensor; -import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.hardware.TriggerEvent; import android.hardware.TriggerEventListener; @@ -43,11 +42,12 @@ import androidx.annotation.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; -import com.android.systemui.R; +import com.android.systemui.Dependency; import com.android.systemui.plugins.SensorManagerPlugin; +import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.statusbar.phone.DozeParameters; -import com.android.systemui.util.AlarmTimeout; -import com.android.systemui.util.AsyncSensorManager; +import com.android.systemui.util.sensors.AsyncSensorManager; +import com.android.systemui.util.sensors.ProximitySensor; import com.android.systemui.util.wakelock.WakeLock; import java.io.PrintWriter; @@ -62,7 +62,7 @@ public class DozeSensors { private final Context mContext; private final AlarmManager mAlarmManager; - private final SensorManager mSensorManager; + private final AsyncSensorManager mSensorManager; private final ContentResolver mResolver; private final TriggerSensor mPickupSensor; private final DozeParameters mDozeParameters; @@ -74,13 +74,13 @@ public class DozeSensors { protected TriggerSensor[] mSensors; private final Handler mHandler = new Handler(); - private final ProxSensor mProxSensor; + private final ProximitySensor mProximitySensor; private long mDebounceFrom; private boolean mSettingRegistered; private boolean mListening; private boolean mPaused; - public DozeSensors(Context context, AlarmManager alarmManager, SensorManager sensorManager, + public DozeSensors(Context context, AlarmManager alarmManager, AsyncSensorManager sensorManager, DozeParameters dozeParameters, AmbientDisplayConfiguration config, WakeLock wakeLock, Callback callback, Consumer<Boolean> proxCallback, AlwaysOnDisplayPolicy policy) { mContext = context; @@ -91,6 +91,7 @@ public class DozeSensors { mWakeLock = wakeLock; mProxCallback = proxCallback; mResolver = mContext.getContentResolver(); + mCallback = callback; boolean alwaysOn = mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT); mSensors = new TriggerSensor[] { @@ -146,8 +147,11 @@ public class DozeSensors { false /* touchscreen */, mConfig.getWakeLockScreenDebounce()), }; - mProxSensor = new ProxSensor(policy); - mCallback = callback; + mProximitySensor = new ProximitySensor( + context, sensorManager, Dependency.get(PluginManager.class)); + + mProximitySensor.register( + proximityEvent -> mProxCallback.accept(!proximityEvent.getNear())); } /** @@ -236,7 +240,15 @@ public class DozeSensors { } public void setProxListening(boolean listen) { - mProxSensor.setRequested(listen); + if (mProximitySensor.isRegistered() && listen) { + mProximitySensor.alertListeners(); + } else { + if (listen) { + mProximitySensor.resume(); + } else { + mProximitySensor.pause(); + } + } } private final ContentObserver mSettingsObserver = new ContentObserver(mHandler) { @@ -267,115 +279,16 @@ public class DozeSensors { /** Dump current state */ public void dump(PrintWriter pw) { for (TriggerSensor s : mSensors) { - pw.print(" Sensor: "); pw.println(s.toString()); + pw.println(" Sensor: " + s.toString()); } - pw.print(" ProxSensor: "); pw.println(mProxSensor.toString()); + pw.println(" ProxSensor: " + mProximitySensor.toString()); } /** - * @return true if prox is currently far, false if near or null if unknown. + * @return true if prox is currently near, false if far or null if unknown. */ - public Boolean isProximityCurrentlyFar() { - return mProxSensor.mCurrentlyFar; - } - - private class ProxSensor implements SensorEventListener { - - boolean mRequested; - boolean mRegistered; - Boolean mCurrentlyFar; - long mLastNear; - final AlarmTimeout mCooldownTimer; - final AlwaysOnDisplayPolicy mPolicy; - final Sensor mSensor; - final boolean mUsingBrightnessSensor; - - public ProxSensor(AlwaysOnDisplayPolicy policy) { - mPolicy = policy; - mCooldownTimer = new AlarmTimeout(mAlarmManager, this::updateRegistered, - "prox_cooldown", mHandler); - - // The default prox sensor can be noisy, so let's use a prox gated brightness sensor - // if available. - Sensor sensor = DozeSensors.findSensorWithType(mSensorManager, - mContext.getString(R.string.doze_brightness_sensor_type)); - mUsingBrightnessSensor = sensor != null; - if (sensor == null) { - sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY); - } - mSensor = sensor; - } - - void setRequested(boolean requested) { - if (mRequested == requested) { - // Send an update even if we don't re-register. - mHandler.post(() -> { - if (mCurrentlyFar != null) { - mProxCallback.accept(mCurrentlyFar); - } - }); - return; - } - mRequested = requested; - updateRegistered(); - } - - private void updateRegistered() { - setRegistered(mRequested && !mCooldownTimer.isScheduled()); - } - - private void setRegistered(boolean register) { - if (mRegistered == register) { - return; - } - if (register) { - mRegistered = mSensorManager.registerListener(this, mSensor, - SensorManager.SENSOR_DELAY_NORMAL, mHandler); - } else { - mSensorManager.unregisterListener(this); - mRegistered = false; - mCurrentlyFar = null; - } - } - - @Override - public void onSensorChanged(android.hardware.SensorEvent event) { - if (DEBUG) Log.d(TAG, "onSensorChanged " + event); - - if (mUsingBrightnessSensor) { - // The custom brightness sensor is gated by the proximity sensor and will return 0 - // whenever prox is covered. - mCurrentlyFar = event.values[0] > 0; - } else { - mCurrentlyFar = event.values[0] >= event.sensor.getMaximumRange(); - } - mProxCallback.accept(mCurrentlyFar); - - long now = SystemClock.elapsedRealtime(); - if (mCurrentlyFar == null) { - // Sensor has been unregistered by the proxCallback. Do nothing. - } else if (!mCurrentlyFar) { - mLastNear = now; - } else if (mCurrentlyFar && now - mLastNear < mPolicy.proxCooldownTriggerMs) { - // If the last near was very recent, we might be using more power for prox - // wakeups than we're saving from turning of the screen. Instead, turn it off - // for a while. - mCooldownTimer.schedule(mPolicy.proxCooldownPeriodMs, - AlarmTimeout.MODE_IGNORE_IF_SCHEDULED); - updateRegistered(); - } - } - - @Override - public void onAccuracyChanged(Sensor sensor, int accuracy) { - } - - @Override - public String toString() { - return String.format("{registered=%s, requested=%s, coolingDown=%s, currentlyFar=%s," - + " sensor=%s}", mRegistered, mRequested, mCooldownTimer.isScheduled(), - mCurrentlyFar, mSensor); - } + public Boolean isProximityCurrentlyNear() { + return mProximitySensor.isNear(); } @VisibleForTesting diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index bab64db4519c..80d4b631314a 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -24,10 +24,6 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.res.Configuration; -import android.hardware.Sensor; -import android.hardware.SensorEvent; -import android.hardware.SensorEventListener; -import android.hardware.SensorManager; import android.hardware.display.AmbientDisplayConfiguration; import android.metrics.LogMaker; import android.os.Handler; @@ -39,16 +35,16 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.internal.util.Preconditions; import com.android.systemui.Dependency; -import com.android.systemui.R; import com.android.systemui.dock.DockManager; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.util.Assert; +import com.android.systemui.util.sensors.AsyncSensorManager; +import com.android.systemui.util.sensors.ProximitySensor; import com.android.systemui.util.wakelock.WakeLock; import java.io.PrintWriter; -import java.util.function.IntConsumer; +import java.util.function.Consumer; /** * Handles triggers for ambient state changes. @@ -67,13 +63,15 @@ public class DozeTriggers implements DozeMachine.Part { */ private static boolean sWakeDisplaySensorState = true; + private static final int PROXIMITY_TIMEOUT_DELAY_MS = 500; + private final Context mContext; private final DozeMachine mMachine; private final DozeSensors mDozeSensors; private final DozeHost mDozeHost; private final AmbientDisplayConfiguration mConfig; private final DozeParameters mDozeParameters; - private final SensorManager mSensorManager; + private final AsyncSensorManager mSensorManager; private final Handler mHandler; private final WakeLock mWakeLock; private final boolean mAllowPulseTriggers; @@ -81,6 +79,7 @@ public class DozeTriggers implements DozeMachine.Part { private final TriggerReceiver mBroadcastReceiver = new TriggerReceiver(); private final DockEventListener mDockEventListener = new DockEventListener(); private final DockManager mDockManager; + private final ProximitySensor.ProximityCheck mProxCheck; private long mNotificationPulseTime; private boolean mPulsePending; @@ -89,7 +88,7 @@ public class DozeTriggers implements DozeMachine.Part { public DozeTriggers(Context context, DozeMachine machine, DozeHost dozeHost, AlarmManager alarmManager, AmbientDisplayConfiguration config, - DozeParameters dozeParameters, SensorManager sensorManager, Handler handler, + DozeParameters dozeParameters, AsyncSensorManager sensorManager, Handler handler, WakeLock wakeLock, boolean allowPulseTriggers, DockManager dockManager) { mContext = context; mMachine = machine; @@ -105,6 +104,9 @@ public class DozeTriggers implements DozeMachine.Part { dozeParameters.getPolicy()); mUiModeManager = mContext.getSystemService(UiModeManager.class); mDockManager = dockManager; + mProxCheck = new ProximitySensor.ProximityCheck( + new ProximitySensor(mContext, mSensorManager, null), + mHandler); } private void onNotification(Runnable onPulseSuppressedListener) { @@ -134,25 +136,27 @@ public class DozeTriggers implements DozeMachine.Part { } } - private void proximityCheckThenCall(IntConsumer callback, + private void proximityCheckThenCall(Consumer<Boolean> callback, boolean alreadyPerformedProxCheck, int reason) { - Boolean cachedProxFar = mDozeSensors.isProximityCurrentlyFar(); + Boolean cachedProxNear = mDozeSensors.isProximityCurrentlyNear(); if (alreadyPerformedProxCheck) { - callback.accept(ProximityCheck.RESULT_NOT_CHECKED); - } else if (cachedProxFar != null) { - callback.accept(cachedProxFar ? ProximityCheck.RESULT_FAR : ProximityCheck.RESULT_NEAR); + callback.accept(null); + } else if (cachedProxNear != null) { + callback.accept(cachedProxNear); } else { final long start = SystemClock.uptimeMillis(); - new ProximityCheck() { - @Override - public void onProximityResult(int result) { - final long end = SystemClock.uptimeMillis(); - DozeLog.traceProximityResult(mContext, result == RESULT_NEAR, - end - start, reason); - callback.accept(result); - } - }.check(); + mProxCheck.check(PROXIMITY_TIMEOUT_DELAY_MS, near -> { + final long end = SystemClock.uptimeMillis(); + DozeLog.traceProximityResult( + mContext, + near == null ? false : near, + end - start, + reason); + callback.accept(near); + mWakeLock.release(TAG); + }); + mWakeLock.acquire(TAG); } } @@ -178,7 +182,7 @@ public class DozeTriggers implements DozeMachine.Part { } } else { proximityCheckThenCall((result) -> { - if (result == ProximityCheck.RESULT_NEAR) { + if (result) { // In pocket, drop event. return; } @@ -267,7 +271,7 @@ public class DozeTriggers implements DozeMachine.Part { if (wake) { proximityCheckThenCall((result) -> { - if (result == ProximityCheck.RESULT_NEAR) { + if (result) { // In pocket, drop event. return; } @@ -376,7 +380,7 @@ public class DozeTriggers implements DozeMachine.Part { mPulsePending = true; proximityCheckThenCall((result) -> { - if (result == ProximityCheck.RESULT_NEAR) { + if (result) { // in pocket, abort pulse DozeLog.tracePulseDropped(mContext, "inPocket"); mPulsePending = false; @@ -412,104 +416,11 @@ public class DozeTriggers implements DozeMachine.Part { pw.print(" notificationPulseTime="); pw.println(Formatter.formatShortElapsedTime(mContext, mNotificationPulseTime)); - pw.print(" pulsePending="); pw.println(mPulsePending); + pw.println(" pulsePending=" + mPulsePending); pw.println("DozeSensors:"); mDozeSensors.dump(pw); } - /** - * @see DozeSensors.ProxSensor - */ - private abstract class ProximityCheck implements SensorEventListener, Runnable { - private static final int TIMEOUT_DELAY_MS = 500; - - protected static final int RESULT_UNKNOWN = 0; - protected static final int RESULT_NEAR = 1; - protected static final int RESULT_FAR = 2; - protected static final int RESULT_NOT_CHECKED = 3; - - private boolean mRegistered; - private boolean mFinished; - private float mMaxRange; - private boolean mUsingBrightnessSensor; - - protected abstract void onProximityResult(int result); - - public void check() { - Preconditions.checkState(!mFinished && !mRegistered); - Sensor sensor = DozeSensors.findSensorWithType(mSensorManager, - mContext.getString(R.string.doze_brightness_sensor_type)); - mUsingBrightnessSensor = sensor != null; - if (sensor == null) { - sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY); - } - if (sensor == null) { - if (DozeMachine.DEBUG) Log.d(TAG, "ProxCheck: No sensor found"); - finishWithResult(RESULT_UNKNOWN); - return; - } - mDozeSensors.setDisableSensorsInterferingWithProximity(true); - - mMaxRange = sensor.getMaximumRange(); - mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL, 0, - mHandler); - mHandler.postDelayed(this, TIMEOUT_DELAY_MS); - mWakeLock.acquire(TAG); - mRegistered = true; - } - - /** - * @see DozeSensors.ProxSensor#onSensorChanged(SensorEvent) - */ - @Override - public void onSensorChanged(SensorEvent event) { - if (event.values.length == 0) { - if (DozeMachine.DEBUG) Log.d(TAG, "ProxCheck: Event has no values!"); - finishWithResult(RESULT_UNKNOWN); - } else { - if (DozeMachine.DEBUG) { - Log.d(TAG, "ProxCheck: Event: value=" + event.values[0] + " max=" + mMaxRange); - } - final boolean isNear; - if (mUsingBrightnessSensor) { - // The custom brightness sensor is gated by the proximity sensor and will - // return 0 whenever prox is covered. - isNear = event.values[0] == 0; - } else { - isNear = event.values[0] < mMaxRange; - } - finishWithResult(isNear ? RESULT_NEAR : RESULT_FAR); - } - } - - @Override - public void run() { - if (DozeMachine.DEBUG) Log.d(TAG, "ProxCheck: No event received before timeout"); - finishWithResult(RESULT_UNKNOWN); - } - - private void finishWithResult(int result) { - if (mFinished) return; - boolean wasRegistered = mRegistered; - if (mRegistered) { - mHandler.removeCallbacks(this); - mSensorManager.unregisterListener(this); - mDozeSensors.setDisableSensorsInterferingWithProximity(false); - mRegistered = false; - } - onProximityResult(result); - if (wasRegistered) { - mWakeLock.release(TAG); - } - mFinished = true; - } - - @Override - public void onAccuracyChanged(Sensor sensor, int accuracy) { - // noop - } - } - private class TriggerReceiver extends BroadcastReceiver { private boolean mRegistered; diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java index 30be7754cffc..6795bff6409a 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java @@ -18,6 +18,7 @@ package com.android.systemui.pip; import static android.util.TypedValue.COMPLEX_UNIT_DIP; +import android.content.ComponentName; import android.content.Context; import android.content.res.Resources; import android.graphics.Point; @@ -46,9 +47,6 @@ public class PipBoundsHandler { private static final String TAG = PipBoundsHandler.class.getSimpleName(); private static final float INVALID_SNAP_FRACTION = -1f; - // System.identityHashCode guarantees zero for null object. - private static final int INVALID_SYSTEM_IDENTITY_TOKEN = 0; - private final Context mContext; private final IWindowManager mWindowManager; private final PipSnapAlgorithm mSnapAlgorithm; @@ -58,7 +56,7 @@ public class PipBoundsHandler { private final Point mTmpDisplaySize = new Point(); private IPinnedStackController mPinnedStackController; - private int mLastPipToken; + private ComponentName mLastPipComponentName; private float mReentrySnapFraction = INVALID_SNAP_FRACTION; private float mDefaultAspectRatio; @@ -80,8 +78,11 @@ public class PipBoundsHandler { mContext = context; mSnapAlgorithm = new PipSnapAlgorithm(context); mWindowManager = WindowManagerGlobal.getWindowManagerService(); - mAspectRatio = mDefaultAspectRatio; reloadResources(); + // Initialize the aspect ratio to the default aspect ratio. Don't do this in reload + // resources as it would clobber mAspectRatio when entering PiP from fullscreen which + // triggers a configuration change and the resources to be reloaded. + mAspectRatio = mDefaultAspectRatio; } /** @@ -161,27 +162,27 @@ public class PipBoundsHandler { } /** - * Responds to IPinnedStackListener on saving reentry snap fraction for a given token. - * Token should be generated via {@link System#identityHashCode(Object)} + * Responds to IPinnedStackListener on saving reentry snap fraction + * for a given {@link ComponentName}. */ - public void onSaveReentrySnapFraction(int token, Rect stackBounds) { - mReentrySnapFraction = getSnapFraction(stackBounds); - mLastPipToken = token; + public void onSaveReentrySnapFraction(ComponentName componentName, Rect bounds) { + mReentrySnapFraction = getSnapFraction(bounds); + mLastPipComponentName = componentName; } /** - * Responds to IPinnedStackListener on resetting reentry snap fraction for a given token. - * Token should be generated via {@link System#identityHashCode(Object)} + * Responds to IPinnedStackListener on resetting reentry snap fraction + * for a given {@link ComponentName}. */ - public void onResetReentrySnapFraction(int token) { - if (mLastPipToken == token) { + public void onResetReentrySnapFraction(ComponentName componentName) { + if (componentName.equals(mLastPipComponentName)) { onResetReentrySnapFractionUnchecked(); } } private void onResetReentrySnapFractionUnchecked() { mReentrySnapFraction = INVALID_SNAP_FRACTION; - mLastPipToken = INVALID_SYSTEM_IDENTITY_TOKEN; + mLastPipComponentName = null; } /** @@ -212,24 +213,28 @@ public class PipBoundsHandler { /** * Responds to IPinnedStackListener on preparing the pinned stack animation. */ - public void onPrepareAnimation(Rect sourceRectHint, float aspectRatio, Rect stackBounds) { - final Rect targetStackBounds; - if (stackBounds == null) { - targetStackBounds = getDefaultBounds(mReentrySnapFraction); + public void onPrepareAnimation(Rect sourceRectHint, float aspectRatio, Rect bounds) { + final Rect destinationBounds; + if (bounds == null) { + destinationBounds = getDefaultBounds(mReentrySnapFraction); } else { - targetStackBounds = new Rect(); - targetStackBounds.set(stackBounds); + destinationBounds = new Rect(bounds); } if (isValidPictureInPictureAspectRatio(aspectRatio)) { - transformBoundsToAspectRatio(targetStackBounds, aspectRatio, - true /* useCurrentMinEdgeSize */); + transformBoundsToAspectRatio(destinationBounds, aspectRatio, + false /* useCurrentMinEdgeSize */); } - if (targetStackBounds.equals(stackBounds)) { + if (destinationBounds.equals(bounds)) { return; } mAspectRatio = aspectRatio; onResetReentrySnapFractionUnchecked(); - // TODO: callback Window Manager on starting animation with calculated bounds + try { + mPinnedStackController.startAnimation(destinationBounds, sourceRectHint, + -1 /* animationDuration */); + } catch (RemoteException e) { + Log.e(TAG, "Failed to start PiP animation from SysUI", e); + } } /** @@ -358,6 +363,7 @@ public class PipBoundsHandler { public void dump(PrintWriter pw, String prefix) { final String innerPrefix = prefix + " "; pw.println(prefix + TAG); + pw.println(innerPrefix + "mLastPipComponentName=" + mLastPipComponentName); pw.println(innerPrefix + "mReentrySnapFraction=" + mReentrySnapFraction); pw.println(innerPrefix + "mDisplayInfo=" + mDisplayInfo); pw.println(innerPrefix + "mDefaultAspectRatio=" + mDefaultAspectRatio); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java index 3be3422a36ad..8dfae32a1939 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java @@ -32,14 +32,16 @@ import android.os.Handler; import android.os.RemoteException; import android.util.Log; import android.util.Pair; +import android.view.DisplayInfo; import android.view.IPinnedStackController; -import android.view.IPinnedStackListener; import com.android.systemui.Dependency; import com.android.systemui.UiOffloadThread; import com.android.systemui.pip.BasePipManager; +import com.android.systemui.pip.PipBoundsHandler; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.InputConsumerController; +import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.shared.system.WindowManagerWrapper; @@ -58,8 +60,12 @@ public class PipManager implements BasePipManager { private IActivityTaskManager mActivityTaskManager; private Handler mHandler = new Handler(); - private final PinnedStackListener mPinnedStackListener = new PinnedStackListener(); + private final PinnedStackListener mPinnedStackListener = new PipManagerPinnedStackListener(); + private final DisplayInfo mTmpDisplayInfo = new DisplayInfo(); + private final Rect mTmpInsetBounds = new Rect(); + private final Rect mTmpNormalBounds = new Rect(); + private PipBoundsHandler mPipBoundsHandler; private InputConsumerController mInputConsumerController; private PipMenuActivityController mMenuController; private PipMediaController mMediaController; @@ -119,11 +125,11 @@ public class PipManager implements BasePipManager { /** * Handler for messages from the PIP controller. */ - private class PinnedStackListener extends IPinnedStackListener.Stub { - + private class PipManagerPinnedStackListener extends PinnedStackListener { @Override public void onListenerRegistered(IPinnedStackController controller) { mHandler.post(() -> { + mPipBoundsHandler.setPinnedStackController(controller); mTouchHandler.setPinnedStackController(controller); }); } @@ -131,6 +137,7 @@ public class PipManager implements BasePipManager { @Override public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) { mHandler.post(() -> { + mPipBoundsHandler.onImeVisibilityChanged(imeVisible, imeHeight); mTouchHandler.onImeVisibilityChanged(imeVisible, imeHeight); }); } @@ -138,31 +145,66 @@ public class PipManager implements BasePipManager { @Override public void onShelfVisibilityChanged(boolean shelfVisible, int shelfHeight) { mHandler.post(() -> { - mTouchHandler.onShelfVisibilityChanged(shelfVisible, shelfHeight); + mPipBoundsHandler.onShelfVisibilityChanged(shelfVisible, shelfHeight); + mTouchHandler.onShelfVisibilityChanged(shelfVisible, shelfHeight); }); } @Override public void onMinimizedStateChanged(boolean isMinimized) { mHandler.post(() -> { + mPipBoundsHandler.onMinimizedStateChanged(isMinimized); mTouchHandler.setMinimizedState(isMinimized, true /* fromController */); }); } @Override - public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds, - Rect animatingBounds, boolean fromImeAdjustment, boolean fromShelfAdjustment, - int displayRotation) { + public void onMovementBoundsChanged(Rect animatingBounds, boolean fromImeAdjustment, + boolean fromShelfAdjustment) { mHandler.post(() -> { - mTouchHandler.onMovementBoundsChanged(insetBounds, normalBounds, animatingBounds, - fromImeAdjustment, fromShelfAdjustment, displayRotation); + // Populate the inset / normal bounds and DisplayInfo from mPipBoundsHandler first. + mPipBoundsHandler.onMovementBoundsChanged(mTmpInsetBounds, mTmpNormalBounds, + animatingBounds, mTmpDisplayInfo); + mTouchHandler.onMovementBoundsChanged(mTmpInsetBounds, mTmpNormalBounds, + animatingBounds, fromImeAdjustment, fromShelfAdjustment, + mTmpDisplayInfo.rotation); }); } @Override public void onActionsChanged(ParceledListSlice actions) { + mHandler.post(() -> mMenuController.setAppActions(actions)); + } + + @Override + public void onSaveReentrySnapFraction(ComponentName componentName, Rect bounds) { + mHandler.post(() -> mPipBoundsHandler.onSaveReentrySnapFraction(componentName, bounds)); + } + + @Override + public void onResetReentrySnapFraction(ComponentName componentName) { + mHandler.post(() -> mPipBoundsHandler.onResetReentrySnapFraction(componentName)); + } + + @Override + public void onDisplayInfoChanged(DisplayInfo displayInfo) { + mHandler.post(() -> mPipBoundsHandler.onDisplayInfoChanged(displayInfo)); + } + + @Override + public void onConfigurationChanged() { + mHandler.post(() -> mPipBoundsHandler.onConfigurationChanged()); + } + + @Override + public void onAspectRatioChanged(float aspectRatio) { + mHandler.post(() -> mPipBoundsHandler.onAspectRatioChanged(aspectRatio)); + } + + @Override + public void onPrepareAnimation(Rect sourceRectHint, float aspectRatio, Rect bounds) { mHandler.post(() -> { - mMenuController.setAppActions(actions); + mPipBoundsHandler.onPrepareAnimation(sourceRectHint, aspectRatio, bounds); }); } } @@ -184,12 +226,13 @@ public class PipManager implements BasePipManager { } ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener); + mPipBoundsHandler = new PipBoundsHandler(context); mInputConsumerController = InputConsumerController.getPipInputConsumer(); mMediaController = new PipMediaController(context, mActivityManager); mMenuController = new PipMenuActivityController(context, mActivityManager, mMediaController, mInputConsumerController); mTouchHandler = new PipTouchHandler(context, mActivityManager, mActivityTaskManager, - mMenuController, mInputConsumerController); + mMenuController, mInputConsumerController, mPipBoundsHandler); mAppOpsListener = new PipAppOpsListener(context, mActivityManager, mTouchHandler.getMotionHelper()); @@ -252,5 +295,6 @@ public class PipManager implements BasePipManager { mInputConsumerController.dump(pw, innerPrefix); mMenuController.dump(pw, innerPrefix); mTouchHandler.dump(pw, innerPrefix); + mPipBoundsHandler.dump(pw, innerPrefix); } } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java index 30cf412671bc..1f36d97ce308 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -48,6 +48,7 @@ import android.view.accessibility.AccessibilityWindowInfo; import com.android.internal.os.logging.MetricsLoggerWrapper; import com.android.internal.policy.PipSnapAlgorithm; import com.android.systemui.R; +import com.android.systemui.pip.PipBoundsHandler; import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.statusbar.FlingAnimationUtils; @@ -75,6 +76,7 @@ public class PipTouchHandler { private final IActivityTaskManager mActivityTaskManager; private final ViewConfiguration mViewConfig; private final PipMenuListener mMenuListener = new PipMenuListener(); + private final PipBoundsHandler mPipBoundsHandler; private IPinnedStackController mPinnedStackController; private final PipMenuActivityController mMenuController; @@ -178,7 +180,8 @@ public class PipTouchHandler { public PipTouchHandler(Context context, IActivityManager activityManager, IActivityTaskManager activityTaskManager, PipMenuActivityController menuController, - InputConsumerController inputConsumerController) { + InputConsumerController inputConsumerController, + PipBoundsHandler pipBoundsHandler) { // Initialize the Pip input consumer mContext = context; @@ -211,6 +214,8 @@ public class PipTouchHandler { inputConsumerController.setInputListener(this::handleTouchEvent); inputConsumerController.setRegistrationListener(this::onRegistrationChanged); onRegistrationChanged(inputConsumerController.isRegistered()); + + mPipBoundsHandler = pipBoundsHandler; } public void setTouchEnabled(boolean enabled) { @@ -787,14 +792,8 @@ public class PipTouchHandler { mMovementBounds = isMenuExpanded ? mExpandedMovementBounds : mNormalMovementBounds; - try { - if (mPinnedStackController != null) { - mPinnedStackController.setMinEdgeSize( - isMenuExpanded ? mExpandedShortestEdgeSize : 0); - } - } catch (RemoteException e) { - Log.e(TAG, "Could not set minimized state", e); - } + mPipBoundsHandler.setMinEdgeSize( + isMenuExpanded ? mExpandedShortestEdgeSize : 0); } /** diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java index 918af4f0cd4c..81d6973efb2a 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java @@ -19,13 +19,10 @@ package com.android.systemui.pip.tv; import static android.app.ActivityTaskManager.INVALID_STACK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; -import static android.view.Display.DEFAULT_DISPLAY; -import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityManager.StackInfo; import android.app.ActivityTaskManager; -import android.app.IActivityManager; import android.app.IActivityTaskManager; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -46,16 +43,15 @@ import android.os.UserHandle; import android.text.TextUtils; import android.util.Log; import android.util.Pair; -import android.view.IPinnedStackController; -import android.view.IPinnedStackListener; -import android.view.IWindowManager; -import android.view.WindowManagerGlobal; +import android.view.DisplayInfo; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.UiOffloadThread; import com.android.systemui.pip.BasePipManager; +import com.android.systemui.pip.PipBoundsHandler; import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.shared.system.WindowManagerWrapper; @@ -111,9 +107,8 @@ public class PipManager implements BasePipManager { private int mSuspendPipResizingReason; private Context mContext; - private IActivityManager mActivityManager; + private PipBoundsHandler mPipBoundsHandler; private IActivityTaskManager mActivityTaskManager; - private IWindowManager mWindowManager; private MediaSessionManager mMediaSessionManager; private int mState = STATE_NO_PIP; private int mResumeResizePinnedStackRunnableState = STATE_NO_PIP; @@ -135,11 +130,16 @@ public class PipManager implements BasePipManager { private PipNotification mPipNotification; private ParceledListSlice mCustomActions; + // Used to calculate the movement bounds + private final DisplayInfo mTmpDisplayInfo = new DisplayInfo(); + private final Rect mTmpInsetBounds = new Rect(); + private final Rect mTmpNormalBounds = new Rect(); + // Keeps track of the IME visibility to adjust the PiP when the IME is visible private boolean mImeVisible; private int mImeHeightAdjustment; - private final PinnedStackListener mPinnedStackListener = new PinnedStackListener(); + private final PinnedStackListener mPinnedStackListener = new PipManagerPinnedStackListener(); private final Runnable mResizePinnedStackRunnable = new Runnable() { @Override @@ -181,11 +181,7 @@ public class PipManager implements BasePipManager { /** * Handler for messages from the PIP controller. */ - private class PinnedStackListener extends IPinnedStackListener.Stub { - - @Override - public void onListenerRegistered(IPinnedStackController controller) {} - + private class PipManagerPinnedStackListener extends PinnedStackListener { @Override public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) { if (mState == STATE_PIP) { @@ -205,17 +201,13 @@ public class PipManager implements BasePipManager { } @Override - public void onShelfVisibilityChanged(boolean shelfVisible, int shelfHeight) {} - - @Override - public void onMinimizedStateChanged(boolean isMinimized) {} - - @Override - public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds, - Rect animatingBounds, boolean fromImeAdjustment, boolean fromShelfAdjustment, - int displayRotation) { + public void onMovementBoundsChanged(Rect animatingBounds, boolean fromImeAdjustment, + boolean fromShelfAdjustment) { mHandler.post(() -> { - mDefaultPipBounds.set(normalBounds); + // Populate the inset / normal bounds and DisplayInfo from mPipBoundsHandler first. + mPipBoundsHandler.onMovementBoundsChanged(mTmpInsetBounds, mTmpNormalBounds, + animatingBounds, mTmpDisplayInfo); + mDefaultPipBounds.set(animatingBounds); }); } @@ -241,10 +233,8 @@ public class PipManager implements BasePipManager { } mInitialized = true; mContext = context; - - mActivityManager = ActivityManager.getService(); + mPipBoundsHandler = new PipBoundsHandler(context); mActivityTaskManager = ActivityTaskManager.getService(); - mWindowManager = WindowManagerGlobal.getWindowManagerService(); ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_MEDIA_RESOURCE_GRANTED); @@ -291,7 +281,7 @@ public class PipManager implements BasePipManager { (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE); try { - mWindowManager.registerPinnedStackListener(DEFAULT_DISPLAY, mPinnedStackListener); + WindowManagerWrapper.getInstance().addPinnedStackListener(mPinnedStackListener); } catch (RemoteException e) { Log.e(TAG, "Failed to register pinned stack listener", e); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java index 61d7498ced94..1e763cf79240 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java @@ -222,7 +222,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D if (!TILES_SETTING.equals(key)) { return; } - if (DEBUG) Log.d(TAG, "Recreating tiles"); + Log.d(TAG, "Recreating tiles"); if (newValue == null && UserManager.isDeviceInDemoMode(mContext)) { newValue = mContext.getResources().getString(R.string.quick_settings_tiles_retail_mode); } @@ -231,7 +231,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D if (tileSpecs.equals(mTileSpecs) && currentUser == mCurrentUser) return; mTiles.entrySet().stream().filter(tile -> !tileSpecs.contains(tile.getKey())).forEach( tile -> { - if (DEBUG) Log.d(TAG, "Destroying tile: " + tile.getKey()); + Log.d(TAG, "Destroying tile: " + tile.getKey()); tile.getValue().destroy(); }); final LinkedHashMap<String, QSTile> newTiles = new LinkedHashMap<>(); @@ -248,9 +248,10 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D newTiles.put(tileSpec, tile); } else { tile.destroy(); + Log.d(TAG, "Destroying not available tile: " + tileSpec); } } else { - if (DEBUG) Log.d(TAG, "Creating tile: " + tileSpec); + Log.d(TAG, "Creating tile: " + tileSpec); try { tile = createTile(tileSpec); if (tile != null) { @@ -259,6 +260,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D newTiles.put(tileSpec, tile); } else { tile.destroy(); + Log.d(TAG, "Destroying not available tile: " + tileSpec); } } } catch (Throwable t) { @@ -274,7 +276,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D mTiles.putAll(newTiles); if (newTiles.isEmpty() && !tileSpecs.isEmpty()) { // If we didn't manage to create any tiles, set it to empty (default) - if (DEBUG) Log.d(TAG, "No valid tiles on tuning changed. Setting to default."); + Log.d(TAG, "No valid tiles on tuning changed. Setting to default."); changeTiles(currentSpecs, loadTileSpecs(mContext, "")); } else { for (int i = 0; i < mCallbacks.size(); i++) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java index 575b5597b657..4cd3ad27ab34 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java @@ -18,7 +18,6 @@ package com.android.systemui.statusbar.phone; import static android.view.Display.INVALID_DISPLAY; import android.content.Context; -import android.content.pm.ParceledListSlice; import android.content.res.Resources; import android.graphics.PixelFormat; import android.graphics.Point; @@ -36,8 +35,6 @@ import android.util.Log; import android.util.MathUtils; import android.util.StatsLog; import android.view.Gravity; -import android.view.IPinnedStackController; -import android.view.IPinnedStackListener; import android.view.ISystemGestureExclusionListener; import android.view.InputChannel; import android.view.InputDevice; @@ -57,6 +54,7 @@ import com.android.systemui.R; import com.android.systemui.bubbles.BubbleController; import com.android.systemui.model.SysUiState; import com.android.systemui.recents.OverviewProxyService; +import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.shared.system.WindowManagerWrapper; @@ -72,35 +70,13 @@ public class EdgeBackGestureHandler implements DisplayListener { private static final int MAX_LONG_PRESS_TIMEOUT = SystemProperties.getInt( "gestures.back_timeout", 250); - private final IPinnedStackListener.Stub mImeChangedListener = new IPinnedStackListener.Stub() { - @Override - public void onListenerRegistered(IPinnedStackController controller) { - } - + private final PinnedStackListener mImeChangedListener = new PinnedStackListener() { @Override public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) { // No need to thread jump, assignments are atomic mImeHeight = imeVisible ? imeHeight : 0; // TODO: Probably cancel any existing gesture } - - @Override - public void onShelfVisibilityChanged(boolean shelfVisible, int shelfHeight) { - } - - @Override - public void onMinimizedStateChanged(boolean isMinimized) { - } - - @Override - public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds, - Rect animatingBounds, boolean fromImeAdjustment, boolean fromShelfAdjustment, - int displayRotation) { - } - - @Override - public void onActionsChanged(ParceledListSlice actions) { - } }; private ISystemGestureExclusionListener mGestureExclusionListener = diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt index f7bb97b38dd5..00b764bfbe9b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt @@ -24,7 +24,7 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.systemui.Dependency import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.util.Assert -import com.android.systemui.util.AsyncSensorManager +import com.android.systemui.util.sensors.AsyncSensorManager class KeyguardLiftController constructor( private val statusBarStateController: StatusBarStateController, diff --git a/packages/SystemUI/src/com/android/systemui/util/ProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/ProximitySensor.java deleted file mode 100644 index a905eba1f0ed..000000000000 --- a/packages/SystemUI/src/com/android/systemui/util/ProximitySensor.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (C) 2019 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.util; - -import android.content.Context; -import android.hardware.Sensor; -import android.hardware.SensorEvent; -import android.hardware.SensorEventListener; -import android.hardware.SensorManager; -import android.util.Log; - -import com.android.systemui.R; - -import java.util.ArrayList; -import java.util.List; - -import javax.inject.Inject; - -/** - * Simple wrapper around SensorManager customized for the Proximity sensor. - */ -public class ProximitySensor { - private static final String TAG = "ProxSensor"; - private static final boolean DEBUG = false; - - private final Sensor mSensor; - private final AsyncSensorManager mSensorManager; - private final boolean mUsingBrightnessSensor; - private final float mMaxRange; - - private SensorEventListener mSensorEventListener = new SensorEventListener() { - @Override - public synchronized void onSensorChanged(SensorEvent event) { - onSensorEvent(event); - } - - @Override - public void onAccuracyChanged(Sensor sensor, int accuracy) { - } - }; - private boolean mNear; - private List<ProximitySensorListener> mListeners = new ArrayList<>(); - private String mTag = null; - - @Inject - public ProximitySensor(Context context, AsyncSensorManager sensorManager) { - mSensorManager = sensorManager; - Sensor sensor = findBrightnessSensor(context, sensorManager); - - if (sensor == null) { - mUsingBrightnessSensor = false; - sensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY); - } else { - mUsingBrightnessSensor = true; - } - mSensor = sensor; - if (mSensor != null) { - mMaxRange = mSensor.getMaximumRange(); - } else { - mMaxRange = 0; - } - } - - public void setTag(String tag) { - mTag = tag; - } - - private Sensor findBrightnessSensor(Context context, SensorManager sensorManager) { - String sensorType = context.getString(R.string.doze_brightness_sensor_type); - List<Sensor> sensorList = sensorManager.getSensorList(Sensor.TYPE_ALL); - Sensor sensor = null; - for (Sensor s : sensorList) { - if (sensorType.equals(s.getStringType())) { - sensor = s; - break; - } - } - - return sensor; - } - - /** - * Returns {@code false} if a Proximity sensor is not available. - */ - public boolean getSensorAvailable() { - return mSensor != null; - } - - /** - * Add a listener. - * - * Registers itself with the {@link SensorManager} if this is the first listener - * added. - */ - public boolean register(ProximitySensorListener listener) { - if (!getSensorAvailable()) { - return false; - } - - logDebug("using brightness sensor? " + mUsingBrightnessSensor); - mListeners.add(listener); - if (mListeners.size() == 1) { - logDebug("registering sensor listener"); - mSensorManager.registerListener( - mSensorEventListener, mSensor, SensorManager.SENSOR_DELAY_GAME); - } - - return true; - } - - /** - * Remove a listener. - * - * If all listeners are removed from an instance of this class, - * it will unregister itself with the SensorManager. - */ - public void unregister(ProximitySensorListener listener) { - mListeners.remove(listener); - if (mListeners.size() == 0) { - logDebug("unregistering sensor listener"); - mSensorManager.unregisterListener(mSensorEventListener); - } - } - - public boolean isNear() { - return getSensorAvailable() && mNear; - } - - private void onSensorEvent(SensorEvent event) { - boolean near = event.values[0] < mMaxRange; - if (mUsingBrightnessSensor) { - near = event.values[0] == 0; - } - mNear = near; - mListeners.forEach(proximitySensorListener -> - proximitySensorListener.onProximitySensorEvent( - new ProximityEvent(mNear, event.timestamp))); - } - - /** Implement to be notified of ProximityEvents. */ - public interface ProximitySensorListener { - /** Called when the ProximitySensor changes. */ - void onProximitySensorEvent(ProximityEvent proximityEvent); - } - - /** - * Returned when the near/far state of a {@link ProximitySensor} changes. - */ - public static class ProximityEvent { - private final boolean mNear; - private final long mTimestampNs; - - public ProximityEvent(boolean near, long timestampNs) { - mNear = near; - mTimestampNs = timestampNs; - } - - public boolean getNear() { - return mNear; - } - - public long getTimestampNs() { - return mTimestampNs; - } - } - - private void logDebug(String msg) { - if (DEBUG) { - Log.d(TAG, (mTag != null ? "[" + mTag + "] " : "") + msg); - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/util/AsyncSensorManager.java b/packages/SystemUI/src/com/android/systemui/util/sensors/AsyncSensorManager.java index b9c5ee5a7a7e..dcd0c58a5310 100644 --- a/packages/SystemUI/src/com/android/systemui/util/AsyncSensorManager.java +++ b/packages/SystemUI/src/com/android/systemui/util/sensors/AsyncSensorManager.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2019 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.util; +package com.android.systemui.util.sensors; import android.content.Context; import android.hardware.HardwareBuffer; @@ -56,23 +56,31 @@ public class AsyncSensorManager extends SensorManager private final SensorManager mInner; private final List<Sensor> mSensorCache; - private final HandlerThread mHandlerThread = new HandlerThread("async_sensor"); - @VisibleForTesting final Handler mHandler; + private final Handler mHandler; private final List<SensorManagerPlugin> mPlugins; @Inject public AsyncSensorManager(Context context, PluginManager pluginManager) { - this(context.getSystemService(SensorManager.class), pluginManager); + this(context.getSystemService(SensorManager.class), pluginManager, null); } @VisibleForTesting - AsyncSensorManager(SensorManager sensorManager, PluginManager pluginManager) { + public AsyncSensorManager( + SensorManager sensorManager, PluginManager pluginManager, Handler handler) { mInner = sensorManager; - mHandlerThread.start(); - mHandler = new Handler(mHandlerThread.getLooper()); + if (handler == null) { + HandlerThread handlerThread = new HandlerThread("async_sensor"); + handlerThread.start(); + mHandler = new Handler(handlerThread.getLooper()); + } else { + mHandler = handler; + } mSensorCache = mInner.getSensorList(Sensor.TYPE_ALL); mPlugins = new ArrayList<>(); - pluginManager.addPluginListener(this, SensorManagerPlugin.class, true /* allowMultiple */); + if (pluginManager != null) { + pluginManager.addPluginListener(this, SensorManagerPlugin.class, + true /* allowMultiple */); + } } @Override diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java new file mode 100644 index 000000000000..c48bdde6adef --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java @@ -0,0 +1,306 @@ +/* + * Copyright (C) 2019 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.util.sensors; + +import android.content.Context; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.os.Handler; +import android.util.Log; + +import com.android.systemui.R; +import com.android.systemui.shared.plugins.PluginManager; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.function.Consumer; + +import javax.inject.Inject; + +/** + * Simple wrapper around SensorManager customized for the Proximity sensor. + */ +public class ProximitySensor { + private static final String TAG = "ProxSensor"; + private static final boolean DEBUG = false; + + private final Sensor mSensor; + private final AsyncSensorManager mSensorManager; + private final boolean mUsingBrightnessSensor; + private final float mMaxRange; + private List<ProximitySensorListener> mListeners = new ArrayList<>(); + private String mTag = null; + private ProximityEvent mLastEvent; + private int mSensorDelay = SensorManager.SENSOR_DELAY_NORMAL; + private boolean mPaused; + private boolean mRegistered; + + private SensorEventListener mSensorEventListener = new SensorEventListener() { + @Override + public synchronized void onSensorChanged(SensorEvent event) { + onSensorEvent(event); + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { + } + }; + + @Inject + public ProximitySensor( + Context context, AsyncSensorManager sensorManager, PluginManager pluginManager) { + mSensorManager = sensorManager; + Sensor sensor = findBrightnessSensor(context); + + if (sensor == null) { + mUsingBrightnessSensor = false; + sensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY); + } else { + mUsingBrightnessSensor = true; + } + mSensor = sensor; + if (mSensor != null) { + mMaxRange = mSensor.getMaximumRange(); + } else { + mMaxRange = 0; + } + } + + public void setTag(String tag) { + mTag = tag; + } + + public void setSensorDelay(int sensorDelay) { + mSensorDelay = sensorDelay; + } + + /** + * Unregister with the {@link SensorManager} without unsetting listeners on this object. + */ + public void pause() { + mPaused = true; + unregisterInternal(); + } + + /** + * Register with the {@link SensorManager}. No-op if no listeners are registered on this object. + */ + public void resume() { + mPaused = false; + registerInternal(); + } + + private Sensor findBrightnessSensor(Context context) { + String sensorType = context.getString(R.string.doze_brightness_sensor_type); + List<Sensor> sensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL); + Sensor sensor = null; + for (Sensor s : sensorList) { + if (sensorType.equals(s.getStringType())) { + sensor = s; + break; + } + } + + return sensor; + } + + /** + * Returns true if we are registered with the SensorManager. + */ + public boolean isRegistered() { + return mRegistered; + } + + /** + * Returns {@code false} if a Proximity sensor is not available. + */ + public boolean getSensorAvailable() { + return mSensor != null; + } + + /** + * Add a listener. + * + * Registers itself with the {@link SensorManager} if this is the first listener + * added. If a cool down is currently running, the sensor will be registered when it is over. + */ + public boolean register(ProximitySensorListener listener) { + if (!getSensorAvailable()) { + return false; + } + + logDebug("Using brightness sensor? " + mUsingBrightnessSensor); + mListeners.add(listener); + registerInternal(); + + return true; + } + + private void registerInternal() { + if (mRegistered || mPaused || mListeners.isEmpty()) { + return; + } + logDebug("Registering sensor listener"); + mRegistered = true; + mSensorManager.registerListener(mSensorEventListener, mSensor, mSensorDelay); + } + + /** + * Remove a listener. + * + * If all listeners are removed from an instance of this class, + * it will unregister itself with the SensorManager. + */ + public void unregister(ProximitySensorListener listener) { + mListeners.remove(listener); + if (mListeners.size() == 0) { + unregisterInternal(); + } + } + + private void unregisterInternal() { + if (!mRegistered) { + return; + } + logDebug("unregistering sensor listener"); + mSensorManager.unregisterListener(mSensorEventListener); + mRegistered = false; + } + + public Boolean isNear() { + return getSensorAvailable() && mLastEvent != null ? mLastEvent.getNear() : null; + } + + /** Update all listeners with the last value this class received from the sensor. */ + public void alertListeners() { + mListeners.forEach(proximitySensorListener -> + proximitySensorListener.onSensorEvent(mLastEvent)); + } + + private void onSensorEvent(SensorEvent event) { + boolean near = event.values[0] < mMaxRange; + if (mUsingBrightnessSensor) { + near = event.values[0] == 0; + } + mLastEvent = new ProximityEvent(near, event.timestamp); + alertListeners(); + } + + @Override + public String toString() { + return String.format("{registered=%s, paused=%s, near=%s, sensor=%s}", + isRegistered(), mPaused, isNear(), mSensor); + } + + /** + * Convenience class allowing for briefly checking the proximity sensor. + */ + public static class ProximityCheck implements Runnable { + + private final ProximitySensor mSensor; + private final Handler mHandler; + private List<Consumer<Boolean>> mCallbacks = new ArrayList<>(); + + @Inject + public ProximityCheck(ProximitySensor sensor, Handler handler) { + mSensor = sensor; + mSensor.setTag("prox_check"); + mHandler = handler; + mSensor.pause(); + ProximitySensorListener listener = proximityEvent -> { + mCallbacks.forEach( + booleanConsumer -> + booleanConsumer.accept( + proximityEvent == null ? null : proximityEvent.getNear())); + mCallbacks.clear(); + mSensor.pause(); + }; + mSensor.register(listener); + } + + /** Set a descriptive tag for the sensors registration. */ + public void setTag(String tag) { + mSensor.setTag(tag); + } + + @Override + public void run() { + mSensor.pause(); + mSensor.alertListeners(); + } + + /** + * Query the proximity sensor, timing out if no result. + */ + public void check(long timeoutMs, Consumer<Boolean> callback) { + if (!mSensor.getSensorAvailable()) { + callback.accept(null); + } + mCallbacks.add(callback); + if (!mSensor.isRegistered()) { + mSensor.resume(); + mHandler.postDelayed(this, timeoutMs); + } + } + } + + /** Implement to be notified of ProximityEvents. */ + public interface ProximitySensorListener { + /** Called when the ProximitySensor changes. */ + void onSensorEvent(ProximityEvent proximityEvent); + } + + /** + * Returned when the near/far state of a {@link ProximitySensor} changes. + */ + public static class ProximityEvent { + private final boolean mNear; + private final long mTimestampNs; + + public ProximityEvent(boolean near, long timestampNs) { + mNear = near; + mTimestampNs = timestampNs; + } + + public boolean getNear() { + return mNear; + } + + public long getTimestampNs() { + return mTimestampNs; + } + + public long getTimestampMs() { + return mTimestampNs / 1000000; + } + + @Override + public String toString() { + return String.format((Locale) null, "{near=%s, timestamp_ns=%d}", mNear, mTimestampNs); + } + + } + + private void logDebug(String msg) { + if (DEBUG) { + Log.d(TAG, (mTag != null ? "[" + mTag + "] " : "") + msg); + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java index b9793562d8d8..3561e3465898 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java @@ -34,7 +34,7 @@ import com.android.systemui.classifier.brightline.BrightLineFalsingManager; import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.DeviceConfigProxyFake; -import com.android.systemui.util.ProximitySensor; +import com.android.systemui.util.sensors.ProximitySensor; import org.junit.After; import org.junit.Before; diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java index 3fc5d7202d0a..35d59c1c9726 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java @@ -30,7 +30,7 @@ import android.view.MotionEvent; import androidx.test.filters.SmallTest; import com.android.systemui.util.DeviceConfigProxyFake; -import com.android.systemui.util.ProximitySensor; +import com.android.systemui.util.sensors.ProximitySensor; import org.junit.After; import org.junit.Before; diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java index 0c124fff53a3..752e145d79bd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java @@ -24,7 +24,7 @@ import static org.mockito.Mockito.when; import static org.mockito.Mockito.withSettings; import com.android.systemui.statusbar.phone.DozeParameters; -import com.android.systemui.utils.hardware.FakeSensorManager; +import com.android.systemui.util.sensors.FakeSensorManager; import org.mockito.Answers; import org.mockito.MockSettings; diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java index 392c677b9827..aa62e9aca4fe 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java @@ -40,7 +40,7 @@ import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.systemui.SysuiTestCase; -import com.android.systemui.utils.hardware.FakeSensorManager; +import com.android.systemui.util.sensors.FakeSensorManager; import org.junit.Before; import org.junit.Test; diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java index cd6d1e069566..ddd1685bf8bc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java @@ -44,7 +44,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.doze.DozeSensors.TriggerSensor; import com.android.systemui.plugins.SensorManagerPlugin; import com.android.systemui.statusbar.phone.DozeParameters; -import com.android.systemui.util.AsyncSensorManager; +import com.android.systemui.util.sensors.AsyncSensorManager; import com.android.systemui.util.wakelock.WakeLock; import org.junit.Before; diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java index e190f9923da8..f7cd69643fc6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java @@ -32,6 +32,7 @@ import android.hardware.display.AmbientDisplayConfiguration; import android.os.Handler; import android.os.Looper; import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; import androidx.test.filters.SmallTest; @@ -39,9 +40,10 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.dock.DockManager; import com.android.systemui.statusbar.phone.DozeParameters; +import com.android.systemui.util.sensors.AsyncSensorManager; +import com.android.systemui.util.sensors.FakeSensorManager; import com.android.systemui.util.wakelock.WakeLock; import com.android.systemui.util.wakelock.WakeLockFake; -import com.android.systemui.utils.hardware.FakeSensorManager; import org.junit.Before; import org.junit.BeforeClass; @@ -55,12 +57,8 @@ public class DozeTriggersTest extends SysuiTestCase { private DozeTriggers mTriggers; private DozeMachine mMachine; private DozeHostFake mHost; - private AmbientDisplayConfiguration mConfig; - private DozeParameters mParameters; private FakeSensorManager mSensors; private Sensor mTapSensor; - private WakeLock mWakeLock; - private AlarmManager mAlarmManager; private DockManager mDockManagerFake; @BeforeClass @@ -72,18 +70,21 @@ public class DozeTriggersTest extends SysuiTestCase { @Before public void setUp() throws Exception { mMachine = mock(DozeMachine.class); - mAlarmManager = mock(AlarmManager.class); + AlarmManager alarmManager = mock(AlarmManager.class); mHost = spy(new DozeHostFake()); - mConfig = DozeConfigurationUtil.createMockConfig(); - mParameters = DozeConfigurationUtil.createMockParameters(); + AmbientDisplayConfiguration config = DozeConfigurationUtil.createMockConfig(); + DozeParameters parameters = DozeConfigurationUtil.createMockParameters(); mSensors = spy(new FakeSensorManager(mContext)); mTapSensor = mSensors.getFakeTapSensor().getSensor(); - mWakeLock = new WakeLockFake(); + WakeLock wakeLock = new WakeLockFake(); mDockManagerFake = mock(DockManager.class); + AsyncSensorManager asyncSensorManager = + new AsyncSensorManager(mSensors, null, new Handler()); - mTriggers = new DozeTriggers(mContext, mMachine, mHost, mAlarmManager, mConfig, mParameters, - mSensors, Handler.createAsync(Looper.myLooper()), mWakeLock, true, + mTriggers = new DozeTriggers(mContext, mMachine, mHost, alarmManager, config, parameters, + asyncSensorManager, Handler.createAsync(Looper.myLooper()), wakeLock, true, mDockManagerFake); + waitForSensorManager(); } @Test @@ -95,13 +96,14 @@ public class DozeTriggersTest extends SysuiTestCase { clearInvocations(mMachine); mHost.callback.onNotificationAlerted(null /* pulseSuppressedListener */); - mSensors.getMockProximitySensor().sendProximityResult(false); /* Near */ + mSensors.getFakeProximitySensor().sendProximityResult(false); /* Near */ verify(mMachine, never()).requestState(any()); verify(mMachine, never()).requestPulse(anyInt()); mHost.callback.onNotificationAlerted(null /* pulseSuppressedListener */); - mSensors.getMockProximitySensor().sendProximityResult(true); /* Far */ + waitForSensorManager(); + mSensors.getFakeProximitySensor().sendProximityResult(true); /* Far */ verify(mMachine).requestPulse(anyInt()); } @@ -111,6 +113,7 @@ public class DozeTriggersTest extends SysuiTestCase { when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE); mTriggers.transitionTo(DozeMachine.State.INITIALIZED, DozeMachine.State.DOZE); + waitForSensorManager(); verify(mSensors).requestTriggerSensor(any(), eq(mTapSensor)); clearInvocations(mSensors); @@ -118,10 +121,12 @@ public class DozeTriggersTest extends SysuiTestCase { DozeMachine.State.DOZE_REQUEST_PULSE); mTriggers.transitionTo(DozeMachine.State.DOZE_REQUEST_PULSE, DozeMachine.State.DOZE_PULSING); + waitForSensorManager(); verify(mSensors).cancelTriggerSensor(any(), eq(mTapSensor)); clearInvocations(mSensors); mTriggers.transitionTo(DozeMachine.State.DOZE_PULSING, DozeMachine.State.DOZE_PULSE_DONE); + waitForSensorManager(); verify(mSensors).requestTriggerSensor(any(), eq(mTapSensor)); } @@ -133,4 +138,8 @@ public class DozeTriggersTest extends SysuiTestCase { mTriggers.transitionTo(DozeMachine.State.DOZE, DozeMachine.State.FINISH); verify(mDockManagerFake).removeListener(any()); } + + private void waitForSensorManager() { + TestableLooper.get(this).processAllMessages(); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/AsyncSensorManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/AsyncSensorManagerTest.java index 4a9b1b3c4006..9149599f2c7c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/AsyncSensorManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/AsyncSensorManagerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2019 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. @@ -14,9 +14,8 @@ * limitations under the License. */ -package com.android.systemui.util; +package com.android.systemui.util.sensors; -import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; @@ -24,15 +23,15 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import android.hardware.SensorEventListener; -import android.hardware.SensorManager; +import android.os.Handler; import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.SensorManagerPlugin; import com.android.systemui.shared.plugins.PluginManager; -import com.android.systemui.utils.hardware.FakeSensorManager; import org.junit.Before; import org.junit.Test; @@ -40,20 +39,21 @@ import org.junit.runner.RunWith; @SmallTest @RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper public class AsyncSensorManagerTest extends SysuiTestCase { - private TestableAsyncSensorManager mAsyncSensorManager; - private FakeSensorManager mFakeSensorManager; + private AsyncSensorManager mAsyncSensorManager; private SensorEventListener mListener; - private FakeSensorManager.MockProximitySensor mSensor; + private FakeSensorManager.FakeProximitySensor mSensor; private PluginManager mPluginManager; @Before public void setUp() throws Exception { mPluginManager = mock(PluginManager.class); - mFakeSensorManager = new FakeSensorManager(mContext); - mAsyncSensorManager = new TestableAsyncSensorManager(mFakeSensorManager); - mSensor = mFakeSensorManager.getMockProximitySensor(); + FakeSensorManager fakeSensorManager = new FakeSensorManager(mContext); + mAsyncSensorManager = new AsyncSensorManager( + fakeSensorManager, mPluginManager, new Handler()); + mSensor = fakeSensorManager.getFakeProximitySensor(); mListener = mock(SensorEventListener.class); } @@ -61,7 +61,7 @@ public class AsyncSensorManagerTest extends SysuiTestCase { public void registerListenerImpl() throws Exception { mAsyncSensorManager.registerListener(mListener, mSensor.getSensor(), 100); - mAsyncSensorManager.waitUntilRequestsCompleted(); + waitUntilRequestsCompleted(); // Verify listener was registered. mSensor.sendProximityResult(true); @@ -73,7 +73,7 @@ public class AsyncSensorManagerTest extends SysuiTestCase { mAsyncSensorManager.registerListener(mListener, mSensor.getSensor(), 100); mAsyncSensorManager.unregisterListener(mListener); - mAsyncSensorManager.waitUntilRequestsCompleted(); + waitUntilRequestsCompleted(); // Verify listener was unregistered. mSensor.sendProximityResult(true); @@ -85,7 +85,7 @@ public class AsyncSensorManagerTest extends SysuiTestCase { mAsyncSensorManager.registerListener(mListener, mSensor.getSensor(), 100); mAsyncSensorManager.unregisterListener(mListener, mSensor.getSensor()); - mAsyncSensorManager.waitUntilRequestsCompleted(); + waitUntilRequestsCompleted(); // Verify listener was unregistered. mSensor.sendProximityResult(true); @@ -98,13 +98,7 @@ public class AsyncSensorManagerTest extends SysuiTestCase { eq(SensorManagerPlugin.class), eq(true) /* allowMultiple */); } - private class TestableAsyncSensorManager extends AsyncSensorManager { - public TestableAsyncSensorManager(SensorManager sensorManager) { - super(sensorManager, mPluginManager); - } - - public void waitUntilRequestsCompleted() { - assertTrue(mHandler.runWithScissors(() -> {}, 0)); - } + public void waitUntilRequestsCompleted() { + TestableLooper.get(this).processAllMessages(); } -}
\ No newline at end of file +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/hardware/FakeSensorManager.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeSensorManager.java index 29b8ab600caf..1deb495b5250 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/utils/hardware/FakeSensorManager.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeSensorManager.java @@ -11,10 +11,10 @@ * 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 + * limitations under the License. */ -package com.android.systemui.utils.hardware; +package com.android.systemui.util.sensors; import android.content.Context; import android.hardware.HardwareBuffer; @@ -54,7 +54,7 @@ public class FakeSensorManager extends SensorManager { public static final String TAP_SENSOR_TYPE = "tapSensorType"; - private final MockProximitySensor mMockProximitySensor; + private final FakeProximitySensor mFakeProximitySensor; private final FakeGenericSensor mFakeLightSensor; private final FakeGenericSensor mFakeTapSensor; private final FakeGenericSensor[] mSensors; @@ -68,14 +68,14 @@ public class FakeSensorManager extends SensorManager { } mSensors = new FakeGenericSensor[]{ - mMockProximitySensor = new MockProximitySensor(proxSensor), + mFakeProximitySensor = new FakeProximitySensor(proxSensor), mFakeLightSensor = new FakeGenericSensor(createSensor(Sensor.TYPE_LIGHT, null)), mFakeTapSensor = new FakeGenericSensor(createSensor(99, TAP_SENSOR_TYPE)) }; } - public MockProximitySensor getMockProximitySensor() { - return mMockProximitySensor; + public FakeProximitySensor getFakeProximitySensor() { + return mFakeProximitySensor; } public FakeGenericSensor getFakeLightSensor() { @@ -231,9 +231,9 @@ public class FakeSensorManager extends SensorManager { setter.invoke(sensor, type); } - public class MockProximitySensor extends FakeGenericSensor { + public class FakeProximitySensor extends FakeGenericSensor { - private MockProximitySensor(Sensor sensor) { + private FakeProximitySensor(Sensor sensor) { super(sensor); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorTest.java new file mode 100644 index 000000000000..6d13408058cc --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorTest.java @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2019 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.util.sensors; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import android.os.Handler; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class ProximitySensorTest extends SysuiTestCase { + + private ProximitySensor mProximitySensor; + private FakeSensorManager.FakeProximitySensor mFakeProximitySensor; + + @Before + public void setUp() throws Exception { + FakeSensorManager sensorManager = new FakeSensorManager(getContext()); + AsyncSensorManager asyncSensorManager = new AsyncSensorManager( + sensorManager, null, new Handler()); + mFakeProximitySensor = sensorManager.getFakeProximitySensor(); + mProximitySensor = new ProximitySensor(getContext(), asyncSensorManager, null); + } + + @Test + public void testSingleListener() { + TestableListener listener = new TestableListener(); + + assertFalse(mProximitySensor.isRegistered()); + mProximitySensor.register(listener); + waitForSensorManager(); + assertTrue(mProximitySensor.isRegistered()); + assertNull(listener.mLastEvent); + + mFakeProximitySensor.sendProximityResult(true); + assertFalse(listener.mLastEvent.getNear()); + assertEquals(listener.mCallCount, 1); + mFakeProximitySensor.sendProximityResult(false); + assertTrue(listener.mLastEvent.getNear()); + assertEquals(listener.mCallCount, 2); + + mProximitySensor.unregister(listener); + waitForSensorManager(); + } + + @Test + public void testMultiListener() { + TestableListener listenerA = new TestableListener(); + TestableListener listenerB = new TestableListener(); + + assertFalse(mProximitySensor.isRegistered()); + + mProximitySensor.register(listenerA); + waitForSensorManager(); + assertTrue(mProximitySensor.isRegistered()); + mProximitySensor.register(listenerB); + waitForSensorManager(); + assertTrue(mProximitySensor.isRegistered()); + assertNull(listenerA.mLastEvent); + assertNull(listenerB.mLastEvent); + + mFakeProximitySensor.sendProximityResult(true); + assertFalse(listenerA.mLastEvent.getNear()); + assertFalse(listenerB.mLastEvent.getNear()); + assertEquals(listenerA.mCallCount, 1); + assertEquals(listenerB.mCallCount, 1); + mFakeProximitySensor.sendProximityResult(false); + assertTrue(listenerA.mLastEvent.getNear()); + assertTrue(listenerB.mLastEvent.getNear()); + assertEquals(listenerA.mCallCount, 2); + assertEquals(listenerB.mCallCount, 2); + + mProximitySensor.unregister(listenerA); + mProximitySensor.unregister(listenerB); + waitForSensorManager(); + } + + @Test + public void testUnregister() { + TestableListener listener = new TestableListener(); + + assertFalse(mProximitySensor.isRegistered()); + mProximitySensor.register(listener); + waitForSensorManager(); + assertTrue(mProximitySensor.isRegistered()); + assertNull(listener.mLastEvent); + + mFakeProximitySensor.sendProximityResult(true); + assertFalse(listener.mLastEvent.getNear()); + assertEquals(listener.mCallCount, 1); + + mProximitySensor.unregister(listener); + waitForSensorManager(); + assertFalse(mProximitySensor.isRegistered()); + } + + @Test + public void testPauseAndResume() { + TestableListener listener = new TestableListener(); + + assertFalse(mProximitySensor.isRegistered()); + mProximitySensor.register(listener); + waitForSensorManager(); + assertTrue(mProximitySensor.isRegistered()); + assertNull(listener.mLastEvent); + + mFakeProximitySensor.sendProximityResult(true); + assertFalse(listener.mLastEvent.getNear()); + assertEquals(listener.mCallCount, 1); + + mProximitySensor.pause(); + waitForSensorManager(); + assertFalse(mProximitySensor.isRegistered()); + + // More events do nothing when paused. + mFakeProximitySensor.sendProximityResult(true); + assertFalse(listener.mLastEvent.getNear()); + assertEquals(listener.mCallCount, 1); + mFakeProximitySensor.sendProximityResult(false); + assertFalse(listener.mLastEvent.getNear()); + assertEquals(listener.mCallCount, 1); + + mProximitySensor.resume(); + waitForSensorManager(); + assertTrue(mProximitySensor.isRegistered()); + // Still matches our previous call + assertFalse(listener.mLastEvent.getNear()); + assertEquals(listener.mCallCount, 1); + + mFakeProximitySensor.sendProximityResult(true); + assertFalse(listener.mLastEvent.getNear()); + assertEquals(listener.mCallCount, 2); + + mProximitySensor.unregister(listener); + waitForSensorManager(); + assertFalse(mProximitySensor.isRegistered()); + } + + @Test + public void testAlertListeners() { + TestableListener listenerA = new TestableListener(); + TestableListener listenerB = new TestableListener(); + + assertFalse(mProximitySensor.isRegistered()); + + mProximitySensor.register(listenerA); + mProximitySensor.register(listenerB); + waitForSensorManager(); + assertTrue(mProximitySensor.isRegistered()); + assertNull(listenerA.mLastEvent); + assertNull(listenerB.mLastEvent); + + mProximitySensor.alertListeners(); + assertNull(listenerA.mLastEvent); + assertEquals(listenerA.mCallCount, 1); + assertNull(listenerB.mLastEvent); + assertEquals(listenerB.mCallCount, 1); + + mFakeProximitySensor.sendProximityResult(false); + assertTrue(listenerA.mLastEvent.getNear()); + assertEquals(listenerA.mCallCount, 2); + assertTrue(listenerB.mLastEvent.getNear()); + assertEquals(listenerB.mCallCount, 2); + + mProximitySensor.unregister(listenerA); + mProximitySensor.unregister(listenerB); + waitForSensorManager(); + } + + class TestableListener implements ProximitySensor.ProximitySensorListener { + ProximitySensor.ProximityEvent mLastEvent; + int mCallCount = 0; + + @Override + public void onSensorEvent(ProximitySensor.ProximityEvent proximityEvent) { + mLastEvent = proximityEvent; + mCallCount++; + } + + void reset() { + mLastEvent = null; + mCallCount = 0; + } + }; + + private void waitForSensorManager() { + TestableLooper.get(this).processAllMessages(); + } + +} diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto index 8ad24894a1b9..353a18756ca2 100644 --- a/proto/src/wifi.proto +++ b/proto/src/wifi.proto @@ -1792,6 +1792,25 @@ message ExperimentValues { // Indicates if we are logging LinkSpeedCount in metrics optional bool link_speed_counts_logging_enabled = 4; + + // Duration for evaluating Wifi condition to trigger a data stall + // measured in milliseconds + optional int32 data_stall_duration_ms = 5; + + // Threshold of Tx throughput below which to trigger a data stall + // measured in Mbps + optional int32 data_stall_tx_tput_thr_mbps = 6; + + // Threshold of Rx throughput below which to trigger a data stall + // measured in Mbps + optional int32 data_stall_rx_tput_thr_mbps = 7; + + // Threshold of Tx packet error rate above which to trigger a data stall + // in percentage + optional int32 data_stall_tx_per_thr = 8; + + // Threshold of CCA level above which to trigger a data stall in percentage + optional int32 data_stall_cca_level_thr = 9; } message WifiIsUnusableEvent { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 217a6c674cdc..3c7cb88174e1 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -5265,11 +5265,14 @@ public class ActivityManagerService extends IActivityManager.Stub // Inform checkpointing systems of success try { + // This line is needed to CTS test for the correct exception handling + // See b/138952436#comment36 for context + Slog.i(TAG, "About to commit checkpoint"); IStorageManager storageManager = PackageHelper.getStorageManager(); storageManager.commitChanges(); } catch (Exception e) { PowerManager pm = (PowerManager) - mContext.getSystemService(Context.POWER_SERVICE); + mInjector.getContext().getSystemService(Context.POWER_SERVICE); pm.reboot("Checkpoint commit failed"); } diff --git a/services/core/java/com/android/server/am/MemoryStatUtil.java b/services/core/java/com/android/server/am/MemoryStatUtil.java index e73abd17cc07..fd64df9e86e0 100644 --- a/services/core/java/com/android/server/am/MemoryStatUtil.java +++ b/services/core/java/com/android/server/am/MemoryStatUtil.java @@ -63,8 +63,6 @@ public final class MemoryStatUtil { private static final Pattern CACHE_IN_BYTES = Pattern.compile("total_cache (\\d+)"); private static final Pattern SWAP_IN_BYTES = Pattern.compile("total_swap (\\d+)"); - private static final Pattern RSS_HIGH_WATERMARK_IN_KILOBYTES = - Pattern.compile("VmHWM:\\s*(\\d+)\\s*kB"); private static final Pattern PROCFS_RSS_IN_KILOBYTES = Pattern.compile("VmRSS:\\s*(\\d+)\\s*kB"); private static final Pattern PROCFS_ANON_RSS_IN_KILOBYTES = @@ -113,15 +111,6 @@ public final class MemoryStatUtil { } /** - * Reads RSS high-water mark of a process from procfs. Returns value of the VmHWM field in - * /proc/PID/status in kilobytes or 0 if not available. - */ - public static int readRssHighWaterMarkFromProcfs(int pid) { - final String statusPath = String.format(Locale.US, PROC_STATUS_FILE_FMT, pid); - return parseVmHWMFromProcfs(readFileContents(statusPath)); - } - - /** * Reads cmdline of a process from procfs. * * Returns content of /proc/pid/cmdline (e.g. /system/bin/statsd) or an empty string @@ -204,19 +193,6 @@ public final class MemoryStatUtil { } /** - * Parses RSS high-water mark out from the contents of the /proc/pid/status file in procfs. The - * returned value is in kilobytes. - */ - @VisibleForTesting - static int parseVmHWMFromProcfs(String procStatusContents) { - if (procStatusContents == null || procStatusContents.isEmpty()) { - return 0; - } - return (int) tryParseLong(RSS_HIGH_WATERMARK_IN_KILOBYTES, procStatusContents); - } - - - /** * Parses cmdline out of the contents of the /proc/pid/cmdline file in procfs. * * Parsing is required to strip anything after first null byte. diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java index 09f52860e069..96af74a60b1d 100644 --- a/services/core/java/com/android/server/camera/CameraServiceProxy.java +++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java @@ -79,7 +79,7 @@ public class CameraServiceProxy extends SystemService private static final int MSG_SWITCH_USER = 1; private static final int RETRY_DELAY_TIME = 20; //ms - private static final int RETRY_TIMES = 30; + private static final int RETRY_TIMES = 60; // Maximum entries to keep in usage history before dumping out private static final int MAX_USAGE_HISTORY = 100; diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index 3482e92a6fbd..1cea4ca1b945 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -301,7 +301,7 @@ public class StagingManager { // Greedily re-trigger the pre-reboot verification. Slog.d(TAG, "Found pending staged session " + session.sessionId + " still to be " + "verified, resuming pre-reboot verification"); - mPreRebootVerificationHandler.startPreRebootVerification(session); + mPreRebootVerificationHandler.startPreRebootVerification(session.sessionId); return; } if (!apexSessionInfo.isActivated && !apexSessionInfo.isSuccess) { @@ -429,7 +429,7 @@ public class StagingManager { return; } mPreRebootVerificationHandler.notifyPreRebootVerification_Apk_Complete( - originalSession); + originalSession.sessionId); }); apkSession.commit(receiver.getIntentSender(), false); return; @@ -526,7 +526,7 @@ public class StagingManager { void commitSession(@NonNull PackageInstallerSession session) { updateStoredSession(session); - mPreRebootVerificationHandler.startPreRebootVerification(session); + mPreRebootVerificationHandler.startPreRebootVerification(session.sessionId); } @Nullable @@ -653,7 +653,7 @@ public class StagingManager { if (!session.isStagedSessionReady()) { // The framework got restarted before the pre-reboot verification could complete, // restart the verification. - mPreRebootVerificationHandler.startPreRebootVerification(session); + mPreRebootVerificationHandler.startPreRebootVerification(session.sessionId); } else { // Session had already being marked ready. Start the checks to verify if there is any // follow-up work. @@ -737,7 +737,16 @@ public class StagingManager { @Override public void handleMessage(Message msg) { - PackageInstallerSession session = (PackageInstallerSession) msg.obj; + final int sessionId = msg.arg1; + final PackageInstallerSession session; + synchronized (mStagedSessions) { + session = mStagedSessions.get(sessionId); + } + // Maybe session was aborted before pre-reboot verification was complete + if (session == null) { + Slog.d(TAG, "Stopping pre-reboot verification for sessionId: " + sessionId); + return; + } switch (msg.what) { case MSG_PRE_REBOOT_VERIFICATION_START: handlePreRebootVerification_Start(session); @@ -755,20 +764,20 @@ public class StagingManager { } // Method for starting the pre-reboot verification - private void startPreRebootVerification(PackageInstallerSession session) { - obtainMessage(MSG_PRE_REBOOT_VERIFICATION_START, session).sendToTarget(); + private void startPreRebootVerification(int sessionId) { + obtainMessage(MSG_PRE_REBOOT_VERIFICATION_START, sessionId, 0).sendToTarget(); } - private void notifyPreRebootVerification_Start_Complete(PackageInstallerSession session) { - obtainMessage(MSG_PRE_REBOOT_VERIFICATION_APEX, session).sendToTarget(); + private void notifyPreRebootVerification_Start_Complete(int sessionId) { + obtainMessage(MSG_PRE_REBOOT_VERIFICATION_APEX, sessionId, 0).sendToTarget(); } - private void notifyPreRebootVerification_Apex_Complete(PackageInstallerSession session) { - obtainMessage(MSG_PRE_REBOOT_VERIFICATION_APK, session).sendToTarget(); + private void notifyPreRebootVerification_Apex_Complete(int sessionId) { + obtainMessage(MSG_PRE_REBOOT_VERIFICATION_APK, sessionId, 0).sendToTarget(); } - private void notifyPreRebootVerification_Apk_Complete(PackageInstallerSession session) { - obtainMessage(MSG_PRE_REBOOT_VERIFICATION_END, session).sendToTarget(); + private void notifyPreRebootVerification_Apk_Complete(int sessionId) { + obtainMessage(MSG_PRE_REBOOT_VERIFICATION_END, sessionId, 0).sendToTarget(); } /** @@ -778,7 +787,7 @@ public class StagingManager { */ private void handlePreRebootVerification_Start(@NonNull PackageInstallerSession session) { Slog.d(TAG, "Starting preRebootVerification for session " + session.sessionId); - notifyPreRebootVerification_Start_Complete(session); + notifyPreRebootVerification_Start_Complete(session.sessionId); } /** @@ -808,7 +817,7 @@ public class StagingManager { } } - notifyPreRebootVerification_Apex_Complete(session); + notifyPreRebootVerification_Apex_Complete(session.sessionId); } /** @@ -819,7 +828,7 @@ public class StagingManager { */ private void handlePreRebootVerification_Apk(@NonNull PackageInstallerSession session) { if (!sessionContainsApk(session)) { - notifyPreRebootVerification_Apk_Complete(session); + notifyPreRebootVerification_Apk_Complete(session.sessionId); return; } diff --git a/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java b/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java new file mode 100644 index 000000000000..3076284a80ed --- /dev/null +++ b/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2017 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.server.stats; + +import android.os.FileUtils; +import android.util.Slog; + +import com.android.internal.annotations.VisibleForTesting; + +import java.io.File; +import java.io.IOException; +import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +final class ProcfsMemoryUtil { + private static final String TAG = "ProcfsMemoryUtil"; + + /** Path to procfs status file: /proc/pid/status. */ + private static final String STATUS_FILE_FMT = "/proc/%d/status"; + + private static final Pattern RSS_HIGH_WATER_MARK_IN_KILOBYTES = + Pattern.compile("VmHWM:\\s*(\\d+)\\s*kB"); + + private ProcfsMemoryUtil() {} + + /** + * Reads RSS high-water mark of a process from procfs. Returns value of the VmHWM field in + * /proc/PID/status in kilobytes or 0 if not available. + */ + static int readRssHighWaterMarkFromProcfs(int pid) { + final String statusPath = String.format(Locale.US, STATUS_FILE_FMT, pid); + return parseVmHWMFromStatus(readFile(statusPath)); + } + + /** + * Parses RSS high-water mark out from the contents of the /proc/pid/status file in procfs. The + * returned value is in kilobytes. + */ + @VisibleForTesting + static int parseVmHWMFromStatus(String contents) { + if (contents.isEmpty()) { + return 0; + } + final Matcher matcher = RSS_HIGH_WATER_MARK_IN_KILOBYTES.matcher(contents); + try { + return matcher.find() ? Integer.parseInt(matcher.group(1)) : 0; + } catch (NumberFormatException e) { + Slog.e(TAG, "Failed to parse value", e); + return 0; + } + } + + private static String readFile(String path) { + try { + final File file = new File(path); + return FileUtils.readTextFile(file, 0 /* max */, null /* ellipsis */); + } catch (IOException e) { + return ""; + } + } +} diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index e92abfddac8f..19b80556a779 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -27,9 +27,9 @@ import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.server.am.MemoryStatUtil.readCmdlineFromProcfs; import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem; import static com.android.server.am.MemoryStatUtil.readMemoryStatFromProcfs; -import static com.android.server.am.MemoryStatUtil.readRssHighWaterMarkFromProcfs; import static com.android.server.stats.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs; import static com.android.server.stats.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs; +import static com.android.server.stats.ProcfsMemoryUtil.readRssHighWaterMarkFromProcfs; import android.annotation.NonNull; import android.annotation.Nullable; diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index 5f98d1d54a24..59f051bc76a6 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -1106,14 +1106,10 @@ final class AccessibilityController { private final Point mTempPoint = new Point(); - private final Rect mTempRect = new Rect(); - private final Region mTempRegion = new Region(); private final Region mTempRegion1 = new Region(); - private final Context mContext; - private final WindowManagerService mService; private final Handler mHandler; @@ -1127,7 +1123,6 @@ final class AccessibilityController { public WindowsForAccessibilityObserver(WindowManagerService windowManagerService, int displayId, WindowsForAccessibilityCallback callback) { - mContext = windowManagerService.mContext; mService = windowManagerService; mCallback = callback; mDisplayId = displayId; diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 7a667315c6c3..c54ccd4d6844 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -2202,7 +2202,9 @@ final class ActivityRecord extends ConfigurationContainer { stack.removeTimeoutsForActivity(this); // Clean-up activities are no longer relaunching (e.g. app process died). Notify window // manager so it can update its bookkeeping. - mAtmService.mWindowManager.notifyAppRelaunchesCleared(appToken); + if (mAppWindowToken != null) { + mAppWindowToken.clearRelaunching(); + } } /** @@ -2961,6 +2963,11 @@ final class ActivityRecord extends ConfigurationContainer { if (display != null) { display.handleActivitySizeCompatModeIfNeeded(r); } + + if (r.mAppWindowToken != null) { + r.mAppWindowToken.getDisplayContent().mUnknownAppVisibilityController + .notifyAppResumedFinished(r.mAppWindowToken); + } } /** @@ -4311,7 +4318,9 @@ final class ActivityRecord extends ConfigurationContainer { "Moving to " + (andResume ? "RESUMED" : "PAUSED") + " Relaunching " + this + " callers=" + Debug.getCallers(6)); forceNewConfig = false; - mStackSupervisor.activityRelaunchingLocked(this); + if (mAppWindowToken != null) { + mAppWindowToken.startRelaunching(); + } final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(pendingResults, pendingNewIntents, configChangeFlags, new MergedConfiguration(mAtmService.getGlobalConfiguration(), diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index 7ee210edf1a8..2ab3e01278e9 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -4941,12 +4941,6 @@ class ActivityStack extends ConfigurationContainer { } } - - Rect getDefaultPictureInPictureBounds(float aspectRatio) { - if (getTaskStack() == null) return null; - return getTaskStack().getPictureInPictureBounds(aspectRatio, null /* currentStackBounds */); - } - void animateResizePinnedStack(Rect sourceHintBounds, Rect toBounds, int animationDuration, boolean fromFullscreen) { if (!inPinnedWindowingMode()) return; diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index 1aa1d483f707..d151f86ff810 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -2480,19 +2480,17 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { } void activityRelaunchedLocked(IBinder token) { - mWindowManager.notifyAppRelaunchingFinished(token); final ActivityRecord r = ActivityRecord.isInStackLocked(token); if (r != null) { + if (r.mAppWindowToken != null) { + r.mAppWindowToken.finishRelaunching(); + } if (r.getActivityStack().shouldSleepOrShutDownActivities()) { r.setSleeping(true, true); } } } - void activityRelaunchingLocked(ActivityRecord r) { - mWindowManager.notifyAppRelaunching(r.appToken); - } - void logStackState() { mActivityMetricsLogger.logWindowState(); } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 2f7acba595c2..468a13d45d55 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -47,7 +47,6 @@ import static android.content.pm.PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_ import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT; import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE; import static android.content.pm.PackageManager.PERMISSION_GRANTED; -import static android.content.res.Configuration.UI_MODE_TYPE_TELEVISION; import static android.os.FactoryTest.FACTORY_TEST_HIGH_LEVEL; import static android.os.FactoryTest.FACTORY_TEST_LOW_LEVEL; import static android.os.FactoryTest.FACTORY_TEST_OFF; @@ -550,7 +549,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { /** The dimensions of the thumbnails in the Recents UI. */ private int mThumbnailWidth; private int mThumbnailHeight; - private float mFullscreenThumbnailScale; /** * Flag that indicates if multi-window is enabled. @@ -790,15 +788,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { com.android.internal.R.dimen.thumbnail_width); mThumbnailHeight = res.getDimensionPixelSize( com.android.internal.R.dimen.thumbnail_height); - - if ((globalConfig.uiMode & UI_MODE_TYPE_TELEVISION) == UI_MODE_TYPE_TELEVISION) { - mFullscreenThumbnailScale = (float) res - .getInteger(com.android.internal.R.integer.thumbnail_width_tv) / - (float) globalConfig.screenWidthDp; - } else { - mFullscreenThumbnailScale = res.getFraction( - com.android.internal.R.fraction.thumbnail_fullscreen_scale, 1, 1); - } } } @@ -1697,7 +1686,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final long origId = Binder.clearCallingIdentity(); synchronized (mGlobalLock) { ActivityRecord.activityResumedLocked(token); - mWindowManager.notifyAppResumedFinished(token); } Binder.restoreCallingIdentity(origId); } @@ -2920,7 +2908,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mAmInternal.enforceCallingPermission(Manifest.permission.UPDATE_LOCK_TASK_PACKAGES, "updateLockTaskPackages()"); } - synchronized (this) { + synchronized (mGlobalLock) { if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Whitelisting " + userId + ":" + Arrays.toString(packages)); getLockTaskController().updateLockTaskPackages(userId, packages); @@ -5365,7 +5353,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final float scaleFactor = Settings.System.getFloatForUser(mContext.getContentResolver(), FONT_SCALE, 1.0f, userId); - synchronized (this) { + synchronized (mGlobalLock) { if (getGlobalConfiguration().fontScale == scaleFactor) { return; } diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index 557a609dbc7b..66d52cc9bf5a 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -1999,8 +1999,8 @@ public class AppTransition implements Dump { mNextAppTransitionFutureCallback, null /* finishedCallback */, mNextAppTransitionScaleUp); mNextAppTransitionFutureCallback = null; + mService.requestTraversal(); } - mService.requestTraversal(); }); } } diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 93b8f0022f79..f647fe46f067 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -955,6 +955,9 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree updateReportedVisibilityLocked(); } + // Reset the last saved PiP snap fraction on removal. + mDisplayContent.mPinnedStackControllerLocked.resetReentrySnapFraction(mActivityComponent); + mRemovingFromDisplay = false; } @@ -1021,7 +1024,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppStopped: " + this); mAppStopped = true; // Reset the last saved PiP snap fraction on app stop. - mDisplayContent.mPinnedStackControllerLocked.resetReentrySnapFraction(this); + mDisplayContent.mPinnedStackControllerLocked.resetReentrySnapFraction(mActivityComponent); destroySurfaces(); // Remove any starting window that was added for this app if they are still around. removeStartingWindow(); @@ -1705,10 +1708,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree return; } - if (prevWinMode != WINDOWING_MODE_UNDEFINED && winMode == WINDOWING_MODE_PINNED) { - // Entering PiP from fullscreen, reset the snap fraction - mDisplayContent.mPinnedStackControllerLocked.resetReentrySnapFraction(this); - } else if (prevWinMode == WINDOWING_MODE_PINNED && winMode != WINDOWING_MODE_UNDEFINED + if (prevWinMode == WINDOWING_MODE_PINNED && winMode != WINDOWING_MODE_UNDEFINED && !isHidden()) { // Leaving PiP to fullscreen, save the snap fraction based on the pre-animation bounds // for the next re-entry into PiP (assuming the activity is not hidden or destroyed) @@ -1726,8 +1726,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree stackBounds = mTmpRect; pinnedStack.getBounds(stackBounds); } - mDisplayContent.mPinnedStackControllerLocked.saveReentrySnapFraction(this, - stackBounds); + mDisplayContent.mPinnedStackControllerLocked.saveReentrySnapFraction( + mActivityComponent, stackBounds); } } else if (shouldStartChangeTransition(prevWinMode, winMode)) { initializeChangeTransition(mTmpPrevBounds); diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index f2ad56a8fdfa..94119e8b7bc7 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -2167,7 +2167,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo * so only need to configure display. */ void setForcedDensity(int density, int userId) { - final boolean clear = density == mInitialDisplayDensity; final boolean updateCurrent = userId == UserHandle.USER_CURRENT; if (mWmService.mCurrentUserId == userId || updateCurrent) { mBaseDisplayDensity = density; @@ -3884,21 +3883,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } } - private static final class ScreenshotApplicationState { - WindowState appWin; - int maxLayer; - int minLayer; - boolean screenshotReady; - - void reset(boolean screenshotReady) { - appWin = null; - maxLayer = 0; - minLayer = 0; - this.screenshotReady = screenshotReady; - minLayer = (screenshotReady) ? 0 : Integer.MAX_VALUE; - } - } - /** * Base class for any direct child window container of {@link #DisplayContent} need to inherit * from. This is mainly a pass through class that allows {@link #DisplayContent} to have diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 4dbb0092140c..10d48c4d5282 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -335,7 +335,6 @@ public class DisplayPolicy { private static final Rect sTmpDisplayCutoutSafeExceptMaybeBarsRect = new Rect(); private static final Rect sTmpRect = new Rect(); - private static final Rect sTmpDockedFrame = new Rect(); private static final Rect sTmpNavFrame = new Rect(); private static final Rect sTmpLastParentFrame = new Rect(); diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java index 120ce3eb146e..ae3b5f2f70d3 100644 --- a/services/core/java/com/android/server/wm/DockedStackDividerController.java +++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java @@ -36,7 +36,6 @@ import static com.android.server.wm.AppTransition.TOUCH_RESPONSE_INTERPOLATOR; import static com.android.server.wm.DockedStackDividerControllerProto.MINIMIZED_DOCK; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; -import static com.android.server.wm.WindowManagerService.LAYER_OFFSET_DIM; import android.content.Context; import android.content.res.Configuration; @@ -141,8 +140,6 @@ public class DockedStackDividerController { float mLastDividerProgress; private final DividerSnapAlgorithm[] mSnapAlgorithmForRotation = new DividerSnapAlgorithm[4]; private boolean mImeHideRequested; - private final Rect mLastDimLayerRect = new Rect(); - private float mLastDimLayerAlpha; private TaskStack mDimmedStack; DockedStackDividerController(WindowManagerService service, DisplayContent displayContent) { @@ -656,14 +653,6 @@ public class DockedStackDividerController { } /** - * @return The layer used for dimming the apps when dismissing docked/fullscreen stack. Just - * above all application surfaces. - */ - private int getResizeDimLayer() { - return (mWindow != null) ? mWindow.mLayer - 1 : LAYER_OFFSET_DIM; - } - - /** * Notifies the docked stack divider controller of a visibility change that happens without * an animation. */ diff --git a/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java b/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java index 20a13334e564..c5c236416013 100644 --- a/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java +++ b/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java @@ -16,7 +16,6 @@ package com.android.server.wm; -import android.app.ActivityManager; import android.app.ActivityTaskManager; import android.app.UriGrantsManager; import android.content.ClipData; diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java index d528ef6ec6a5..2b5eb3ac29fb 100644 --- a/services/core/java/com/android/server/wm/KeyguardController.java +++ b/services/core/java/com/android/server/wm/KeyguardController.java @@ -71,7 +71,6 @@ class KeyguardController { private boolean mAodShowing; private boolean mKeyguardGoingAway; private boolean mDismissalRequested; - private int[] mSecondaryDisplayIdsShowing; private int mBeforeUnoccludeTransit; private int mVisibilityTransactionDepth; private final SparseArray<KeyguardDisplayState> mDisplayStates = new SparseArray<>(); @@ -328,7 +327,7 @@ class KeyguardController { return; } - mWindowManager.onKeyguardOccludedChanged(isDisplayOccluded(DEFAULT_DISPLAY)); + mWindowManager.mPolicy.onKeyguardOccludedChangedLw(isDisplayOccluded(DEFAULT_DISPLAY)); if (isKeyguardLocked()) { mService.deferWindowLayout(); try { @@ -381,7 +380,7 @@ class KeyguardController { * @return true if Keyguard can be currently dismissed without entering credentials. */ boolean canDismissKeyguard() { - return mWindowManager.isKeyguardTrusted() + return mWindowManager.mPolicy.isKeyguardTrustedLw() || !mWindowManager.isKeyguardSecure(mService.getCurrentUserId()); } @@ -516,7 +515,8 @@ class KeyguardController { } // TODO(b/123372519): isShowingDream can only works on default display. if (mDisplayId == DEFAULT_DISPLAY) { - mOccluded |= controller.mWindowManager.isShowingDream(); + mOccluded |= mService.mRootActivityContainer.getDefaultDisplay().mDisplayContent + .getDisplayPolicy().isShowingDreamLw(); } if (lastOccluded != mOccluded) { diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java index ef0049b068f4..8e57fec6ba46 100644 --- a/services/core/java/com/android/server/wm/PinnedStackController.java +++ b/services/core/java/com/android/server/wm/PinnedStackController.java @@ -27,6 +27,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.annotation.NonNull; import android.app.RemoteAction; +import android.content.ComponentName; import android.content.pm.ParceledListSlice; import android.content.res.Resources; import android.graphics.Point; @@ -50,7 +51,6 @@ import com.android.internal.util.Preconditions; import com.android.server.UiThread; import java.io.PrintWriter; -import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; @@ -74,7 +74,7 @@ class PinnedStackController { private static final String TAG = TAG_WITH_CLASS_NAME ? "PinnedStackController" : TAG_WM; - public static final float INVALID_SNAP_FRACTION = -1f; + private static final float INVALID_SNAP_FRACTION = -1f; private final WindowManagerService mService; private final DisplayContent mDisplayContent; private final Handler mHandler = UiThread.getHandler(); @@ -106,9 +106,6 @@ class PinnedStackController { private int mDefaultStackGravity; private float mDefaultAspectRatio; private Point mScreenEdgeInsets; - private int mCurrentMinSize; - private float mReentrySnapFraction = INVALID_SNAP_FRACTION; - private WeakReference<AppWindowToken> mLastPipActivity = null; // The aspect ratio bounds of the PIP. private float mMinAspectRatio; @@ -118,7 +115,6 @@ class PinnedStackController { private final DisplayMetrics mTmpMetrics = new DisplayMetrics(); private final Rect mTmpInsets = new Rect(); private final Rect mTmpRect = new Rect(); - private final Rect mTmpAnimatingBoundsRect = new Rect(); private final Point mTmpDisplaySize = new Point(); @@ -136,16 +132,19 @@ class PinnedStackController { } @Override - public void setMinEdgeSize(int minEdgeSize) { - mHandler.post(() -> { - mCurrentMinSize = Math.max(mDefaultMinSize, minEdgeSize); - }); + public int getDisplayRotation() { + synchronized (mService.mGlobalLock) { + return mDisplayInfo.rotation; + } } @Override - public int getDisplayRotation() { + public void startAnimation(Rect destinationBounds, Rect sourceRectHint, + int animationDuration) { synchronized (mService.mGlobalLock) { - return mDisplayInfo.rotation; + final TaskStack pinnedStack = mDisplayContent.getPinnedStack(); + pinnedStack.animateResizePinnedStack(destinationBounds, + sourceRectHint, animationDuration, true /* fromFullscreen */); } } } @@ -188,7 +187,6 @@ class PinnedStackController { final Resources res = mService.mContext.getResources(); mDefaultMinSize = res.getDimensionPixelSize( com.android.internal.R.dimen.default_minimal_size_pip_resizable_task); - mCurrentMinSize = mDefaultMinSize; mDefaultAspectRatio = res.getFloat( com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio); final String screenEdgeInsetsDpString = res.getString( @@ -216,6 +214,7 @@ class PinnedStackController { listener.asBinder().linkToDeath(mPinnedStackListenerDeathHandler, 0); listener.onListenerRegistered(mCallbacks); mPinnedStackListener = listener; + notifyDisplayInfoChanged(mDisplayInfo); notifyImeVisibilityChanged(mIsImeShowing, mImeHeight); notifyShelfVisibilityChanged(mIsShelfShowing, mShelfHeight); // The movement bounds notification needs to be sent before the minimized state, since @@ -238,58 +237,34 @@ class PinnedStackController { } /** - * Returns the current bounds (or the default bounds if there are no current bounds) with the - * specified aspect ratio. - */ - Rect transformBoundsToAspectRatio(Rect stackBounds, float aspectRatio, - boolean useCurrentMinEdgeSize) { - // Save the snap fraction, calculate the aspect ratio based on screen size - final float snapFraction = mSnapAlgorithm.getSnapFraction(stackBounds, - getMovementBounds(stackBounds)); - - final int minEdgeSize = useCurrentMinEdgeSize ? mCurrentMinSize : mDefaultMinSize; - final Size size = mSnapAlgorithm.getSizeForAspectRatio(aspectRatio, minEdgeSize, - mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight); - final int left = (int) (stackBounds.centerX() - size.getWidth() / 2f); - final int top = (int) (stackBounds.centerY() - size.getHeight() / 2f); - stackBounds.set(left, top, left + size.getWidth(), top + size.getHeight()); - mSnapAlgorithm.applySnapFraction(stackBounds, getMovementBounds(stackBounds), snapFraction); - if (mIsMinimized) { - applyMinimizedOffset(stackBounds, getMovementBounds(stackBounds)); - } - return stackBounds; - } - - /** * Saves the current snap fraction for re-entry of the current activity into PiP. */ - void saveReentrySnapFraction(final AppWindowToken token, final Rect stackBounds) { - mReentrySnapFraction = getSnapFraction(stackBounds); - mLastPipActivity = new WeakReference<>(token); + void saveReentrySnapFraction(final ComponentName componentName, final Rect stackBounds) { + if (mPinnedStackListener == null) return; + try { + mPinnedStackListener.onSaveReentrySnapFraction(componentName, stackBounds); + } catch (RemoteException e) { + Slog.e(TAG_WM, "Error delivering save reentry fraction event.", e); + } } /** * Resets the last saved snap fraction so that the default bounds will be returned. */ - void resetReentrySnapFraction(AppWindowToken token) { - if (mLastPipActivity != null && mLastPipActivity.get() == token) { - mReentrySnapFraction = INVALID_SNAP_FRACTION; - mLastPipActivity = null; + void resetReentrySnapFraction(ComponentName componentName) { + if (mPinnedStackListener == null) return; + try { + mPinnedStackListener.onResetReentrySnapFraction(componentName); + } catch (RemoteException e) { + Slog.e(TAG_WM, "Error delivering reset reentry fraction event.", e); } } /** - * @return the default bounds to show the PIP when there is no active PIP. - */ - Rect getDefaultOrLastSavedBounds() { - return getDefaultBounds(mReentrySnapFraction); - } - - /** * @return the default bounds to show the PIP, if a {@param snapFraction} is provided, then it * will apply the default bounds to the provided snap fraction. */ - Rect getDefaultBounds(float snapFraction) { + private Rect getDefaultBounds(float snapFraction) { synchronized (mService.mGlobalLock) { final Rect insetBounds = new Rect(); getInsetBounds(insetBounds); @@ -311,13 +286,18 @@ class PinnedStackController { } } + private void setDisplayInfo(DisplayInfo displayInfo) { + mDisplayInfo.copyFrom(displayInfo); + notifyDisplayInfoChanged(mDisplayInfo); + } + /** * In the case where the display rotation is changed but there is no stack, we can't depend on * onTaskStackBoundsChanged() to be called. But we still should update our known display info * with the new state so that we can update SystemUI. */ synchronized void onDisplayInfoChanged(DisplayInfo displayInfo) { - mDisplayInfo.copyFrom(displayInfo); + setDisplayInfo(displayInfo); notifyMovementBoundsChanged(false /* fromImeAdjustment */, false /* fromShelfAdjustment */); } @@ -335,7 +315,7 @@ class PinnedStackController { } else if (targetBounds.isEmpty()) { // The stack is null, we are just initializing the stack, so just store the display // info and ignore - mDisplayInfo.copyFrom(displayInfo); + setDisplayInfo(displayInfo); outBounds.setEmpty(); return false; } @@ -345,7 +325,8 @@ class PinnedStackController { // Calculate the snap fraction of the current stack along the old movement bounds final float snapFraction = getSnapFraction(postChangeStackBounds); - mDisplayInfo.copyFrom(displayInfo); + + setDisplayInfo(displayInfo); // Calculate the stack bounds in the new orientation to the same same fraction along the // rotated movement bounds. @@ -406,8 +387,11 @@ class PinnedStackController { void setAspectRatio(float aspectRatio) { if (Float.compare(mAspectRatio, aspectRatio) != 0) { mAspectRatio = aspectRatio; + notifyAspectRatioChanged(aspectRatio); notifyMovementBoundsChanged(false /* fromImeAdjustment */, false /* fromShelfAdjustment */); + notifyPrepareAnimation(null /* sourceHintRect */, aspectRatio, + null /* stackBounds */); } } @@ -429,6 +413,10 @@ class PinnedStackController { notifyActionsChanged(mActions); } + void prepareAnimation(Rect sourceRectHint, float aspectRatio, Rect stackBounds) { + notifyPrepareAnimation(sourceRectHint, aspectRatio, stackBounds); + } + private boolean isSameDimensionAndRotation(@NonNull DisplayInfo display1, @NonNull DisplayInfo display2) { Preconditions.checkNotNull(display1); @@ -461,6 +449,15 @@ class PinnedStackController { } } + private void notifyAspectRatioChanged(float aspectRatio) { + if (mPinnedStackListener == null) return; + try { + mPinnedStackListener.onAspectRatioChanged(aspectRatio); + } catch (RemoteException e) { + Slog.e(TAG_WM, "Error delivering aspect ratio changed event.", e); + } + } + /** * Notifies listeners that the PIP minimized state has changed. */ @@ -497,23 +494,13 @@ class PinnedStackController { return; } try { - final Rect insetBounds = new Rect(); - getInsetBounds(insetBounds); - final Rect normalBounds = getDefaultBounds(INVALID_SNAP_FRACTION); - if (isValidPictureInPictureAspectRatio(mAspectRatio)) { - transformBoundsToAspectRatio(normalBounds, mAspectRatio, - false /* useCurrentMinEdgeSize */); - } - final Rect animatingBounds = mTmpAnimatingBoundsRect; + final Rect animatingBounds = new Rect(); final TaskStack pinnedStack = mDisplayContent.getPinnedStack(); if (pinnedStack != null) { pinnedStack.getAnimationOrCurrentBounds(animatingBounds); - } else { - animatingBounds.set(normalBounds); } - mPinnedStackListener.onMovementBoundsChanged(insetBounds, normalBounds, - animatingBounds, fromImeAdjustment, fromShelfAdjustment, - mDisplayInfo.rotation); + mPinnedStackListener.onMovementBoundsChanged(animatingBounds, + fromImeAdjustment, fromShelfAdjustment); } catch (RemoteException e) { Slog.e(TAG_WM, "Error delivering actions changed event.", e); } @@ -521,6 +508,30 @@ class PinnedStackController { } /** + * Notifies listeners that the PIP animation is about to happen. + */ + private void notifyDisplayInfoChanged(DisplayInfo displayInfo) { + if (mPinnedStackListener == null) return; + try { + mPinnedStackListener.onDisplayInfoChanged(displayInfo); + } catch (RemoteException e) { + Slog.e(TAG_WM, "Error delivering DisplayInfo changed event.", e); + } + } + + /** + * Notifies listeners that the PIP animation is about to happen. + */ + private void notifyPrepareAnimation(Rect sourceRectHint, float aspectRatio, Rect stackBounds) { + if (mPinnedStackListener == null) return; + try { + mPinnedStackListener.onPrepareAnimation(sourceRectHint, aspectRatio, stackBounds); + } catch (RemoteException e) { + Slog.e(TAG_WM, "Error delivering prepare animation event.", e); + } + } + + /** * @return the bounds on the screen that the PIP can be visible in. */ private void getInsetBounds(Rect outRect) { @@ -604,7 +615,6 @@ class PinnedStackController { pw.println(prefix + " mImeHeight=" + mImeHeight); pw.println(prefix + " mIsShelfShowing=" + mIsShelfShowing); pw.println(prefix + " mShelfHeight=" + mShelfHeight); - pw.println(prefix + " mReentrySnapFraction=" + mReentrySnapFraction); pw.println(prefix + " mIsMinimized=" + mIsMinimized); pw.println(prefix + " mAspectRatio=" + mAspectRatio); pw.println(prefix + " mMinAspectRatio=" + mMinAspectRatio); diff --git a/services/core/java/com/android/server/wm/PointerEventDispatcher.java b/services/core/java/com/android/server/wm/PointerEventDispatcher.java index 8d08aa370b44..6b8144c69079 100644 --- a/services/core/java/com/android/server/wm/PointerEventDispatcher.java +++ b/services/core/java/com/android/server/wm/PointerEventDispatcher.java @@ -28,13 +28,11 @@ import com.android.server.UiThread; import java.util.ArrayList; public class PointerEventDispatcher extends InputEventReceiver { - private final InputChannel mInputChannel; private final ArrayList<PointerEventListener> mListeners = new ArrayList<>(); private PointerEventListener[] mListenersArray = new PointerEventListener[0]; public PointerEventDispatcher(InputChannel inputChannel) { super(inputChannel, UiThread.getHandler().getLooper()); - mInputChannel = inputChannel; } @Override @@ -94,7 +92,6 @@ public class PointerEventDispatcher extends InputEventReceiver { @Override public void dispose() { super.dispose(); - mInputChannel.dispose(); synchronized (mListeners) { mListeners.clear(); mListenersArray = null; diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java index 6d46716dfd8f..734f2248d131 100644 --- a/services/core/java/com/android/server/wm/RootActivityContainer.java +++ b/services/core/java/com/android/server/wm/RootActivityContainer.java @@ -969,10 +969,6 @@ class RootActivityContainer extends ConfigurationContainer // Need to make sure the pinned stack exist so we can resize it below... stack = display.getOrCreateStack(WINDOWING_MODE_PINNED, r.getActivityType(), ON_TOP); - // Calculate the target bounds here before the task is reparented back into pinned windowing - // mode (which will reset the saved bounds) - final Rect destBounds = stack.getDefaultPictureInPictureBounds(aspectRatio); - try { final TaskRecord task = r.getTaskRecord(); // Resize the pinned stack to match the current size of the task the activity we are @@ -1011,9 +1007,14 @@ class RootActivityContainer extends ConfigurationContainer mService.continueWindowLayout(); } - stack.animateResizePinnedStack(sourceHintBounds, destBounds, -1 /* animationDuration */, - true /* fromFullscreen */); + // Notify the pinned stack controller to prepare the PiP animation, expect callback + // delivered from SystemUI to WM to start the animation. + final PinnedStackController pinnedStackController = + display.mDisplayContent.getPinnedStackController(); + pinnedStackController.prepareAnimation(sourceHintBounds, aspectRatio, + null /* stackBounds */); + // TODO: revisit the following statement after the animation is moved from WM to SysUI. // Update the visibility of all activities after the they have been reparented to the new // stack. This MUST run after the animation above is scheduled to ensure that the windows // drawn signal is scheduled after the bounds animation start call on the bounds animator diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index d0b6fc890ca0..4365d0325545 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -472,8 +472,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> final int count = mChildren.size(); for (int i = 0; i < count; ++i) { - final DisplayContent dc = mChildren.get(i); - final int pendingChanges = animator.getPendingLayoutChanges(dc.getDisplayId()); + final int pendingChanges = mChildren.get(i).pendingLayoutChanges; if ((pendingChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) { animator.mBulkUpdateParams |= SET_WALLPAPER_ACTION_PENDING; } diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java index cd211a28a908..ba728ba18d57 100644 --- a/services/core/java/com/android/server/wm/SurfaceAnimator.java +++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java @@ -54,6 +54,7 @@ class SurfaceAnimator { final Animatable mAnimatable; private final OnAnimationFinishedCallback mInnerAnimationFinishedCallback; @VisibleForTesting + @Nullable final Runnable mAnimationFinishedCallback; private boolean mAnimationStartDelayed; @@ -262,7 +263,7 @@ class SurfaceAnimator { if (!mAnimationStartDelayed && forwardCancel) { animation.onAnimationCancelled(leash); } - if (!restarting) { + if (!restarting && mAnimationFinishedCallback != null) { mAnimationFinishedCallback.run(); } } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 762066c1f80a..85ba80602bdb 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -85,8 +85,6 @@ class Task extends WindowContainer<AppWindowToken> implements ConfigurationConta private Rect mTmpRect = new Rect(); // For handling display rotations. private Rect mTmpRect2 = new Rect(); - // For retrieving dim bounds - private Rect mTmpRect3 = new Rect(); // Resize mode of the task. See {@link ActivityInfo#resizeMode} private int mResizeMode; diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java index 8b0b6ce8ce32..42866f97b4b8 100644 --- a/services/core/java/com/android/server/wm/TaskPositioner.java +++ b/services/core/java/com/android/server/wm/TaskPositioner.java @@ -64,10 +64,6 @@ class TaskPositioner implements IBinder.DeathRecipient { private static Factory sFactory; - // The margin the pointer position has to be within the side of the screen to be - // considered at the side of the screen. - static final int SIDE_MARGIN_DIP = 100; - @IntDef(flag = true, value = { CTRL_NONE, @@ -101,7 +97,6 @@ class TaskPositioner implements IBinder.DeathRecipient { private DisplayContent mDisplayContent; private final DisplayMetrics mDisplayMetrics = new DisplayMetrics(); private Rect mTmpRect = new Rect(); - private int mSideMargin; private int mMinVisibleWidth; private int mMinVisibleHeight; @@ -309,7 +304,6 @@ class TaskPositioner implements IBinder.DeathRecipient { // Notify InputMonitor to take mDragWindowHandle. mDisplayContent.getInputMonitor().updateInputWindowsLw(true /*force*/); - mSideMargin = dipToPixel(SIDE_MARGIN_DIP, mDisplayMetrics); mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, mDisplayMetrics); mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, mDisplayMetrics); display.getRealSize(mMaxVisibleSize); @@ -488,12 +482,6 @@ class TaskPositioner implements IBinder.DeathRecipient { int right = mWindowOriginalBounds.right; int bottom = mWindowOriginalBounds.bottom; - // The aspect which we have to respect. Note that if the orientation does not need to be - // preserved the aspect will be calculated as 1.0 which neutralizes the following - // computations. - final float minAspect = !mPreserveOrientation - ? 1.0f - : (mStartOrientationWasLandscape ? MIN_ASPECT : (1.0f / MIN_ASPECT)); // Calculate the resulting width and height of the drag operation. int width = right - left; int height = bottom - top; diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java index 4b3691c88a06..0ea108e30280 100644 --- a/services/core/java/com/android/server/wm/TaskRecord.java +++ b/services/core/java/com/android/server/wm/TaskRecord.java @@ -1085,8 +1085,8 @@ class TaskRecord extends ConfigurationContainer { clearRootProcess(); - // TODO: Use window container controller once tasks are better synced between AM and WM - mService.mWindowManager.notifyTaskRemovedFromRecents(taskId, userId); + mService.mWindowManager.mTaskSnapshotController.notifyTaskRemovedFromRecents( + taskId, userId); } void setTaskToAffiliateWith(TaskRecord taskToAffiliateWith) { diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index 239bd004705f..94651294da10 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -738,7 +738,6 @@ public class TaskStack extends WindowContainer<Task> implements // surface position. updateSurfaceSize(getPendingTransaction()); final int windowingMode = getWindowingMode(); - final boolean isAlwaysOnTop = isAlwaysOnTop(); if (mDisplayContent == null) { return; @@ -1661,40 +1660,6 @@ public class TaskStack extends WindowContainer<Task> implements } /** - * @return the current stack bounds transformed to the given {@param aspectRatio}. If - * the default bounds is {@code null}, then the {@param aspectRatio} is applied to the - * default bounds. - */ - Rect getPictureInPictureBounds(float aspectRatio, Rect stackBounds) { - if (!mWmService.mAtmService.mSupportsPictureInPicture) { - return null; - } - - final DisplayContent displayContent = getDisplayContent(); - if (displayContent == null) { - return null; - } - - if (!inPinnedWindowingMode()) { - return null; - } - - final PinnedStackController pinnedStackController = - displayContent.getPinnedStackController(); - if (stackBounds == null) { - // Calculate the aspect ratio bounds from the default bounds - stackBounds = pinnedStackController.getDefaultOrLastSavedBounds(); - } - - if (pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)) { - return pinnedStackController.transformBoundsToAspectRatio(stackBounds, aspectRatio, - true /* useCurrentMinEdgeSize */); - } else { - return stackBounds; - } - } - - /** * Animates the pinned stack. */ void animateResizePinnedStack(Rect toBounds, Rect sourceHintBounds, @@ -1771,6 +1736,11 @@ public class TaskStack extends WindowContainer<Task> implements return; } + final DisplayContent displayContent = getDisplayContent(); + if (displayContent == null) { + return; + } + if (!inPinnedWindowingMode()) { return; } @@ -1781,13 +1751,10 @@ public class TaskStack extends WindowContainer<Task> implements if (Float.compare(aspectRatio, pinnedStackController.getAspectRatio()) == 0) { return; } - getAnimationOrCurrentBounds(mTmpFromBounds); - mTmpToBounds.set(mTmpFromBounds); - getPictureInPictureBounds(aspectRatio, mTmpToBounds); - if (!mTmpToBounds.equals(mTmpFromBounds)) { - animateResizePinnedStack(mTmpToBounds, null /* sourceHintBounds */, - -1 /* duration */, false /* fromFullscreen */); - } + + // Notify the pinned stack controller about aspect ratio change. + // This would result a callback delivered from SystemUI to WM to start animation, + // if the bounds are ought to be altered due to aspect ratio change. pinnedStackController.setAspectRatio( pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio) ? aspectRatio : -1f); diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java index 614727263469..13902eedbfba 100644 --- a/services/core/java/com/android/server/wm/WallpaperController.java +++ b/services/core/java/com/android/server/wm/WallpaperController.java @@ -110,7 +110,6 @@ class WallpaperController { private final FindWallpaperTargetResult mFindResults = new FindWallpaperTargetResult(); private final ToBooleanFunction<WindowState> mFindWallpaperTargetFunction = w -> { - final WindowAnimator winAnimator = mService.mAnimator; if ((w.mAttrs.type == TYPE_WALLPAPER)) { if (mFindResults.topWallpaper == null || mFindResults.resetTopWallpaper) { mFindResults.setTopWallpaper(w); diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java index 4fce46b9dfaf..3bd1d560a42c 100644 --- a/services/core/java/com/android/server/wm/WindowAnimator.java +++ b/services/core/java/com/android/server/wm/WindowAnimator.java @@ -306,24 +306,6 @@ public class WindowAnimator { } } - int getPendingLayoutChanges(final int displayId) { - if (displayId < 0) { - return 0; - } - final DisplayContent displayContent = mService.mRoot.getDisplayContent(displayId); - return (displayContent != null) ? displayContent.pendingLayoutChanges : 0; - } - - void setPendingLayoutChanges(final int displayId, final int changes) { - if (displayId < 0) { - return; - } - final DisplayContent displayContent = mService.mRoot.getDisplayContent(displayId); - if (displayContent != null) { - displayContent.pendingLayoutChanges |= changes; - } - } - private DisplayContentsAnimator getDisplayContentsAnimatorLocked(int displayId) { if (displayId < 0) { return null; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 1ebaa5da5bef..14214b4be7d1 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -313,11 +313,6 @@ public class WindowManagerService extends IWindowManager.Stub static final int WINDOW_LAYER_MULTIPLIER = 5; /** - * Dim surface layer is immediately below target window. - */ - static final int LAYER_OFFSET_DIM = 1; - - /** * Animation thumbnail is as far as possible below the window above * the thumbnail (or in other words as far as possible above the window * below it). @@ -367,8 +362,6 @@ public class WindowManagerService extends IWindowManager.Stub private static final String DENSITY_OVERRIDE = "ro.config.density_override"; private static final String SIZE_OVERRIDE = "ro.config.size_override"; - private static final int MAX_SCREENSHOT_RETRIES = 3; - private static final String PROPERTY_EMULATOR_CIRCULAR = "ro.emulator.circular"; // Used to indicate that if there is already a transition set, it should be preserved when @@ -2064,13 +2057,11 @@ public class WindowManagerService extends IWindowManager.Stub final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); long origId = Binder.clearCallingIdentity(); - final int displayId; synchronized (mGlobalLock) { final WindowState win = windowForClientLocked(session, client, false); if (win == null) { return 0; } - displayId = win.getDisplayId(); final DisplayContent displayContent = win.getDisplayContent(); final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy(); @@ -2648,16 +2639,14 @@ public class WindowManagerService extends IWindowManager.Stub getDefaultDisplayContentLocked().executeAppTransition(); } - public void initializeRecentsAnimation(int targetActivityType, + void initializeRecentsAnimation(int targetActivityType, IRecentsAnimationRunner recentsAnimationRunner, RecentsAnimationController.RecentsAnimationCallbacks callbacks, int displayId, SparseBooleanArray recentTaskIds) { - synchronized (mGlobalLock) { - mRecentsAnimationController = new RecentsAnimationController(this, - recentsAnimationRunner, callbacks, displayId); - mRoot.getDisplayContent(displayId).mAppTransition.updateBooster(); - mRecentsAnimationController.initialize(targetActivityType, recentTaskIds); - } + mRecentsAnimationController = new RecentsAnimationController(this, recentsAnimationRunner, + callbacks, displayId); + mRoot.getDisplayContent(displayId).mAppTransition.updateBooster(); + mRecentsAnimationController.initialize(targetActivityType, recentTaskIds); } @VisibleForTesting @@ -2803,12 +2792,6 @@ public class WindowManagerService extends IWindowManager.Stub mAtmInternal.notifyKeyguardFlagsChanged(callback, displayId); } - public boolean isKeyguardTrusted() { - synchronized (mGlobalLock) { - return mPolicy.isKeyguardTrustedLw(); - } - } - public void setKeyguardGoingAway(boolean keyguardGoingAway) { synchronized (mGlobalLock) { mKeyguardGoingAway = keyguardGoingAway; @@ -2954,13 +2937,6 @@ public class WindowManagerService extends IWindowManager.Stub } } - public boolean isShowingDream() { - synchronized (mGlobalLock) { - // TODO(b/123372519): Fix this when dream can be shown on non-default display. - return getDefaultDisplayContentLocked().getDisplayPolicy().isShowingDreamLw(); - } - } - @Override public void dismissKeyguard(IKeyguardDismissCallback callback, CharSequence message) { if (!checkCallingPermission(permission.CONTROL_KEYGUARD, "dismissKeyguard")) { @@ -2971,12 +2947,6 @@ public class WindowManagerService extends IWindowManager.Stub } } - public void onKeyguardOccludedChanged(boolean occluded) { - synchronized (mGlobalLock) { - mPolicy.onKeyguardOccludedChangedLw(occluded); - } - } - @Override public void setSwitchingUser(boolean switching) { if (!checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL, @@ -5347,9 +5317,7 @@ public class WindowManagerService extends IWindowManager.Stub } void requestTraversal() { - synchronized (mGlobalLock) { - mWindowPlacerLocked.requestTraversal(); - } + mWindowPlacerLocked.requestTraversal(); } /** Note that Locked in this case is on mLayoutToAnim */ @@ -5817,55 +5785,6 @@ public class WindowManagerService extends IWindowManager.Stub } } - public void notifyAppRelaunching(IBinder token) { - synchronized (mGlobalLock) { - final AppWindowToken appWindow = mRoot.getAppWindowToken(token); - if (appWindow != null) { - appWindow.startRelaunching(); - } - } - } - - public void notifyAppRelaunchingFinished(IBinder token) { - synchronized (mGlobalLock) { - final AppWindowToken appWindow = mRoot.getAppWindowToken(token); - if (appWindow != null) { - appWindow.finishRelaunching(); - } - } - } - - public void notifyAppRelaunchesCleared(IBinder token) { - synchronized (mGlobalLock) { - final AppWindowToken appWindow = mRoot.getAppWindowToken(token); - if (appWindow != null) { - appWindow.clearRelaunching(); - } - } - } - - public void notifyAppResumedFinished(IBinder token) { - synchronized (mGlobalLock) { - final AppWindowToken appWindow = mRoot.getAppWindowToken(token); - if (appWindow != null) { - appWindow.getDisplayContent().mUnknownAppVisibilityController - .notifyAppResumedFinished(appWindow); - } - } - } - - /** - * Called when a task has been removed from the recent tasks list. - * <p> - * Note: This doesn't go through {@link TaskWindowContainerController} yet as the window - * container may not exist when this happens. - */ - public void notifyTaskRemovedFromRecents(int taskId, int userId) { - synchronized (mGlobalLock) { - mTaskSnapshotController.notifyTaskRemovedFromRecents(taskId, userId); - } - } - private void dumpPolicyLocked(PrintWriter pw, String[] args, boolean dumpAll) { pw.println("WINDOW MANAGER POLICY STATE (dumpsys window policy)"); mPolicy.dump(" ", pw, args); @@ -6375,16 +6294,6 @@ public class WindowManagerService extends IWindowManager.Stub } } - public void onDisplayChanged(int displayId) { - synchronized (mGlobalLock) { - final DisplayContent displayContent = mRoot.getDisplayContent(displayId); - if (displayContent != null) { - displayContent.updateDisplayInfo(); - } - mWindowPlacerLocked.requestTraversal(); - } - } - @Override public Object getWindowManagerLock() { return mGlobalLock; @@ -6395,21 +6304,18 @@ public class WindowManagerService extends IWindowManager.Stub * a window. * @param token Application token for which the activity will be relaunched. */ - public void setWillReplaceWindow(IBinder token, boolean animate) { - synchronized (mGlobalLock) { - final AppWindowToken appWindowToken = mRoot.getAppWindowToken(token); - if (appWindowToken == null) { - Slog.w(TAG_WM, "Attempted to set replacing window on non-existing app token " - + token); - return; - } - if (!appWindowToken.hasContentToDisplay()) { - Slog.w(TAG_WM, "Attempted to set replacing window on app token with no content" - + token); - return; - } - appWindowToken.setWillReplaceWindows(animate); + void setWillReplaceWindow(IBinder token, boolean animate) { + final AppWindowToken appWindowToken = mRoot.getAppWindowToken(token); + if (appWindowToken == null) { + Slog.w(TAG_WM, "Attempted to set replacing window on non-existing app token " + token); + return; + } + if (!appWindowToken.hasContentToDisplay()) { + Slog.w(TAG_WM, "Attempted to set replacing window on app token with no content" + + token); + return; } + appWindowToken.setWillReplaceWindows(animate); } /** @@ -6457,19 +6363,17 @@ public class WindowManagerService extends IWindowManager.Stub * @param token Application token for the activity whose window might be replaced. * @param replacing Whether the window is being replaced or not. */ - public void scheduleClearWillReplaceWindows(IBinder token, boolean replacing) { - synchronized (mGlobalLock) { - final AppWindowToken appWindowToken = mRoot.getAppWindowToken(token); - if (appWindowToken == null) { - Slog.w(TAG_WM, "Attempted to reset replacing window on non-existing app token " - + token); - return; - } - if (replacing) { - scheduleWindowReplacementTimeouts(appWindowToken); - } else { - appWindowToken.clearWillReplaceWindows(); - } + void scheduleClearWillReplaceWindows(IBinder token, boolean replacing) { + final AppWindowToken appWindowToken = mRoot.getAppWindowToken(token); + if (appWindowToken == null) { + Slog.w(TAG_WM, "Attempted to reset replacing window on non-existing app token " + + token); + return; + } + if (replacing) { + scheduleWindowReplacementTimeouts(appWindowToken); + } else { + appWindowToken.clearWillReplaceWindows(); } } @@ -6491,11 +6395,9 @@ public class WindowManagerService extends IWindowManager.Stub } } - public void setDockedStackResizing(boolean resizing) { - synchronized (mGlobalLock) { - getDefaultDisplayContentLocked().getDockedDividerController().setResizing(resizing); - requestTraversal(); - } + void setDockedStackResizing(boolean resizing) { + getDefaultDisplayContentLocked().getDockedDividerController().setResizing(resizing); + requestTraversal(); } @Override @@ -7040,7 +6942,9 @@ public class WindowManagerService extends IWindowManager.Stub private final class LocalService extends WindowManagerInternal { @Override public void requestTraversalFromDisplayManager() { - requestTraversal(); + synchronized (mGlobalLock) { + requestTraversal(); + } } @Override diff --git a/services/core/java/com/android/server/wm/WindowProcessListener.java b/services/core/java/com/android/server/wm/WindowProcessListener.java index 23d7a6a9d293..1dade1519fdb 100644 --- a/services/core/java/com/android/server/wm/WindowProcessListener.java +++ b/services/core/java/com/android/server/wm/WindowProcessListener.java @@ -17,7 +17,6 @@ package com.android.server.wm; import android.util.proto.ProtoOutputStream; -import android.view.IRemoteAnimationRunner; import android.view.RemoteAnimationAdapter; /** diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 99ae18d67be5..501a93ef6645 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -520,11 +520,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP /** When true this window can be displayed on screens owther than mOwnerUid's */ private boolean mShowToOwnerOnly; - // Whether the window was visible when we set the app to invisible last time. WM uses - // this as a hint to restore the surface (if available) for early animation next time - // the app is brought visible. - private boolean mWasVisibleBeforeClientHidden; - // This window will be replaced due to relaunch. This allows window manager // to differentiate between simple removal of a window and replacement. In the latter case it // will preserve the old window until the new one is drawn. @@ -2013,8 +2008,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // Visibility of the removed window. Will be used later to update orientation later on. boolean wasVisible = false; - final int displayId = getDisplayId(); - // First, see if we need to run an animation. If we do, we have to hold off on removing the // window until the animation is done. If the display is frozen, just remove immediately, // since the animation wouldn't be seen. diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index ef1d110c9617..c676e723de71 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -271,20 +271,17 @@ class WindowStateAnimator { if (mAttrType == LayoutParams.TYPE_STATUS_BAR && mWin.isVisibleByPolicy()) { // Upon completion of a not-visible to visible status bar animation a relayout is // required. - if (displayContent != null) { - displayContent.setLayoutNeeded(); - } + displayContent.setLayoutNeeded(); } mWin.onExitAnimationDone(); - final int displayId = mWin.getDisplayId(); - int pendingLayoutChanges = FINISH_LAYOUT_REDO_ANIM; + displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_ANIM; if (displayContent.mWallpaperController.isWallpaperTarget(mWin)) { - pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; + displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; } - mAnimator.setPendingLayoutChanges(displayId, pendingLayoutChanges); - if (DEBUG_LAYOUT_REPEATS) + if (DEBUG_LAYOUT_REPEATS) { mService.mWindowPlacerLocked.debugLayoutRepeats( - "WindowStateAnimator", mAnimator.getPendingLayoutChanges(displayId)); + "WindowStateAnimator", displayContent.pendingLayoutChanges); + } if (mWin.mAppToken != null) { mWin.mAppToken.updateReportedVisibilityLocked(); @@ -429,10 +426,6 @@ class WindowStateAnimator { } } - private int getLayerStack() { - return mWin.getDisplayContent().getDisplay().getLayerStack(); - } - void resetDrawState() { mDrawState = DRAW_PENDING; @@ -1072,8 +1065,7 @@ class WindowStateAnimator { if (mSurfaceResized) { mReportSurfaceResized = true; - mAnimator.setPendingLayoutChanges(w.getDisplayId(), - FINISH_LAYOUT_REDO_WALLPAPER); + mWin.getDisplayContent().pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; } } @@ -1168,16 +1160,16 @@ class WindowStateAnimator { if (mIsWallpaper) { w.dispatchWallpaperVisibility(true); } - if (!w.getDisplayContent().getLastHasContent()) { + final DisplayContent displayContent = w.getDisplayContent(); + if (!displayContent.getLastHasContent()) { // This draw means the difference between unique content and mirroring. // Run another pass through performLayout to set mHasContent in the // LogicalDisplay. - mAnimator.setPendingLayoutChanges(w.getDisplayId(), - FINISH_LAYOUT_REDO_ANIM); + displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_ANIM; if (DEBUG_LAYOUT_REPEATS) { mService.mWindowPlacerLocked.debugLayoutRepeats( "showSurfaceRobustlyLocked " + w, - mAnimator.getPendingLayoutChanges(w.getDisplayId())); + displayContent.pendingLayoutChanges); } } } else { diff --git a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java index 6a0d7f192adb..9e3b54d1ca96 100644 --- a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java +++ b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java @@ -22,7 +22,6 @@ import static com.android.server.am.MemoryStatUtil.MemoryStat; import static com.android.server.am.MemoryStatUtil.parseCmdlineFromProcfs; import static com.android.server.am.MemoryStatUtil.parseMemoryStatFromMemcg; import static com.android.server.am.MemoryStatUtil.parseMemoryStatFromProcfs; -import static com.android.server.am.MemoryStatUtil.parseVmHWMFromProcfs; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; @@ -230,18 +229,6 @@ public class MemoryStatUtilTest { } @Test - public void testParseVmHWMFromProcfs_parsesCorrectValue() { - assertEquals(137668, parseVmHWMFromProcfs(PROC_STATUS_CONTENTS)); - } - - @Test - public void testParseVmHWMFromProcfs_emptyContents() { - assertEquals(0, parseVmHWMFromProcfs("")); - - assertEquals(0, parseVmHWMFromProcfs(null)); - } - - @Test public void testParseCmdlineFromProcfs_invalidValue() { byte[] nothing = new byte[] {0x00, 0x74, 0x65, 0x73, 0x74}; // \0test diff --git a/services/tests/servicestests/src/com/android/server/stats/ProcfsMemoryUtilTest.java b/services/tests/servicestests/src/com/android/server/stats/ProcfsMemoryUtilTest.java new file mode 100644 index 000000000000..4fb533f726b2 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/stats/ProcfsMemoryUtilTest.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2019 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.server.stats; + +import static com.android.server.stats.ProcfsMemoryUtil.parseVmHWMFromStatus; + +import static com.google.common.truth.Truth.assertThat; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; + +/** + * Build/Install/Run: + * atest FrameworksServicesTests:ProcfsMemoryUtilTest + */ +@SmallTest +public class ProcfsMemoryUtilTest { + private static final String STATUS_CONTENTS = "Name:\tandroid.youtube\n" + + "State:\tS (sleeping)\n" + + "Tgid:\t12088\n" + + "Pid:\t12088\n" + + "PPid:\t723\n" + + "TracerPid:\t0\n" + + "Uid:\t10083\t10083\t10083\t10083\n" + + "Gid:\t10083\t10083\t10083\t10083\n" + + "Ngid:\t0\n" + + "FDSize:\t128\n" + + "Groups:\t3003 9997 20083 50083 \n" + + "VmPeak:\t 4546844 kB\n" + + "VmSize:\t 4542636 kB\n" + + "VmLck:\t 0 kB\n" + + "VmPin:\t 0 kB\n" + + "VmHWM:\t 137668 kB\n" // RSS high-water mark + + "VmRSS:\t 126776 kB\n" // RSS + + "RssAnon:\t 37860 kB\n" + + "RssFile:\t 88764 kB\n" + + "RssShmem:\t 152 kB\n" + + "VmData:\t 4125112 kB\n" + + "VmStk:\t 8192 kB\n" + + "VmExe:\t 24 kB\n" + + "VmLib:\t 102432 kB\n" + + "VmPTE:\t 1300 kB\n" + + "VmPMD:\t 36 kB\n" + + "VmSwap:\t 22 kB\n" // Swap + + "Threads:\t95\n" + + "SigQ:\t0/13641\n" + + "SigPnd:\t0000000000000000\n" + + "ShdPnd:\t0000000000000000\n" + + "SigBlk:\t0000000000001204\n" + + "SigIgn:\t0000000000000001\n" + + "SigCgt:\t00000006400084f8\n" + + "CapInh:\t0000000000000000\n" + + "CapPrm:\t0000000000000000\n" + + "CapEff:\t0000000000000000\n" + + "CapBnd:\t0000000000000000\n" + + "CapAmb:\t0000000000000000\n" + + "Seccomp:\t2\n" + + "Cpus_allowed:\tff\n" + + "Cpus_allowed_list:\t0-7\n" + + "Mems_allowed:\t1\n" + + "Mems_allowed_list:\t0\n" + + "voluntary_ctxt_switches:\t903\n" + + "nonvoluntary_ctxt_switches:\t104\n"; + + @Test + public void testParseVmHWMFromStatus_parsesCorrectValue() { + assertThat(parseVmHWMFromStatus(STATUS_CONTENTS)).isEqualTo(137668); + } + + @Test + public void testParseVmHWMFromStatus_invalidValue() { + assertThat(parseVmHWMFromStatus("test\nVmHWM: x0x0x\ntest")).isEqualTo(0); + } + + @Test + public void testParseVmHWMFromStatus_emptyContents() { + assertThat(parseVmHWMFromStatus("")).isEqualTo(0); + } +} diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java index 4f00383d1789..d311dfc60675 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java @@ -38,7 +38,6 @@ import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.res.Configuration; -import android.graphics.Rect; import android.os.UserHandle; import android.service.voice.IVoiceInteractionSession; import android.testing.DexmakerShareClassLoaderRule; @@ -446,12 +445,7 @@ class ActivityTestsBase { final ActivityStackSupervisor supervisor = mRootActivityContainer.mStackSupervisor; if (mWindowingMode == WINDOWING_MODE_PINNED) { stack = new ActivityStack(mDisplay, stackId, supervisor, - mWindowingMode, ACTIVITY_TYPE_STANDARD, mOnTop) { - @Override - Rect getDefaultPictureInPictureBounds(float aspectRatio) { - return new Rect(50, 50, 100, 100); - } - }; + mWindowingMode, ACTIVITY_TYPE_STANDARD, mOnTop); } else { stack = new ActivityStack(mDisplay, stackId, supervisor, mWindowingMode, mActivityType, mOnTop); diff --git a/services/tests/wmtests/src/com/android/server/wm/PinnedStackControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/PinnedStackControllerTest.java index efd468f1f77a..e9c226340164 100644 --- a/services/tests/wmtests/src/com/android/server/wm/PinnedStackControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/PinnedStackControllerTest.java @@ -66,8 +66,8 @@ public class PinnedStackControllerTest extends WindowTestsBase { verify(mIPinnedStackListener).onImeVisibilityChanged(false, 0); verify(mIPinnedStackListener).onShelfVisibilityChanged(false, 0); - verify(mIPinnedStackListener).onMovementBoundsChanged(any(), any(), any(), eq(false), - eq(false), anyInt()); + verify(mIPinnedStackListener).onMovementBoundsChanged(any(), eq(false), + eq(false)); verify(mIPinnedStackListener).onActionsChanged(any()); verify(mIPinnedStackListener).onMinimizedStateChanged(anyBoolean()); @@ -75,8 +75,8 @@ public class PinnedStackControllerTest extends WindowTestsBase { mWm.setShelfHeight(true, SHELF_HEIGHT); verify(mIPinnedStackListener).onShelfVisibilityChanged(true, SHELF_HEIGHT); - verify(mIPinnedStackListener).onMovementBoundsChanged(any(), any(), any(), eq(false), - eq(true), anyInt()); + verify(mIPinnedStackListener).onMovementBoundsChanged(any(), eq(false), + eq(true)); verify(mIPinnedStackListener, never()).onImeVisibilityChanged(anyBoolean(), anyInt()); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java index 340e7411d21e..2b1c4fff5861 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java @@ -138,6 +138,19 @@ public class SurfaceAnimatorTest extends WindowTestsBase { } @Test + public void testCancelWithNullFinishCallbackAnimation() { + SurfaceAnimator animator = new SurfaceAnimator(mAnimatable, null, mWm); + animator.startAnimation(mTransaction, mSpec, true /* hidden */); + assertTrue(animator.isAnimating()); + assertNotNull(animator.getAnimation()); + animator.cancelAnimation(); + assertFalse(animator.isAnimating()); + assertNull(animator.getAnimation()); + verify(mSpec).onAnimationCancelled(any()); + verify(mTransaction).remove(eq(mAnimatable.mLeash)); + } + + @Test public void testDelayingAnimationStart() { mAnimatable.mSurfaceAnimator.startDelayingAnimationStart(); mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */); diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java index 35488100fb58..0abd9fc62b14 100644 --- a/telecomm/java/android/telecom/ConnectionService.java +++ b/telecomm/java/android/telecom/ConnectionService.java @@ -30,6 +30,7 @@ import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.telecom.Logging.Session; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.SomeArgs; import com.android.internal.telecom.IConnectionService; import com.android.internal.telecom.IConnectionServiceAdapter; @@ -2672,4 +2673,13 @@ public abstract class ConnectionService extends Service { return ++mId; } } + + /** + * Returns this handler, ONLY FOR TESTING. + * @hide + */ + @VisibleForTesting + public Handler getHandler() { + return mHandler; + } } diff --git a/telecomm/java/android/telecom/Logging/SessionManager.java b/telecomm/java/android/telecom/Logging/SessionManager.java index 949f7b7a89ae..49c3a7205d59 100644 --- a/telecomm/java/android/telecom/Logging/SessionManager.java +++ b/telecomm/java/android/telecom/Logging/SessionManager.java @@ -391,6 +391,20 @@ public class SessionManager { return mCurrentThreadId.get(); } + /** + * @return A String representation of the active sessions at the time that this method is + * called. + */ + @VisibleForTesting + public synchronized String printActiveSessions() { + StringBuilder message = new StringBuilder(); + for (ConcurrentHashMap.Entry<Integer, Session> entry : mSessionMapper.entrySet()) { + message.append(entry.getValue().printFullSessionTree()); + message.append("\n"); + } + return message.toString(); + } + @VisibleForTesting public synchronized void cleanupStaleSessions(long timeoutMs) { String logMessage = "Stale Sessions Cleaned:\n"; diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index b5dbbe749563..70796752be84 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -270,9 +270,6 @@ public class TelephonyManager { private SubscriptionManager mSubscriptionManager; private TelephonyScanManager mTelephonyScanManager; - private static String multiSimConfig = - SystemProperties.get(TelephonyProperties.PROPERTY_MULTI_SIM_CONFIG); - /** Enum indicating multisim variants * DSDS - Dual SIM Dual Standby * DSDA - Dual SIM Dual Active @@ -432,8 +429,7 @@ public class TelephonyManager { /** {@hide} */ @UnsupportedAppUsage public boolean isMultiSimEnabled() { - return (multiSimConfig.equals("dsds") || multiSimConfig.equals("dsda") || - multiSimConfig.equals("tsts")); + return getPhoneCount() > 1; } // @@ -6625,11 +6621,7 @@ public class TelephonyManager { public int getSimCount() { // FIXME Need to get it from Telephony Dev Controller when that gets implemented! // and then this method shouldn't be used at all! - if(isMultiSimEnabled()) { - return getPhoneCount(); - } else { - return 1; - } + return getPhoneCount(); } /** |