Merge "Internal cleanup of window manager"
diff --git a/api/current.txt b/api/current.txt
index eeaabf6..8522034 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -53041,6 +53041,7 @@
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 10ac4a1..476fae3 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 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 70f0f6f..441d3c8 100644
--- a/cmds/statsd/tests/LogEntryMatcher_test.cpp
+++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp
@@ -330,6 +330,7 @@
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 c74daa8..3933e81 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -519,9 +519,9 @@
* <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 30e5959..76e728a 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -182,6 +182,12 @@
*/
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 8665106..1c50d73 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -276,6 +276,7 @@
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 @@
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 @@
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 d2dcb568..f1d152b 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 @@
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.
- */
- oneway void setMinEdgeSize(int minEdgeSize);
-
- /**
* @return what WM considers to be the current device rotation.
*/
int getDisplayRotation();
+
+ /**
+ * 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.
+ */
+ 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 2da353b..806d81e 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 @@
/**
* 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 @@
* 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 85457cb..1b6c575 100644
--- a/core/java/android/view/SyncRtSurfaceTransactionApplier.java
+++ b/core/java/android/view/SyncRtSurfaceTransactionApplier.java
@@ -30,6 +30,14 @@
*/
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 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,17 +135,95 @@
public static class SurfaceParams {
- /**
- * Constructs surface parameters to be applied when the current view state gets pushed to
- * RenderThread.
- *
- * @param surface The surface to modify.
- * @param alpha Alpha to apply.
- * @param matrix Matrix to apply.
- * @param windowCrop Crop to apply.
- */
- public SurfaceParams(SurfaceControl surface, float alpha, Matrix matrix,
+ 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);
@@ -135,6 +233,36 @@
this.visible = visible;
}
+
+ /**
+ * Constructs surface parameters to be applied when the current view state gets pushed to
+ * RenderThread.
+ *
+ * @param surface The surface to modify.
+ * @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);
+ this.windowCrop = new Rect(windowCrop);
+ this.layer = layer;
+ this.cornerRadius = cornerRadius;
+ 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 484d9a1..dc8bf9b 100644
--- a/core/java/android/view/accessibility/AccessibilityCache.java
+++ b/core/java/android/view/accessibility/AccessibilityCache.java
@@ -71,7 +71,9 @@
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 @@
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 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;
+ }
+
+ final int windowCount = windowsOfDisplay.size();
+ if (windowCount > 0) {
+ // Careful to return the windows in a decreasing layer order.
+ SparseArray<AccessibilityWindowInfo> sortedWindows = mTempWindowArray;
+ sortedWindows.clear();
+
+ 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);
+ }
}
-
- // 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);
- }
-
- return 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 @@
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 @@
}
}
- 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 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 4db6f4f..d9fa9f2 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -28,6 +28,7 @@
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 @@
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 @@
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 b3b0b72..5e02de4 100644
--- a/core/java/android/view/contentcapture/ChildContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ChildContentCaptureSession.java
@@ -89,6 +89,11 @@
}
@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 625fcda..cf08c18 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -439,6 +439,19 @@
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 1e7440b..349ef09 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -583,6 +583,11 @@
}
@Override
+ public void internalNotifySessionLifecycle(boolean started) {
+ notifySessionLifecycle(mId, started);
+ }
+
+ @Override
boolean isContentCaptureEnabled() {
return super.isContentCaptureEnabled() && mManager.isContentCaptureEnabled();
}
@@ -637,10 +642,9 @@
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 cac75cfd..57ce28e 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -2561,7 +2561,8 @@
* @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 1a22a70..6bce651 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.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 @@
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 @@
@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 @@
@Test
public void testEmptyCache_returnsNull() {
assertNull(mAccessibilityCache.getNode(0, 0));
- assertNull(mAccessibilityCache.getWindows());
+ assertNull(mAccessibilityCache.getWindowsOnAllDisplays());
assertNull(mAccessibilityCache.getWindow(0));
}
@@ -114,10 +121,11 @@
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 @@
@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 @@
}
@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 @@
@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 @@
}
}
- 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 @@
}
}
}
+
+ 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 81ce15a4..c5da549 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 @@
}
@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 8c0108d..602fe3e 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -1264,9 +1264,7 @@
}
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 d674be4..37fefc2 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -76,6 +76,16 @@
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 60435d0..d62c1d4 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 @@
/**
* 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 925e4fa..a1006a8 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 3ae2df5b..2797042 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 @@
* 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 794c30a..9f1a1fa 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.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 @@
* 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 @@
/**
* 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 bd5b9c7..ca6803d 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.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 @@
@Inject Lazy<INotificationManager> mINotificationManager;
@Inject Lazy<FalsingManager> mFalsingManager;
@Inject Lazy<SysUiState> mSysUiStateFlagsContainer;
+ @Inject Lazy<AlarmManager> mAlarmManager;
@Inject
public Dependency() {
@@ -508,6 +510,7 @@
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 d46a86c..239cbfe 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.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 @@
@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 ff4eb83..38f2f5e8 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.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 e4d2005..73bbce9 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 @@
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 67fc3e3..8211c6e 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.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.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.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 @@
@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 @@
@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 @@
}
/** 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 c2b0fe4..20742d6 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.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 85bc22b..914258f 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.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.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 @@
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 3f5cae6..0aa66af 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.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 bf39751..53ca783 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 @@
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 eeca409..f0feb4e 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.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 c367286..bb8c7f1 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.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 @@
/** 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 @@
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 026a625..67eefc5 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.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 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 @@
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 @@
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 @@
mWakeLock = wakeLock;
mProxCallback = proxCallback;
mResolver = mContext.getContentResolver();
+ mCallback = callback;
boolean alwaysOn = mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT);
mSensors = new TriggerSensor[] {
@@ -146,8 +147,11 @@
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 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 @@
/** 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 bab64db..80d4b63 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.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 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 @@
*/
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 @@
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 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 @@
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 @@
}
}
- 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 @@
}
} else {
proximityCheckThenCall((result) -> {
- if (result == ProximityCheck.RESULT_NEAR) {
+ if (result) {
// In pocket, drop event.
return;
}
@@ -267,7 +271,7 @@
if (wake) {
proximityCheckThenCall((result) -> {
- if (result == ProximityCheck.RESULT_NEAR) {
+ if (result) {
// In pocket, drop event.
return;
}
@@ -376,7 +380,7 @@
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 @@
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 30be775..6795bff 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 @@
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 @@
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 @@
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 @@
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 @@
}
/**
- * 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 @@
/**
* 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 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 3be3422..8dfae32 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.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 @@
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 @@
/**
* 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 @@
@Override
public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
mHandler.post(() -> {
+ mPipBoundsHandler.onImeVisibilityChanged(imeVisible, imeHeight);
mTouchHandler.onImeVisibilityChanged(imeVisible, imeHeight);
});
}
@@ -138,31 +145,66 @@
@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 @@
}
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 @@
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 30cf412..1f36d97 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 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 @@
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 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 @@
inputConsumerController.setInputListener(this::handleTouchEvent);
inputConsumerController.setRegistrationListener(this::onRegistrationChanged);
onRegistrationChanged(inputConsumerController.isRegistered());
+
+ mPipBoundsHandler = pipBoundsHandler;
}
public void setTouchEnabled(boolean enabled) {
@@ -787,14 +792,8 @@
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 918af4f..81d6973 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 @@
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.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 @@
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 @@
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 @@
/**
* 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 @@
}
@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 @@
}
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 @@
(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 61d7498..1e763cf 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 @@
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 @@
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 @@
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 @@
newTiles.put(tileSpec, tile);
} else {
tile.destroy();
+ Log.d(TAG, "Destroying not available tile: " + tileSpec);
}
}
} catch (Throwable t) {
@@ -274,7 +276,7 @@
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/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
index 276afa7..a70dc7c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
@@ -33,6 +33,7 @@
import com.android.systemui.Interpolators
import com.android.systemui.R
import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.ExpandableView
@@ -56,7 +57,8 @@
private val wakeUpCoordinator: NotificationWakeUpCoordinator,
private val bypassController: KeyguardBypassController,
private val headsUpManager: HeadsUpManagerPhone,
- private val roundnessManager: NotificationRoundnessManager
+ private val roundnessManager: NotificationRoundnessManager,
+ private val statusBarStateController: StatusBarStateController
) : Gefingerpoken {
companion object {
private val RUBBERBAND_FACTOR_STATIC = 0.25f
@@ -188,7 +190,8 @@
MotionEvent.ACTION_MOVE -> updateExpansionHeight(moveDistance)
MotionEvent.ACTION_UP -> {
velocityTracker!!.computeCurrentVelocity(1000 /* units */)
- val canExpand = moveDistance > 0 && velocityTracker!!.getYVelocity() > -1000
+ val canExpand = moveDistance > 0 && velocityTracker!!.getYVelocity() > -1000 &&
+ statusBarStateController.state != StatusBarState.SHADE
if (!mFalsingManager.isUnlockingDisabled && !isFalseTouch && canExpand) {
finishExpansion()
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index 4422a81..8b9268e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -20,6 +20,7 @@
import android.animation.ValueAnimator;
import android.text.format.DateFormat;
import android.util.FloatProperty;
+import android.util.Log;
import android.view.View;
import android.view.animation.Interpolator;
@@ -137,6 +138,11 @@
// Record the to-be mState and mLastState
recordHistoricalState(state, mState);
+ // b/139259891
+ if (mState == StatusBarState.SHADE && state == StatusBarState.SHADE_LOCKED) {
+ Log.e(TAG, "Invalid state transition: SHADE -> SHADE_LOCKED", new Throwable());
+ }
+
synchronized (mListeners) {
String tag = getClass().getSimpleName() + "#setState(" + state + ")";
DejankUtils.startDetectingBlockingIpcs(tag);
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 575b559..4cd3ad2 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 @@
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.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.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 @@
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 f7bb97b..00b764b 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.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 a905eba..0000000
--- 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
similarity index 90%
rename from packages/SystemUI/src/com/android/systemui/util/AsyncSensorManager.java
rename to packages/SystemUI/src/com/android/systemui/util/sensors/AsyncSensorManager.java
index b9c5ee5..dcd0c58 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 @@
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 0000000..c48bdde
--- /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 b979356..3561e34 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.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 3fc5d72..35d59c1 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 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 0c124ff..752e145 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.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 392c677..aa62e9a 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.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 cd6d1e0..ddd1685 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.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 e190f99..f7cd696 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.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 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 @@
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 @@
@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 @@
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 @@
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 @@
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 @@
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/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 2f24494..219aef1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -131,7 +131,7 @@
mKeyguardBypassController);
PulseExpansionHandler expansionHandler = new PulseExpansionHandler(mContext, coordinator,
mKeyguardBypassController, mHeadsUpManager,
- mock(NotificationRoundnessManager.class));
+ mock(NotificationRoundnessManager.class), mStatusBarStateController);
mNotificationPanelView = new TestableNotificationPanelView(coordinator, expansionHandler,
mKeyguardBypassController);
mNotificationPanelView.setHeadsUpManager(mHeadsUpManager);
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
similarity index 71%
rename from packages/SystemUI/tests/src/com/android/systemui/util/AsyncSensorManagerTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/util/sensors/AsyncSensorManagerTest.java
index 4a9b1b3..9149599 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.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 @@
@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 void registerListenerImpl() throws Exception {
mAsyncSensorManager.registerListener(mListener, mSensor.getSensor(), 100);
- mAsyncSensorManager.waitUntilRequestsCompleted();
+ waitUntilRequestsCompleted();
// Verify listener was registered.
mSensor.sendProximityResult(true);
@@ -73,7 +73,7 @@
mAsyncSensorManager.registerListener(mListener, mSensor.getSensor(), 100);
mAsyncSensorManager.unregisterListener(mListener);
- mAsyncSensorManager.waitUntilRequestsCompleted();
+ waitUntilRequestsCompleted();
// Verify listener was unregistered.
mSensor.sendProximityResult(true);
@@ -85,7 +85,7 @@
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 @@
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
similarity index 95%
rename from packages/SystemUI/tests/src/com/android/systemui/utils/hardware/FakeSensorManager.java
rename to packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeSensorManager.java
index 29b8ab60..1deb495 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 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 @@
}
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 @@
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 0000000..6d13408
--- /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 8ad2489..353a187 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -1792,6 +1792,25 @@
// 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/MemoryStatUtil.java b/services/core/java/com/android/server/am/MemoryStatUtil.java
index e73abd1..fd64df9 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 @@
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 @@
}
/**
- * 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 @@
}
/**
- * 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 09f5286..96af74a 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 @@
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 3482e92..1cea4ca 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 @@
// 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 @@
return;
}
mPreRebootVerificationHandler.notifyPreRebootVerification_Apk_Complete(
- originalSession);
+ originalSession.sessionId);
});
apkSession.commit(receiver.getIntentSender(), false);
return;
@@ -526,7 +526,7 @@
void commitSession(@NonNull PackageInstallerSession session) {
updateStoredSession(session);
- mPreRebootVerificationHandler.startPreRebootVerification(session);
+ mPreRebootVerificationHandler.startPreRebootVerification(session.sessionId);
}
@Nullable
@@ -653,7 +653,7 @@
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 @@
@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 @@
}
// 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 @@
*/
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 @@
}
}
- notifyPreRebootVerification_Apex_Complete(session);
+ notifyPreRebootVerification_Apex_Complete(session.sessionId);
}
/**
@@ -819,7 +828,7 @@
*/
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 0000000..3076284
--- /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 e92abfd..19b8055 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.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/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 50200a7c..2ab3e01 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -839,11 +839,12 @@
// so that the divider matches and remove this logic.
// TODO: This is currently only called when entering split-screen while in another
// task, and from the tests
- // TODO (b/78247419): Check if launcher and overview are same then move home stack
- // instead of recents stack. Then fix the rotation animation from fullscreen to
- // minimized mode
+ // TODO (b/78247419): Fix the rotation animation from fullscreen to minimized mode
+ final boolean isRecentsComponentHome =
+ mService.getRecentTasks().isRecentsComponentHomeActivity(mCurrentUser);
final ActivityStack recentStack = display.getOrCreateStack(
- WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_RECENTS,
+ WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
+ isRecentsComponentHome ? ACTIVITY_TYPE_HOME : ACTIVITY_TYPE_RECENTS,
true /* onTop */);
recentStack.moveToFront("setWindowingMode");
// If task moved to docked stack - show recents if needed.
@@ -4940,12 +4941,6 @@
}
}
-
- 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/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index c933ece..47be792 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -2342,7 +2342,12 @@
REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME,
"reparentingHome");
mMovedToFront = true;
+ } else if (launchStack.topTask() == null) {
+ // The task does not need to be reparented to the launch stack. Remove the
+ // launch stack if there is no activity in it.
+ launchStack.remove();
}
+
mOptions = null;
// We are moving a task to the front, use starting window to hide initial drawn
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 93b8f00..f647fe4 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 @@
updateReportedVisibilityLocked();
}
+ // Reset the last saved PiP snap fraction on removal.
+ mDisplayContent.mPinnedStackControllerLocked.resetReentrySnapFraction(mActivityComponent);
+
mRemovingFromDisplay = false;
}
@@ -1021,7 +1024,7 @@
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 @@
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 @@
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/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index ef0049b..8e57fec 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 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.server.UiThread;
import java.io.PrintWriter;
-import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
@@ -74,7 +74,7 @@
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 @@
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 @@
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,18 +132,21 @@
}
@Override
- public void setMinEdgeSize(int minEdgeSize) {
- mHandler.post(() -> {
- mCurrentMinSize = Math.max(mDefaultMinSize, minEdgeSize);
- });
- }
-
- @Override
public int getDisplayRotation() {
synchronized (mService.mGlobalLock) {
return mDisplayInfo.rotation;
}
}
+
+ @Override
+ public void startAnimation(Rect destinationBounds, Rect sourceRectHint,
+ int animationDuration) {
+ synchronized (mService.mGlobalLock) {
+ final TaskStack pinnedStack = mDisplayContent.getPinnedStack();
+ pinnedStack.animateResizePinnedStack(destinationBounds,
+ sourceRectHint, animationDuration, true /* fromFullscreen */);
+ }
+ }
}
/**
@@ -188,7 +187,6 @@
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 @@
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 @@
}
/**
- * 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 @@
}
}
+ 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 @@
} 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 @@
// 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 @@
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 @@
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 @@
}
}
+ 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 @@
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 @@
}
/**
+ * 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 @@
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/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index 4b2d4ce..734f224 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -193,6 +193,9 @@
/** Set when a power hint has started, but not ended. */
private boolean mPowerHintSent;
+ /** Used to keep ensureActivitiesVisible() from being entered recursively. */
+ private boolean mInEnsureActivitiesVisible = false;
+
// The default minimal size that will be used if the activity doesn't specify its minimal size.
// It will be calculated when the default display gets added.
int mDefaultMinSizeOfResizeableTaskDp = -1;
@@ -805,8 +808,14 @@
*/
void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
boolean preserveWindows, boolean notifyClients) {
- mStackSupervisor.getKeyguardController().beginActivityVisibilityUpdate();
+ if (mInEnsureActivitiesVisible) {
+ // Don't do recursive work.
+ return;
+ }
+ mInEnsureActivitiesVisible = true;
+
try {
+ mStackSupervisor.getKeyguardController().beginActivityVisibilityUpdate();
// First the front stacks. In case any are not fullscreen and are in front of home.
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ActivityDisplay display = mActivityDisplays.get(displayNdx);
@@ -815,6 +824,7 @@
}
} finally {
mStackSupervisor.getKeyguardController().endActivityVisibilityUpdate();
+ mInEnsureActivitiesVisible = false;
}
}
@@ -959,10 +969,6 @@
// 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
@@ -1001,9 +1007,14 @@
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/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 6a7f0c3..9465129 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -1660,40 +1660,6 @@
}
/**
- * @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,
@@ -1770,6 +1736,11 @@
return;
}
+ final DisplayContent displayContent = getDisplayContent();
+ if (displayContent == null) {
+ return;
+ }
+
if (!inPinnedWindowingMode()) {
return;
}
@@ -1780,13 +1751,10 @@
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/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
index 6a0d7f1..9e3b54d 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.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 @@
}
@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 0000000..4fb533f
--- /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 4f00383..d311dfc 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.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 @@
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 efd468f..e9c2263 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 @@
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 @@
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/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 3548810..0abd9fc 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -30,6 +30,7 @@
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 @@
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 949f7b7..49c3a72 100644
--- a/telecomm/java/android/telecom/Logging/SessionManager.java
+++ b/telecomm/java/android/telecom/Logging/SessionManager.java
@@ -391,6 +391,20 @@
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 b5dbbe7..7079675 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -270,9 +270,6 @@
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 @@
/** {@hide} */
@UnsupportedAppUsage
public boolean isMultiSimEnabled() {
- return (multiSimConfig.equals("dsds") || multiSimConfig.equals("dsda") ||
- multiSimConfig.equals("tsts"));
+ return getPhoneCount() > 1;
}
//
@@ -6625,11 +6621,7 @@
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();
}
/**
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index 7ffa5ff..137fbd6 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -246,6 +246,36 @@
Printer* printer_;
};
+std::string OverlayablePoliciesToString(OverlayableItem::PolicyFlags policies) {
+ static const std::map<OverlayableItem::PolicyFlags, std::string> kFlagToString = {
+ {OverlayableItem::kPublic, "public"},
+ {OverlayableItem::kSystem, "system"},
+ {OverlayableItem::kVendor, "vendor"},
+ {OverlayableItem::kProduct, "product"},
+ {OverlayableItem::kSignature, "signature"},
+ {OverlayableItem::kOdm, "odm"},
+ {OverlayableItem::kOem, "oem"},
+ };
+ std::string str;
+ for (auto const& policy : kFlagToString) {
+ if ((policies & policy.first) != policy.first) {
+ continue;
+ }
+ if (!str.empty()) {
+ str.append("|");
+ }
+ str.append(policy.second);
+ policies &= ~policy.first;
+ }
+ if (policies != 0) {
+ if (!str.empty()) {
+ str.append("|");
+ }
+ str.append(StringPrintf("0x%08x", policies));
+ }
+ return !str.empty() ? str : "none";
+}
+
} // namespace
void Debug::PrintTable(const ResourceTable& table, const DebugPrintTableOptions& options,
@@ -312,6 +342,10 @@
break;
}
+ if (entry->overlayable_item) {
+ printer->Print(" OVERLAYABLE");
+ }
+
printer->Println();
if (options.show_values) {
@@ -525,4 +559,62 @@
doc.root->Accept(&xml_visitor);
}
+struct DumpOverlayableEntry {
+ std::string overlayable_section;
+ std::string policy_subsection;
+ std::string resource_name;
+};
+
+void Debug::DumpOverlayable(const ResourceTable& table, text::Printer* printer) {
+ std::vector<DumpOverlayableEntry> items;
+ for (const auto& package : table.packages) {
+ for (const auto& type : package->types) {
+ for (const auto& entry : type->entries) {
+ if (entry->overlayable_item) {
+ const auto& overlayable_item = entry->overlayable_item.value();
+ const auto overlayable_section = StringPrintf(R"(name="%s" actor="%s")",
+ overlayable_item.overlayable->name.c_str(),
+ overlayable_item.overlayable->actor.c_str());
+ const auto policy_subsection = StringPrintf(R"(policies="%s")",
+ OverlayablePoliciesToString(overlayable_item.policies).c_str());
+ const auto value =
+ StringPrintf("%s/%s", to_string(type->type).data(), entry->name.c_str());
+ items.push_back(DumpOverlayableEntry{overlayable_section, policy_subsection, value});
+ }
+ }
+ }
+ }
+
+ std::sort(items.begin(), items.end(),
+ [](const DumpOverlayableEntry& a, const DumpOverlayableEntry& b) {
+ if (a.overlayable_section != b.overlayable_section) {
+ return a.overlayable_section < b.overlayable_section;
+ }
+ if (a.policy_subsection != b.policy_subsection) {
+ return a.policy_subsection < b.policy_subsection;
+ }
+ return a.resource_name < b.resource_name;
+ });
+
+ std::string last_overlayable_section;
+ std::string last_policy_subsection;
+ for (const auto& item : items) {
+ if (last_overlayable_section != item.overlayable_section) {
+ printer->Println(item.overlayable_section);
+ last_overlayable_section = item.overlayable_section;
+ }
+ if (last_policy_subsection != item.policy_subsection) {
+ printer->Indent();
+ printer->Println(item.policy_subsection);
+ last_policy_subsection = item.policy_subsection;
+ printer->Undent();
+ }
+ printer->Indent();
+ printer->Indent();
+ printer->Println(item.resource_name);
+ printer->Undent();
+ printer->Undent();
+ }
+}
+
} // namespace aapt
diff --git a/tools/aapt2/Debug.h b/tools/aapt2/Debug.h
index a43197c..9443d60 100644
--- a/tools/aapt2/Debug.h
+++ b/tools/aapt2/Debug.h
@@ -39,6 +39,7 @@
static void DumpHex(const void* data, size_t len);
static void DumpXml(const xml::XmlResource& doc, text::Printer* printer);
static void DumpResStringPool(const android::ResStringPool* pool, text::Printer* printer);
+ static void DumpOverlayable(const ResourceTable& table, text::Printer* printer);
};
} // namespace aapt
diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp
index 429aff1..3982d12 100644
--- a/tools/aapt2/cmd/Dump.cpp
+++ b/tools/aapt2/cmd/Dump.cpp
@@ -394,6 +394,17 @@
return 0;
}
+int DumpOverlayableCommand::Dump(LoadedApk* apk) {
+ ResourceTable* table = apk->GetResourceTable();
+ if (!table) {
+ GetDiagnostics()->Error(DiagMessage() << "Failed to retrieve resource table");
+ return 1;
+ }
+
+ Debug::DumpOverlayable(*table, GetPrinter());
+ return 0;
+}
+
const char DumpBadgerCommand::kBadgerData[2925] = {
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 95, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
diff --git a/tools/aapt2/cmd/Dump.h b/tools/aapt2/cmd/Dump.h
index 7ded9bc..cd51f7a 100644
--- a/tools/aapt2/cmd/Dump.h
+++ b/tools/aapt2/cmd/Dump.h
@@ -240,6 +240,16 @@
std::vector<std::string> files_;
};
+class DumpOverlayableCommand : public DumpApkCommand {
+ public:
+ explicit DumpOverlayableCommand(text::Printer* printer, IDiagnostics* diag)
+ : DumpApkCommand("overlayable", printer, diag) {
+ SetDescription("Print the <overlayable> resources of an APK.");
+ }
+
+ int Dump(LoadedApk* apk) override;
+};
+
/** The default dump command. Performs no action because a subcommand is required. */
class DumpCommand : public Command {
public:
@@ -255,8 +265,8 @@
AddOptionalSubcommand(util::make_unique<DumpTableCommand>(printer, diag_));
AddOptionalSubcommand(util::make_unique<DumpXmlStringsCommand>(printer, diag_));
AddOptionalSubcommand(util::make_unique<DumpXmlTreeCommand>(printer, diag_));
+ AddOptionalSubcommand(util::make_unique<DumpOverlayableCommand>(printer, diag_));
AddOptionalSubcommand(util::make_unique<DumpBadgerCommand>(printer), /* hidden */ true);
- // TODO(b/120609160): Add aapt2 overlayable dump command
}
int Action(const std::vector<std::string>& args) override {