Merge changes from topic "presubmit-am-9b5e750ffe3a4cb798418c89d9e7f523"
* changes:
[automerge] Re-land "Move rounded corner to provider" 2p: 4301034952 2p: 88e14532f8
[automerge] Re-land "Move rounded corner to provider" 2p: 4301034952
Re-land "Move rounded corner to provider"
diff --git a/packages/SystemUI/res/layout/rounded_corners_bottom.xml b/packages/SystemUI/res/layout/rounded_corners_bottom.xml
deleted file mode 100644
index bb6d4bd..0000000
--- a/packages/SystemUI/res/layout/rounded_corners_bottom.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-** Copyright 2020, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
--->
-<com.android.systemui.RegionInterceptingFrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/rounded_corners_bottom"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <ImageView
- android:id="@+id/left"
- android:layout_width="12dp"
- android:layout_height="12dp"
- android:layout_gravity="left|bottom"
- android:tint="#ff000000"
- android:visibility="gone"
- android:src="@drawable/rounded_corner_bottom"/>
-
- <ImageView
- android:id="@+id/right"
- android:layout_width="12dp"
- android:layout_height="12dp"
- android:tint="#ff000000"
- android:visibility="gone"
- android:layout_gravity="right|bottom"
- android:src="@drawable/rounded_corner_bottom"/>
-
-</com.android.systemui.RegionInterceptingFrameLayout>
diff --git a/packages/SystemUI/res/layout/rounded_corners_top.xml b/packages/SystemUI/res/layout/rounded_corners_top.xml
deleted file mode 100644
index 46648c8..0000000
--- a/packages/SystemUI/res/layout/rounded_corners_top.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-** Copyright 2020, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
--->
-<com.android.systemui.RegionInterceptingFrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/rounded_corners_top"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <ImageView
- android:id="@+id/left"
- android:layout_width="12dp"
- android:layout_height="12dp"
- android:layout_gravity="left|top"
- android:tint="#ff000000"
- android:visibility="gone"
- android:src="@drawable/rounded_corner_top"/>
-
- <ImageView
- android:id="@+id/right"
- android:layout_width="12dp"
- android:layout_height="12dp"
- android:tint="#ff000000"
- android:visibility="gone"
- android:layout_gravity="right|top"
- android:src="@drawable/rounded_corner_top"/>
-
-</com.android.systemui.RegionInterceptingFrameLayout>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index ff71b4f..5eacc3e 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -170,5 +170,11 @@
<item type="id" name="action_move_bottom_right"/>
<item type="id" name="action_move_to_edge_and_hide"/>
<item type="id" name="action_move_out_edge_and_show"/>
+
+ <!-- rounded corner view id -->
+ <item type="id" name="rounded_corner_top_left"/>
+ <item type="id" name="rounded_corner_top_right"/>
+ <item type="id" name="rounded_corner_bottom_left"/>
+ <item type="id" name="rounded_corner_bottom_right"/>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 43d91a2..9b09101 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -77,6 +77,7 @@
import com.android.systemui.decor.DecorProviderKt;
import com.android.systemui.decor.OverlayWindow;
import com.android.systemui.decor.PrivacyDotDecorProviderFactory;
+import com.android.systemui.decor.RoundedCornerDecorProviderFactory;
import com.android.systemui.decor.RoundedCornerResDelegate;
import com.android.systemui.qs.SettingObserver;
import com.android.systemui.settings.UserTracker;
@@ -137,6 +138,9 @@
@VisibleForTesting
protected RoundedCornerResDelegate mRoundedCornerResDelegate;
@VisibleForTesting
+ protected DecorProviderFactory mRoundedCornerFactory;
+ private int mProviderRefreshToken = 0;
+ @VisibleForTesting
protected OverlayWindow[] mOverlays = null;
@VisibleForTesting
@Nullable
@@ -282,16 +286,58 @@
return mDotFactory.getHasProviders();
}
+ @NonNull
+ private List<DecorProvider> getProviders(boolean hasHwLayer) {
+ List<DecorProvider> decorProviders = new ArrayList<>(mDotFactory.getProviders());
+ if (!hasHwLayer) {
+ decorProviders.addAll(mRoundedCornerFactory.getProviders());
+ }
+ return decorProviders;
+ }
+
+ private void updateDisplayIdToProviderFactories() {
+ mDotFactory.onDisplayUniqueIdChanged(mDisplayUniqueId);
+ mRoundedCornerFactory.onDisplayUniqueIdChanged(mDisplayUniqueId);
+ }
+
+ /**
+ * Check that newProviders is the same list with decorProviders inside mOverlay.
+ * @param newProviders expected comparing DecorProviders
+ * @return true if same provider list
+ */
+ @VisibleForTesting
+ boolean hasSameProviders(@NonNull List<DecorProvider> newProviders) {
+ final ArrayList<Integer> overlayViewIds = new ArrayList<>();
+ if (mOverlays != null) {
+ for (OverlayWindow overlay : mOverlays) {
+ if (overlay == null) {
+ continue;
+ }
+ overlayViewIds.addAll(overlay.getViewIds());
+ }
+ }
+ if (overlayViewIds.size() != newProviders.size()) {
+ return false;
+ }
+
+ for (DecorProvider provider: newProviders) {
+ if (!overlayViewIds.contains(provider.getViewId())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
private void startOnScreenDecorationsThread() {
mRotation = mContext.getDisplay().getRotation();
mDisplayUniqueId = mContext.getDisplay().getUniqueId();
mRoundedCornerResDelegate = new RoundedCornerResDelegate(mContext.getResources(),
mDisplayUniqueId);
+ mRoundedCornerFactory = new RoundedCornerDecorProviderFactory(mRoundedCornerResDelegate);
mWindowManager = mContext.getSystemService(WindowManager.class);
mDisplayManager = mContext.getSystemService(DisplayManager.class);
mHwcScreenDecorationSupport = mContext.getDisplay().getDisplayDecorationSupport();
- updateRoundedCornerDrawable();
- updateRoundedCornerRadii();
+ updateHwLayerRoundedCornerDrawable();
setupDecorations();
setupCameraListener();
@@ -343,18 +389,27 @@
final String newUniqueId = mContext.getDisplay().getUniqueId();
if (!Objects.equals(newUniqueId, mDisplayUniqueId)) {
mDisplayUniqueId = newUniqueId;
- mRoundedCornerResDelegate.reloadAll(newUniqueId);
final DisplayDecorationSupport newScreenDecorationSupport =
mContext.getDisplay().getDisplayDecorationSupport();
- // When the value of mSupportHwcScreenDecoration is changed, re-setup the whole
- // screen decoration.
- if (!eq(newScreenDecorationSupport, mHwcScreenDecorationSupport)) {
+
+ updateDisplayIdToProviderFactories();
+
+ // When providers or the value of mSupportHwcScreenDecoration is changed,
+ // re-setup the whole screen decoration.
+ if (!hasSameProviders(getProviders(newScreenDecorationSupport != null))
+ || !eq(newScreenDecorationSupport, mHwcScreenDecorationSupport)) {
mHwcScreenDecorationSupport = newScreenDecorationSupport;
removeAllOverlays();
setupDecorations();
return;
}
- updateRoundedCornerDrawable();
+
+ if (mScreenDecorHwcLayer != null) {
+ updateHwLayerRoundedCornerDrawable();
+ updateHwLayerRoundedCornerSize();
+ }
+
+ updateOverlayProviderViews();
}
if (mCutoutViews != null) {
final int size = mCutoutViews.length;
@@ -369,7 +424,6 @@
if (mScreenDecorHwcLayer != null) {
mScreenDecorHwcLayer.onDisplayChanged(displayId);
}
- updateOrientation();
}
};
@@ -396,6 +450,19 @@
return null;
}
+ private void removeRedundantOverlayViews(@NonNull List<DecorProvider> decorProviders) {
+ if (mOverlays == null) {
+ return;
+ }
+ int[] viewIds = decorProviders.stream().mapToInt(DecorProvider::getViewId).toArray();
+ for (final OverlayWindow overlay : mOverlays) {
+ if (overlay == null) {
+ continue;
+ }
+ overlay.removeRedundantViews(viewIds);
+ }
+ }
+
private void removeOverlayView(@IdRes int id) {
if (mOverlays == null) {
return;
@@ -411,9 +478,10 @@
}
private void setupDecorations() {
- List<DecorProvider> decorProviders = mDotFactory.getProviders();
+ if (hasRoundedCorners() || shouldDrawCutout() || isPrivacyDotEnabled()) {
+ List<DecorProvider> decorProviders = getProviders(mHwcScreenDecorationSupport != null);
+ removeRedundantOverlayViews(decorProviders);
- if (hasRoundedCorners() || shouldDrawCutout() || !decorProviders.isEmpty()) {
if (mHwcScreenDecorationSupport != null) {
createHwcOverlay();
} else {
@@ -427,7 +495,7 @@
Pair<List<DecorProvider>, List<DecorProvider>> pair =
DecorProviderKt.partitionAlignedBound(decorProviders, i);
decorProviders = pair.getSecond();
- createOverlay(i, cutout, pair.getFirst(), isOnlyPrivacyDotInSwLayer);
+ createOverlay(i, pair.getFirst(), isOnlyPrivacyDotInSwLayer);
} else {
removeOverlay(i);
}
@@ -560,7 +628,6 @@
private void createOverlay(
@BoundsPosition int pos,
- @Nullable DisplayCutout cutout,
@NonNull List<DecorProvider> decorProviders,
boolean isOnlyPrivacyDotInSwLayer) {
if (mOverlays == null) {
@@ -568,14 +635,12 @@
}
if (mOverlays[pos] != null) {
- // When mOverlay[pos] is not null and only privacy dot in sw layer, use privacy dot
- // view's visibility
- mOverlays[pos].getRootView().setVisibility(
- getWindowVisibility(mOverlays[pos], isOnlyPrivacyDotInSwLayer));
+ initOverlay(mOverlays[pos], decorProviders, isOnlyPrivacyDotInSwLayer);
return;
}
- mOverlays[pos] = overlayForPosition(pos, decorProviders, isOnlyPrivacyDotInSwLayer);
+ mOverlays[pos] = new OverlayWindow(mContext);
+ initOverlay(mOverlays[pos], decorProviders, isOnlyPrivacyDotInSwLayer);
final ViewGroup overlayView = mOverlays[pos].getRootView();
overlayView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
overlayView.setAlpha(0);
@@ -590,7 +655,7 @@
mCutoutViews[pos] = new DisplayCutoutView(mContext, pos);
mCutoutViews[pos].setColor(mTintColor);
overlayView.addView(mCutoutViews[pos]);
- updateView(pos, cutout);
+ mCutoutViews[pos].updateRotation(mRotation);
}
mWindowManager.addView(overlayView, getWindowLayoutParams(pos));
@@ -641,42 +706,24 @@
}
/**
- * Allow overrides for top/bottom positions
+ * Init OverlayWindow with decorProviders
*/
- private OverlayWindow overlayForPosition(
- @BoundsPosition int pos,
+ private void initOverlay(
+ @NonNull OverlayWindow overlay,
@NonNull List<DecorProvider> decorProviders,
boolean isOnlyPrivacyDotInSwLayer) {
- final OverlayWindow currentOverlay = new OverlayWindow(LayoutInflater.from(mContext), pos);
- decorProviders.forEach(provider -> {
- removeOverlayView(provider.getViewId());
- currentOverlay.addDecorProvider(provider, mRotation);
- });
- // When only privacy dot in mOverlay, set the initial visibility of mOverlays to
- // INVISIBLE and set it to VISIBLE when the privacy dot is showing.
- if (isOnlyPrivacyDotInSwLayer) {
- currentOverlay.getRootView().setVisibility(View.INVISIBLE);
+ if (!overlay.hasSameProviders(decorProviders)) {
+ decorProviders.forEach(provider -> {
+ if (overlay.getView(provider.getViewId()) != null) {
+ return;
+ }
+ removeOverlayView(provider.getViewId());
+ overlay.addDecorProvider(provider, mRotation);
+ });
}
- return currentOverlay;
- }
-
- private void updateView(@BoundsPosition int pos, @Nullable DisplayCutout cutout) {
- if (mOverlays == null || mOverlays[pos] == null || mHwcScreenDecorationSupport != null) {
- return;
- }
-
- // update rounded corner view rotation
- updateRoundedCornerView(pos, R.id.left, cutout);
- updateRoundedCornerView(pos, R.id.right, cutout);
- updateRoundedCornerSize(
- mRoundedCornerResDelegate.getTopRoundedSize(),
- mRoundedCornerResDelegate.getBottomRoundedSize());
- updateRoundedCornerImageView();
-
- // update cutout view rotation
- if (mCutoutViews != null && mCutoutViews[pos] != null) {
- mCutoutViews[pos].updateRotation(mRotation);
- }
+ // Use visibility of privacy dot views if only privacy dot in sw layer
+ overlay.getRootView().setVisibility(
+ getWindowVisibility(overlay, isOnlyPrivacyDotInSwLayer));
}
@VisibleForTesting
@@ -849,7 +896,6 @@
int oldRotation = mRotation;
mPendingRotationChange = false;
updateOrientation();
- updateRoundedCornerRadii();
if (DEBUG) Log.i(TAG, "onConfigChanged from rot " + oldRotation + " to " + mRotation);
setupDecorations();
if (mOverlays != null) {
@@ -910,109 +956,32 @@
mDotViewController.setNewRotation(newRotation);
}
- if (mPendingRotationChange) {
- return;
- }
- if (newRotation != mRotation) {
+ if (!mPendingRotationChange && newRotation != mRotation) {
mRotation = newRotation;
if (mScreenDecorHwcLayer != null) {
mScreenDecorHwcLayer.pendingRotationChange = false;
mScreenDecorHwcLayer.updateRotation(mRotation);
+ updateHwLayerRoundedCornerSize();
+ updateHwLayerRoundedCornerDrawable();
}
- if (mOverlays != null) {
- updateLayoutParams();
- final DisplayCutout cutout = getCutout();
- for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
- if (mOverlays[i] == null) {
+ updateLayoutParams();
+ // update cutout view rotation
+ if (mCutoutViews != null) {
+ for (final DisplayCutoutView cutoutView: mCutoutViews) {
+ if (cutoutView == null) {
continue;
}
- updateView(i, cutout);
+ cutoutView.updateRotation(mRotation);
}
}
}
+
+ // update all provider views inside overlay
+ updateOverlayProviderViews();
}
- private void updateRoundedCornerRadii() {
- // We should eventually move to just using the intrinsic size of the drawables since
- // they should be sized to the exact pixels they want to cover. Therefore I'm purposely not
- // upgrading all of the configs to contain (width, height) pairs. Instead assume that a
- // device configured using the single integer config value is okay with drawing the corners
- // as a square
- final Size oldRoundedDefaultTop = mRoundedCornerResDelegate.getTopRoundedSize();
- final Size oldRoundedDefaultBottom = mRoundedCornerResDelegate.getBottomRoundedSize();
- mRoundedCornerResDelegate.reloadAll(mDisplayUniqueId);
- final Size newRoundedDefaultTop = mRoundedCornerResDelegate.getTopRoundedSize();
- final Size newRoundedDefaultBottom = mRoundedCornerResDelegate.getBottomRoundedSize();
-
- if (oldRoundedDefaultTop.getWidth() != newRoundedDefaultTop.getWidth()
- || oldRoundedDefaultBottom.getWidth() != newRoundedDefaultBottom.getWidth()) {
- onTuningChanged(SIZE, null);
- }
- }
-
- private void updateRoundedCornerView(@BoundsPosition int pos, int id,
- @Nullable DisplayCutout cutout) {
- final View rounded = mOverlays[pos].getRootView().findViewById(id);
- if (rounded == null) {
- return;
- }
- rounded.setVisibility(View.GONE);
- if (shouldShowSwLayerRoundedCorner(pos, cutout)) {
- final int gravity = getRoundedCornerGravity(pos, id == R.id.left);
- ((FrameLayout.LayoutParams) rounded.getLayoutParams()).gravity = gravity;
- setRoundedCornerOrientation(rounded, gravity);
- rounded.setVisibility(View.VISIBLE);
- }
- }
-
- private int getRoundedCornerGravity(@BoundsPosition int pos, boolean isStart) {
- final int rotatedPos = getBoundPositionFromRotation(pos, mRotation);
- switch (rotatedPos) {
- case BOUNDS_POSITION_LEFT:
- return isStart ? Gravity.TOP | Gravity.LEFT : Gravity.BOTTOM | Gravity.LEFT;
- case BOUNDS_POSITION_TOP:
- return isStart ? Gravity.TOP | Gravity.LEFT : Gravity.TOP | Gravity.RIGHT;
- case BOUNDS_POSITION_RIGHT:
- return isStart ? Gravity.TOP | Gravity.RIGHT : Gravity.BOTTOM | Gravity.RIGHT;
- case BOUNDS_POSITION_BOTTOM:
- return isStart ? Gravity.BOTTOM | Gravity.LEFT : Gravity.BOTTOM | Gravity.RIGHT;
- default:
- throw new IllegalArgumentException("Incorrect position: " + rotatedPos);
- }
- }
-
- /**
- * Configures the rounded corner drawable's view matrix based on the gravity.
- *
- * The gravity describes which corner to configure for, and the drawable we are rotating is
- * assumed to be oriented for the top-left corner of the device regardless of the target corner.
- * Therefore we need to rotate 180 degrees to get a bottom-left corner, and mirror in the x- or
- * y-axis for the top-right and bottom-left corners.
- */
- private void setRoundedCornerOrientation(View corner, int gravity) {
- corner.setRotation(0);
- corner.setScaleX(1);
- corner.setScaleY(1);
- switch (gravity) {
- case Gravity.TOP | Gravity.LEFT:
- return;
- case Gravity.TOP | Gravity.RIGHT:
- corner.setScaleX(-1); // flip X axis
- return;
- case Gravity.BOTTOM | Gravity.LEFT:
- corner.setScaleY(-1); // flip Y axis
- return;
- case Gravity.BOTTOM | Gravity.RIGHT:
- corner.setRotation(180);
- return;
- default:
- throw new IllegalArgumentException("Unsupported gravity: " + gravity);
- }
- }
private boolean hasRoundedCorners() {
- return mRoundedCornerResDelegate.getBottomRoundedSize().getWidth() > 0
- || mRoundedCornerResDelegate.getTopRoundedSize().getWidth() > 0
- || mRoundedCornerResDelegate.isMultipleRadius();
+ return mRoundedCornerFactory.getHasProviders();
}
private boolean isDefaultShownOverlayPos(@BoundsPosition int pos,
@@ -1066,6 +1035,19 @@
context.getResources(), context.getDisplay().getUniqueId());
}
+ private void updateOverlayProviderViews() {
+ if (mOverlays == null) {
+ return;
+ }
+ ++mProviderRefreshToken;
+ for (final OverlayWindow overlay: mOverlays) {
+ if (overlay == null) {
+ continue;
+ }
+ overlay.onReloadResAndMeasure(null, mProviderRefreshToken, mRotation, mDisplayUniqueId);
+ }
+ }
+
private void updateLayoutParams() {
if (mOverlays == null) {
return;
@@ -1085,63 +1067,33 @@
return;
}
mExecutor.execute(() -> {
- if (mOverlays == null) return;
- if (SIZE.equals(key)) {
- boolean hasReloadRoundedCornerRes = false;
- if (newValue != null) {
- try {
- mRoundedCornerResDelegate.updateTuningSizeFactor(
- Integer.parseInt(newValue));
- hasReloadRoundedCornerRes = true;
- } catch (Exception e) {
- }
- }
-
- // When onTuningChanged() is not called through updateRoundedCornerRadii(),
- // we need to reload rounded corner res to prevent incorrect dimen
- if (!hasReloadRoundedCornerRes) {
- mRoundedCornerResDelegate.reloadAll(mDisplayUniqueId);
- }
-
- updateRoundedCornerSize(
- mRoundedCornerResDelegate.getTopRoundedSize(),
- mRoundedCornerResDelegate.getBottomRoundedSize());
+ if (mOverlays == null || !SIZE.equals(key)) {
+ return;
}
+ ++mProviderRefreshToken;
+ try {
+ final int sizeFactor = Integer.parseInt(newValue);
+ mRoundedCornerResDelegate.updateTuningSizeFactor(sizeFactor, mProviderRefreshToken);
+ } catch (NumberFormatException e) {
+ mRoundedCornerResDelegate.updateTuningSizeFactor(null, mProviderRefreshToken);
+ }
+ Integer[] filterIds = {
+ R.id.rounded_corner_top_left,
+ R.id.rounded_corner_top_right,
+ R.id.rounded_corner_bottom_left,
+ R.id.rounded_corner_bottom_right
+ };
+ for (final OverlayWindow overlay: mOverlays) {
+ if (overlay == null) {
+ continue;
+ }
+ overlay.onReloadResAndMeasure(filterIds, mProviderRefreshToken, mRotation,
+ mDisplayUniqueId);
+ }
+ updateHwLayerRoundedCornerSize();
});
}
- private void updateRoundedCornerDrawable() {
- mRoundedCornerResDelegate.reloadAll(mDisplayUniqueId);
- updateRoundedCornerImageView();
- }
-
- private void updateRoundedCornerImageView() {
- final Drawable top = mRoundedCornerResDelegate.getTopRoundedDrawable();
- final Drawable bottom = mRoundedCornerResDelegate.getBottomRoundedDrawable();
-
- if (mScreenDecorHwcLayer != null) {
- mScreenDecorHwcLayer.updateRoundedCornerDrawable(top, bottom);
- return;
- }
-
- if (mOverlays == null) {
- return;
- }
- final ColorStateList colorStateList = ColorStateList.valueOf(mTintColor);
- for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
- if (mOverlays[i] == null) {
- continue;
- }
- final ViewGroup overlayView = mOverlays[i].getRootView();
- ((ImageView) overlayView.findViewById(R.id.left)).setImageTintList(colorStateList);
- ((ImageView) overlayView.findViewById(R.id.right)).setImageTintList(colorStateList);
- ((ImageView) overlayView.findViewById(R.id.left)).setImageDrawable(
- isTopRoundedCorner(i, R.id.left) ? top : bottom);
- ((ImageView) overlayView.findViewById(R.id.right)).setImageDrawable(
- isTopRoundedCorner(i, R.id.right) ? top : bottom);
- }
- }
-
private void updateHwLayerRoundedCornerDrawable() {
if (mScreenDecorHwcLayer == null) {
return;
@@ -1156,25 +1108,6 @@
mScreenDecorHwcLayer.updateRoundedCornerDrawable(topDrawable, bottomDrawable);
}
- @VisibleForTesting
- boolean isTopRoundedCorner(@BoundsPosition int pos, int id) {
- switch (pos) {
- case BOUNDS_POSITION_LEFT:
- case BOUNDS_POSITION_RIGHT:
- if (mRotation == ROTATION_270) {
- return id == R.id.left ? false : true;
- } else {
- return id == R.id.left ? true : false;
- }
- case BOUNDS_POSITION_TOP:
- return true;
- case BOUNDS_POSITION_BOTTOM:
- return false;
- default:
- throw new IllegalArgumentException("Unknown bounds position");
- }
- }
-
private void updateHwLayerRoundedCornerSize() {
if (mScreenDecorHwcLayer == null) {
return;
@@ -1186,28 +1119,6 @@
mScreenDecorHwcLayer.updateRoundedCornerSize(topWidth, bottomWidth);
}
- private void updateRoundedCornerSize(Size sizeTop, Size sizeBottom) {
-
- if (mScreenDecorHwcLayer != null) {
- mScreenDecorHwcLayer.updateRoundedCornerSize(sizeTop.getWidth(), sizeBottom.getWidth());
- return;
- }
-
- if (mOverlays == null) {
- return;
- }
- for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
- if (mOverlays[i] == null) {
- continue;
- }
- final ViewGroup overlayView = mOverlays[i].getRootView();
- setSize(overlayView.findViewById(R.id.left),
- isTopRoundedCorner(i, R.id.left) ? sizeTop : sizeBottom);
- setSize(overlayView.findViewById(R.id.right),
- isTopRoundedCorner(i, R.id.right) ? sizeTop : sizeBottom);
- }
- }
-
@VisibleForTesting
protected void setSize(View view, Size pixelSize) {
LayoutParams params = view.getLayoutParams();
diff --git a/packages/SystemUI/src/com/android/systemui/decor/DecorProvider.kt b/packages/SystemUI/src/com/android/systemui/decor/DecorProvider.kt
index 3543bb4..03ee8b1 100644
--- a/packages/SystemUI/src/com/android/systemui/decor/DecorProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/decor/DecorProvider.kt
@@ -15,8 +15,8 @@
*/
package com.android.systemui.decor
+import android.content.Context
import android.view.DisplayCutout
-import android.view.LayoutInflater
import android.view.Surface
import android.view.View
import android.view.ViewGroup
@@ -38,9 +38,20 @@
/** The aligned bounds for the view which is created through inflateView() */
abstract val alignedBounds: List<Int>
+ /**
+ * Called when res info changed.
+ * Child provider needs to implement it if its view needs to be updated.
+ */
+ abstract fun onReloadResAndMeasure(
+ view: View,
+ reloadToken: Int,
+ @Surface.Rotation rotation: Int,
+ displayUniqueId: String? = null
+ )
+
/** Inflate view into parent as current rotation */
abstract fun inflateView(
- inflater: LayoutInflater,
+ context: Context,
parent: ViewGroup,
@Surface.Rotation rotation: Int
): View
diff --git a/packages/SystemUI/src/com/android/systemui/decor/DecorProviderFactory.kt b/packages/SystemUI/src/com/android/systemui/decor/DecorProviderFactory.kt
index c60cad8..cc4096f 100644
--- a/packages/SystemUI/src/com/android/systemui/decor/DecorProviderFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/decor/DecorProviderFactory.kt
@@ -19,4 +19,5 @@
abstract class DecorProviderFactory {
abstract val providers: List<DecorProvider>
abstract val hasProviders: Boolean
+ abstract fun onDisplayUniqueIdChanged(displayUniqueId: String?)
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/decor/OverlayWindow.kt b/packages/SystemUI/src/com/android/systemui/decor/OverlayWindow.kt
index 9f8679c..d775ad3 100644
--- a/packages/SystemUI/src/com/android/systemui/decor/OverlayWindow.kt
+++ b/packages/SystemUI/src/com/android/systemui/decor/OverlayWindow.kt
@@ -16,31 +16,25 @@
package com.android.systemui.decor
import android.annotation.IdRes
-import android.view.DisplayCutout
-import android.view.LayoutInflater
+import android.content.Context
import android.view.Surface
import android.view.View
import android.view.ViewGroup
-import com.android.systemui.R
-import java.util.HashMap
+import com.android.systemui.RegionInterceptingFrameLayout
-class OverlayWindow(private val layoutInflater: LayoutInflater, private val pos: Int) {
+class OverlayWindow(private val context: Context) {
- private val layoutId: Int
- get() {
- return if (pos == DisplayCutout.BOUNDS_POSITION_LEFT ||
- pos == DisplayCutout.BOUNDS_POSITION_TOP) {
- R.layout.rounded_corners_top
- } else {
- R.layout.rounded_corners_bottom
- }
- }
+ val rootView = RegionInterceptingFrameLayout(context) as ViewGroup
+ private val viewProviderMap = mutableMapOf<Int, Pair<View, DecorProvider>>()
- val rootView = layoutInflater.inflate(layoutId, null) as ViewGroup
- private val viewProviderMap: MutableMap<Int, Pair<View, DecorProvider>> = HashMap()
+ val viewIds: List<Int>
+ get() = viewProviderMap.keys.toList()
- fun addDecorProvider(decorProvider: DecorProvider, @Surface.Rotation rotation: Int) {
- val view = decorProvider.inflateView(layoutInflater, rootView, rotation)
+ fun addDecorProvider(
+ decorProvider: DecorProvider,
+ @Surface.Rotation rotation: Int
+ ) {
+ val view = decorProvider.inflateView(context, rootView, rotation)
viewProviderMap[decorProvider.viewId] = Pair(view, decorProvider)
}
@@ -56,4 +50,54 @@
viewProviderMap.remove(id)
}
}
+
+ /**
+ * Remove views which does not been found in expectExistViewIds
+ */
+ fun removeRedundantViews(expectExistViewIds: IntArray?) {
+ viewIds.forEach {
+ if (expectExistViewIds == null || !(expectExistViewIds.contains(it))) {
+ removeView(it)
+ }
+ }
+ }
+
+ /**
+ * Check that newProviders is the same list with viewProviderMap.
+ */
+ fun hasSameProviders(newProviders: List<DecorProvider>): Boolean {
+ return (newProviders.size == viewProviderMap.size) &&
+ newProviders.all { getView(it.viewId) != null }
+ }
+
+ /**
+ * Apply new configuration info into views.
+ * @param filterIds target view ids. Apply to all if null.
+ * @param rotation current or new rotation direction.
+ * @param displayUniqueId new displayUniqueId if any.
+ */
+ fun onReloadResAndMeasure(
+ filterIds: Array<Int>? = null,
+ reloadToken: Int,
+ @Surface.Rotation rotation: Int,
+ displayUniqueId: String? = null
+ ) {
+ filterIds?.forEach { id ->
+ viewProviderMap[id]?.let {
+ it.second.onReloadResAndMeasure(
+ view = it.first,
+ reloadToken = reloadToken,
+ displayUniqueId = displayUniqueId,
+ rotation = rotation)
+ }
+ } ?: run {
+ viewProviderMap.values.forEach {
+ it.second.onReloadResAndMeasure(
+ view = it.first,
+ reloadToken = reloadToken,
+ displayUniqueId = displayUniqueId,
+ rotation = rotation)
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/decor/PrivacyDotDecorProviderFactory.kt b/packages/SystemUI/src/com/android/systemui/decor/PrivacyDotDecorProviderFactory.kt
index 7afd7e0e..d16d960 100644
--- a/packages/SystemUI/src/com/android/systemui/decor/PrivacyDotDecorProviderFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/decor/PrivacyDotDecorProviderFactory.kt
@@ -16,6 +16,7 @@
package com.android.systemui.decor
+import android.content.Context
import android.content.res.Resources
import android.view.DisplayCutout
import android.view.LayoutInflater
@@ -38,6 +39,10 @@
override val hasProviders: Boolean
get() = isPrivacyDotEnabled
+ override fun onDisplayUniqueIdChanged(displayUniqueId: String?) {
+ // Do nothing for privacy dot
+ }
+
override val providers: List<DecorProvider>
get() {
return if (hasProviders) {
@@ -76,12 +81,21 @@
private val layoutId: Int
) : CornerDecorProvider() {
+ override fun onReloadResAndMeasure(
+ view: View,
+ reloadToken: Int,
+ rotation: Int,
+ displayUniqueId: String?
+ ) {
+ // Do nothing here because it is handled inside PrivacyDotViewController
+ }
+
override fun inflateView(
- inflater: LayoutInflater,
+ context: Context,
parent: ViewGroup,
@Surface.Rotation rotation: Int
): View {
- inflater.inflate(layoutId, parent, true)
+ LayoutInflater.from(context).inflate(layoutId, parent, true)
return parent.getChildAt(parent.childCount - 1 /* latest new added child */)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerDecorProviderFactory.kt b/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerDecorProviderFactory.kt
new file mode 100644
index 0000000..a4f7a58
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerDecorProviderFactory.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.decor
+
+import android.view.DisplayCutout
+import com.android.systemui.R
+
+class RoundedCornerDecorProviderFactory(
+ private val roundedCornerResDelegate: RoundedCornerResDelegate
+) : DecorProviderFactory() {
+
+ override val hasProviders: Boolean
+ get() = roundedCornerResDelegate.run {
+ // We don't consider isMultipleRadius here because it makes no sense if size is zero.
+ topRoundedSize.width > 0 || bottomRoundedSize.width > 0
+ }
+
+ override fun onDisplayUniqueIdChanged(displayUniqueId: String?) {
+ roundedCornerResDelegate.updateDisplayUniqueId(displayUniqueId, null)
+ }
+
+ override val providers: List<DecorProvider>
+ get() {
+ val hasTop = roundedCornerResDelegate.topRoundedSize.width > 0
+ val hasBottom = roundedCornerResDelegate.bottomRoundedSize.width > 0
+ return when {
+ hasTop && hasBottom -> listOf(
+ RoundedCornerDecorProviderImpl(
+ viewId = R.id.rounded_corner_top_left,
+ alignedBound1 = DisplayCutout.BOUNDS_POSITION_TOP,
+ alignedBound2 = DisplayCutout.BOUNDS_POSITION_LEFT,
+ roundedCornerResDelegate = roundedCornerResDelegate),
+ RoundedCornerDecorProviderImpl(
+ viewId = R.id.rounded_corner_top_right,
+ alignedBound1 = DisplayCutout.BOUNDS_POSITION_TOP,
+ alignedBound2 = DisplayCutout.BOUNDS_POSITION_RIGHT,
+ roundedCornerResDelegate = roundedCornerResDelegate),
+ RoundedCornerDecorProviderImpl(
+ viewId = R.id.rounded_corner_bottom_left,
+ alignedBound1 = DisplayCutout.BOUNDS_POSITION_BOTTOM,
+ alignedBound2 = DisplayCutout.BOUNDS_POSITION_LEFT,
+ roundedCornerResDelegate = roundedCornerResDelegate),
+ RoundedCornerDecorProviderImpl(
+ viewId = R.id.rounded_corner_bottom_right,
+ alignedBound1 = DisplayCutout.BOUNDS_POSITION_BOTTOM,
+ alignedBound2 = DisplayCutout.BOUNDS_POSITION_RIGHT,
+ roundedCornerResDelegate = roundedCornerResDelegate)
+ )
+ hasTop -> listOf(
+ RoundedCornerDecorProviderImpl(
+ viewId = R.id.rounded_corner_top_left,
+ alignedBound1 = DisplayCutout.BOUNDS_POSITION_TOP,
+ alignedBound2 = DisplayCutout.BOUNDS_POSITION_LEFT,
+ roundedCornerResDelegate = roundedCornerResDelegate),
+ RoundedCornerDecorProviderImpl(
+ viewId = R.id.rounded_corner_top_right,
+ alignedBound1 = DisplayCutout.BOUNDS_POSITION_TOP,
+ alignedBound2 = DisplayCutout.BOUNDS_POSITION_RIGHT,
+ roundedCornerResDelegate = roundedCornerResDelegate)
+ )
+ hasBottom -> listOf(
+ RoundedCornerDecorProviderImpl(
+ viewId = R.id.rounded_corner_bottom_left,
+ alignedBound1 = DisplayCutout.BOUNDS_POSITION_BOTTOM,
+ alignedBound2 = DisplayCutout.BOUNDS_POSITION_LEFT,
+ roundedCornerResDelegate = roundedCornerResDelegate),
+ RoundedCornerDecorProviderImpl(
+ viewId = R.id.rounded_corner_bottom_right,
+ alignedBound1 = DisplayCutout.BOUNDS_POSITION_BOTTOM,
+ alignedBound2 = DisplayCutout.BOUNDS_POSITION_RIGHT,
+ roundedCornerResDelegate = roundedCornerResDelegate)
+ )
+ else -> emptyList()
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerDecorProviderImpl.kt b/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerDecorProviderImpl.kt
new file mode 100644
index 0000000..90ff950
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerDecorProviderImpl.kt
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.decor
+
+import android.content.Context
+import android.view.DisplayCutout
+import android.view.Gravity
+import android.view.Surface
+import android.view.View
+import android.view.ViewGroup
+import android.widget.FrameLayout
+import android.widget.ImageView
+import com.android.systemui.R
+
+class RoundedCornerDecorProviderImpl(
+ override val viewId: Int,
+ @DisplayCutout.BoundsPosition override val alignedBound1: Int,
+ @DisplayCutout.BoundsPosition override val alignedBound2: Int,
+ private val roundedCornerResDelegate: RoundedCornerResDelegate
+) : CornerDecorProvider() {
+
+ private val isTop = alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_TOP)
+
+ override fun inflateView(
+ context: Context,
+ parent: ViewGroup,
+ @Surface.Rotation rotation: Int
+ ): View {
+ return ImageView(context).also { view ->
+ // View
+ view.id = viewId
+ initView(view, rotation)
+
+ // LayoutParams
+ val layoutSize = if (isTop) {
+ roundedCornerResDelegate.topRoundedSize
+ } else {
+ roundedCornerResDelegate.bottomRoundedSize
+ }
+ val params = FrameLayout.LayoutParams(
+ layoutSize.width,
+ layoutSize.height,
+ alignedBound1.toLayoutGravity(rotation) or
+ alignedBound2.toLayoutGravity(rotation))
+
+ // AddView
+ parent.addView(view, params)
+ }
+ }
+
+ private fun initView(view: ImageView, @Surface.Rotation rotation: Int) {
+ view.setRoundedCornerImage(roundedCornerResDelegate, isTop)
+ view.adjustRotation(alignedBounds, rotation)
+ view.setColorFilter(IMAGE_TINT_COLOR)
+ }
+
+ override fun onReloadResAndMeasure(
+ view: View,
+ reloadToken: Int,
+ @Surface.Rotation rotation: Int,
+ displayUniqueId: String?
+ ) {
+ roundedCornerResDelegate.updateDisplayUniqueId(displayUniqueId, reloadToken)
+
+ initView((view as ImageView), rotation)
+
+ val layoutSize = if (isTop) {
+ roundedCornerResDelegate.topRoundedSize
+ } else {
+ roundedCornerResDelegate.bottomRoundedSize
+ }
+ (view.layoutParams as FrameLayout.LayoutParams).let {
+ it.width = layoutSize.width
+ it.height = layoutSize.height
+ it.gravity = alignedBound1.toLayoutGravity(rotation) or
+ alignedBound2.toLayoutGravity(rotation)
+ view.setLayoutParams(it)
+ }
+ }
+}
+
+private const val IMAGE_TINT_COLOR: Int = 0xFF000000.toInt()
+
+@DisplayCutout.BoundsPosition
+private fun Int.toLayoutGravity(@Surface.Rotation rotation: Int): Int = when (rotation) {
+ Surface.ROTATION_0 -> when (this) {
+ DisplayCutout.BOUNDS_POSITION_LEFT -> Gravity.LEFT
+ DisplayCutout.BOUNDS_POSITION_TOP -> Gravity.TOP
+ DisplayCutout.BOUNDS_POSITION_RIGHT -> Gravity.RIGHT
+ else /* DisplayCutout.BOUNDS_POSITION_BOTTOM */ -> Gravity.BOTTOM
+ }
+ Surface.ROTATION_90 -> when (this) {
+ DisplayCutout.BOUNDS_POSITION_LEFT -> Gravity.BOTTOM
+ DisplayCutout.BOUNDS_POSITION_TOP -> Gravity.LEFT
+ DisplayCutout.BOUNDS_POSITION_RIGHT -> Gravity.TOP
+ else /* DisplayCutout.BOUNDS_POSITION_BOTTOM */ -> Gravity.LEFT
+ }
+ Surface.ROTATION_270 -> when (this) {
+ DisplayCutout.BOUNDS_POSITION_LEFT -> Gravity.TOP
+ DisplayCutout.BOUNDS_POSITION_TOP -> Gravity.RIGHT
+ DisplayCutout.BOUNDS_POSITION_RIGHT -> Gravity.BOTTOM
+ else /* DisplayCutout.BOUNDS_POSITION_BOTTOM */ -> Gravity.LEFT
+ }
+ else /* Surface.ROTATION_180 */ -> when (this) {
+ DisplayCutout.BOUNDS_POSITION_LEFT -> Gravity.RIGHT
+ DisplayCutout.BOUNDS_POSITION_TOP -> Gravity.BOTTOM
+ DisplayCutout.BOUNDS_POSITION_RIGHT -> Gravity.LEFT
+ else /* DisplayCutout.BOUNDS_POSITION_BOTTOM */ -> Gravity.TOP
+ }
+}
+
+private fun ImageView.setRoundedCornerImage(
+ resDelegate: RoundedCornerResDelegate,
+ isTop: Boolean
+) {
+ val drawable = if (isTop)
+ resDelegate.topRoundedDrawable
+ else
+ resDelegate.bottomRoundedDrawable
+
+ if (drawable != null) {
+ setImageDrawable(drawable)
+ } else {
+ setImageResource(
+ if (isTop)
+ R.drawable.rounded_corner_top
+ else
+ R.drawable.rounded_corner_bottom
+ )
+ }
+}
+
+/**
+ * Configures the rounded corner drawable's view matrix based on the gravity.
+ *
+ * The gravity describes which corner to configure for, and the drawable we are rotating is assumed
+ * to be oriented for the top-left corner of the device regardless of the target corner.
+ * Therefore we need to rotate 180 degrees to get a bottom-left corner, and mirror in the x- or
+ * y-axis for the top-right and bottom-left corners.
+ */
+private fun ImageView.adjustRotation(alignedBounds: List<Int>, @Surface.Rotation rotation: Int) {
+ var newRotation = 0F
+ var newScaleX = 1F
+ var newScaleY = 1F
+
+ val isTop = alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_TOP)
+ val isLeft = alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_LEFT)
+ when (rotation) {
+ Surface.ROTATION_0 -> when {
+ isTop && isLeft -> {}
+ isTop && !isLeft -> { newScaleX = -1F }
+ !isTop && isLeft -> { newScaleY = -1F }
+ else /* !isTop && !isLeft */ -> { newRotation = 180F }
+ }
+ Surface.ROTATION_90 -> when {
+ isTop && isLeft -> { newScaleY = -1F }
+ isTop && !isLeft -> {}
+ !isTop && isLeft -> { newRotation = 180F }
+ else /* !isTop && !isLeft */ -> { newScaleX = -1F }
+ }
+ Surface.ROTATION_270 -> when {
+ isTop && isLeft -> { newScaleX = -1F }
+ isTop && !isLeft -> { newRotation = 180F }
+ !isTop && isLeft -> {}
+ else /* !isTop && !isLeft */ -> { newScaleY = -1F }
+ }
+ else /* Surface.ROTATION_180 */ -> when {
+ isTop && isLeft -> { newRotation = 180F }
+ isTop && !isLeft -> { newScaleY = -1F }
+ !isTop && isLeft -> { newScaleX = -1F }
+ else /* !isTop && !isLeft */ -> {}
+ }
+ }
+
+ this.rotation = newRotation
+ this.scaleX = newScaleX
+ this.scaleY = newScaleY
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt b/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt
index ed175ef..c2bab26 100644
--- a/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt
@@ -35,6 +35,8 @@
private val density: Float
get() = res.displayMetrics.density
+ private var reloadToken: Int = 0
+
var isMultipleRadius: Boolean = false
private set
@@ -59,12 +61,26 @@
reloadMeasures()
}
- fun reloadAll(newDisplayUniqueId: String?) {
- displayUniqueId = newDisplayUniqueId
+ private fun reloadAll(newReloadToken: Int) {
+ if (reloadToken == newReloadToken) {
+ return
+ }
+ reloadToken = newReloadToken
reloadRes()
reloadMeasures()
}
+ fun updateDisplayUniqueId(newDisplayUniqueId: String?, newReloadToken: Int?) {
+ if (displayUniqueId != newDisplayUniqueId) {
+ displayUniqueId = newDisplayUniqueId
+ newReloadToken ?.let { reloadToken = it }
+ reloadRes()
+ reloadMeasures()
+ } else {
+ newReloadToken?.let { reloadAll(it) }
+ }
+ }
+
private fun reloadRes() {
val configIdx = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId)
isMultipleRadius = getIsMultipleRadius(configIdx)
@@ -122,7 +138,11 @@
}
}
- fun updateTuningSizeFactor(factor: Int) {
+ fun updateTuningSizeFactor(factor: Int?, newReloadToken: Int) {
+ if (reloadToken == newReloadToken) {
+ return
+ }
+ reloadToken = newReloadToken
reloadMeasures(factor)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index 50bd9b0..6bb994f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -27,14 +27,15 @@
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isA;
-import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -62,9 +63,11 @@
import android.view.Display;
import android.view.DisplayCutout;
import android.view.View;
+import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.WindowMetrics;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.test.filters.SmallTest;
@@ -103,7 +106,7 @@
private SecureSettings mSecureSettings;
private final FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
private FakeThreadFactory mThreadFactory;
- private ArrayList<DecorProvider> mDecorProviders;
+ private ArrayList<DecorProvider> mPrivacyDecorProviders;
@Mock
private Display mDisplay;
@Mock
@@ -216,16 +219,43 @@
}
}
- private void verifyRoundedCornerViewsVisibility(
+ @NonNull
+ private int[] getRoundCornerIdsFromOverlayId(@DisplayCutout.BoundsPosition int overlayId) {
+ switch (overlayId) {
+ case BOUNDS_POSITION_LEFT:
+ return new int[] {
+ R.id.rounded_corner_top_left,
+ R.id.rounded_corner_top_left };
+ case BOUNDS_POSITION_TOP:
+ return new int[] {
+ R.id.rounded_corner_top_left,
+ R.id.rounded_corner_top_right };
+ case BOUNDS_POSITION_RIGHT:
+ return new int[] {
+ R.id.rounded_corner_top_right,
+ R.id.rounded_corner_bottom_right };
+ case BOUNDS_POSITION_BOTTOM:
+ return new int[] {
+ R.id.rounded_corner_bottom_left,
+ R.id.rounded_corner_bottom_right };
+ default:
+ throw new IllegalArgumentException("unknown overlayId: " + overlayId);
+ }
+ }
+
+ private void verifyRoundedCornerViewsExist(
@DisplayCutout.BoundsPosition final int overlayId,
- @View.Visibility final int visibility) {
+ @View.Visibility final boolean isExist) {
final View overlay = mScreenDecorations.mOverlays[overlayId].getRootView();
- final View left = overlay.findViewById(R.id.left);
- final View right = overlay.findViewById(R.id.right);
- assertNotNull(left);
- assertNotNull(right);
- assertThat(left.getVisibility()).isEqualTo(visibility);
- assertThat(right.getVisibility()).isEqualTo(visibility);
+ for (int id: getRoundCornerIdsFromOverlayId(overlayId)) {
+ final View view = overlay.findViewById(id);
+ if (isExist) {
+ assertNotNull(view);
+ assertThat(view.getVisibility()).isEqualTo(View.VISIBLE);
+ } else {
+ assertNull(view);
+ }
+ }
}
@Nullable
@@ -388,8 +418,8 @@
mScreenDecorations.mPrivacyDotShowingListener);
// Rounded corner views shall not exist
- verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.GONE);
- verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.GONE);
+ verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, false);
+ verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, false);
// Privacy dots shall exist but invisible
verifyDotViewsVisibility(View.INVISIBLE);
@@ -417,8 +447,8 @@
verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE);
// Rounded corner views shall exist
- verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE);
- verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.VISIBLE);
+ verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, true);
+ verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, true);
// Privacy dots shall not exist
verifyDotViewsNullable(true);
@@ -447,8 +477,8 @@
verify(mDotViewController, times(1)).setShowingListener(null);
// Rounded corner views shall exist
- verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE);
- verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.VISIBLE);
+ verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, true);
+ verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, true);
// Privacy dots shall exist but invisible
verifyDotViewsVisibility(View.INVISIBLE);
@@ -488,21 +518,26 @@
mScreenDecorations.start();
View leftRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP].getRootView()
- .findViewById(R.id.left);
+ .findViewById(R.id.rounded_corner_top_left);
View rightRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP].getRootView()
- .findViewById(R.id.right);
- verify(mScreenDecorations, atLeastOnce())
- .setSize(leftRoundedCorner, new Size(testTopRadius, testTopRadius));
- verify(mScreenDecorations, atLeastOnce())
- .setSize(rightRoundedCorner, new Size(testTopRadius, testTopRadius));
+ .findViewById(R.id.rounded_corner_top_right);
+ ViewGroup.LayoutParams leftParams = leftRoundedCorner.getLayoutParams();
+ ViewGroup.LayoutParams rightParams = rightRoundedCorner.getLayoutParams();
+ assertEquals(leftParams.width, testTopRadius);
+ assertEquals(leftParams.height, testTopRadius);
+ assertEquals(rightParams.width, testTopRadius);
+ assertEquals(rightParams.height, testTopRadius);
+
leftRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM].getRootView()
- .findViewById(R.id.left);
+ .findViewById(R.id.rounded_corner_bottom_left);
rightRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM].getRootView()
- .findViewById(R.id.right);
- verify(mScreenDecorations, atLeastOnce())
- .setSize(leftRoundedCorner, new Size(testBottomRadius, testBottomRadius));
- verify(mScreenDecorations, atLeastOnce())
- .setSize(rightRoundedCorner, new Size(testBottomRadius, testBottomRadius));
+ .findViewById(R.id.rounded_corner_bottom_right);
+ leftParams = leftRoundedCorner.getLayoutParams();
+ rightParams = rightRoundedCorner.getLayoutParams();
+ assertEquals(leftParams.width, testBottomRadius);
+ assertEquals(leftParams.height, testBottomRadius);
+ assertEquals(rightParams.width, testBottomRadius);
+ assertEquals(rightParams.height, testBottomRadius);
}
@Test
@@ -518,31 +553,27 @@
.when(mScreenDecorations).getCutout();
mScreenDecorations.start();
- final Size topRadius = new Size(testTopRadius, testTopRadius);
- final Size bottomRadius = new Size(testBottomRadius, testBottomRadius);
- View leftRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT].getRootView()
- .findViewById(R.id.left);
- boolean isTop = mScreenDecorations.isTopRoundedCorner(BOUNDS_POSITION_LEFT, R.id.left);
- verify(mScreenDecorations, atLeastOnce())
- .setSize(leftRoundedCorner, isTop ? topRadius : bottomRadius);
+ View topRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT].getRootView()
+ .findViewById(R.id.rounded_corner_top_left);
+ View bottomRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT].getRootView()
+ .findViewById(R.id.rounded_corner_bottom_left);
+ ViewGroup.LayoutParams topParams = topRoundedCorner.getLayoutParams();
+ ViewGroup.LayoutParams bottomParams = bottomRoundedCorner.getLayoutParams();
+ assertEquals(topParams.width, testTopRadius);
+ assertEquals(topParams.height, testTopRadius);
+ assertEquals(bottomParams.width, testBottomRadius);
+ assertEquals(bottomParams.height, testBottomRadius);
- View rightRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT].getRootView()
- .findViewById(R.id.right);
- isTop = mScreenDecorations.isTopRoundedCorner(BOUNDS_POSITION_LEFT, R.id.right);
- verify(mScreenDecorations, atLeastOnce())
- .setSize(rightRoundedCorner, isTop ? topRadius : bottomRadius);
-
- leftRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT].getRootView()
- .findViewById(R.id.left);
- isTop = mScreenDecorations.isTopRoundedCorner(BOUNDS_POSITION_RIGHT, R.id.left);
- verify(mScreenDecorations, atLeastOnce())
- .setSize(leftRoundedCorner, isTop ? topRadius : bottomRadius);
-
- rightRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT].getRootView()
- .findViewById(R.id.right);
- isTop = mScreenDecorations.isTopRoundedCorner(BOUNDS_POSITION_RIGHT, R.id.right);
- verify(mScreenDecorations, atLeastOnce())
- .setSize(rightRoundedCorner, isTop ? topRadius : bottomRadius);
+ topRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT].getRootView()
+ .findViewById(R.id.rounded_corner_top_right);
+ bottomRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT].getRootView()
+ .findViewById(R.id.rounded_corner_bottom_right);
+ topParams = topRoundedCorner.getLayoutParams();
+ bottomParams = bottomRoundedCorner.getLayoutParams();
+ assertEquals(topParams.width, testTopRadius);
+ assertEquals(topParams.height, testTopRadius);
+ assertEquals(bottomParams.width, testBottomRadius);
+ assertEquals(bottomParams.height, testBottomRadius);
}
@Test
@@ -562,8 +593,8 @@
verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE);
// Rounded corner views shall exist
- verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE);
- verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.VISIBLE);
+ verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, true);
+ verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, true);
// Privacy dots shall not exist
verifyDotViewsNullable(true);
@@ -598,8 +629,8 @@
verify(mDotViewController, times(1)).setShowingListener(null);
// Rounded corner views shall exist
- verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE);
- verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.VISIBLE);
+ verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, true);
+ verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, true);
// Privacy dots shall exist but invisible
verifyDotViewsVisibility(View.INVISIBLE);
@@ -660,10 +691,10 @@
// Top rounded corner views shall exist because of cutout
// but be gone because of no rounded corner
- verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.GONE);
+ verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, false);
// Bottom rounded corner views shall exist because of privacy dot
// but be gone because of no rounded corner
- verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.GONE);
+ verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, false);
// Privacy dots shall exist but invisible
verifyDotViewsVisibility(View.INVISIBLE);
@@ -691,7 +722,7 @@
// Left rounded corner views shall exist because of cutout
// but be gone because of no rounded corner
- verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_LEFT, View.GONE);
+ verifyRoundedCornerViewsExist(BOUNDS_POSITION_LEFT, false);
// Top privacy dots shall not exist because of no privacy
verifyDotViewsNullable(true);
@@ -745,8 +776,8 @@
verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE);
// Rounded corner views shall exist
- verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE);
- verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.VISIBLE);
+ verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, true);
+ verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, true);
// Top privacy dots shall not exist because of no privacy dot
verifyDotViewsNullable(true);
@@ -775,8 +806,8 @@
verify(mDotViewController, times(1)).setShowingListener(null);
// Rounded corner views shall exist
- verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE);
- verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.VISIBLE);
+ verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, true);
+ verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, true);
// Top privacy dots shall exist but invisible
verifyDotViewsVisibility(View.INVISIBLE);
@@ -914,7 +945,7 @@
verify(mDotViewController, times(2)).setShowingListener(null);
// Verify each privacy dot id appears only once
- mDecorProviders.stream().map(DecorProvider::getViewId).forEach(viewId -> {
+ mPrivacyDecorProviders.stream().map(DecorProvider::getViewId).forEach(viewId -> {
int findCount = 0;
for (OverlayWindow overlay: mScreenDecorations.mOverlays) {
if (overlay == null) {
@@ -968,8 +999,8 @@
// Both top and bottom windows should be added with INVISIBLE because of only privacy dot,
// but rounded corners visibility shall be gone because of no rounding.
verifyOverlaysExistAndAdded(false, true, false, true, View.INVISIBLE);
- verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.GONE);
- verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.GONE);
+ verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, false);
+ verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, false);
verify(mDotViewController, times(1)).initialize(any(), any(), any(), any());
verify(mDotViewController, times(1)).setShowingListener(
mScreenDecorations.mPrivacyDotShowingListener);
@@ -982,8 +1013,8 @@
// Both top and bottom windows should be added with VISIBLE because of privacy dot and
// cutout, but rounded corners visibility shall be gone because of no rounding.
verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE);
- verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.GONE);
- verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.GONE);
+ verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, false);
+ verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, false);
verify(mDotViewController, times(2)).initialize(any(), any(), any(), any());
verify(mDotViewController, times(1)).setShowingListener(null);
}
@@ -1297,6 +1328,48 @@
verify(cutoutView, times(1)).onDisplayChanged(1);
}
+ @Test
+ public void testHasSameProvidersWithNullOverlays() {
+ setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+ 0 /* roundedPadding */, false /* multipleRadius */,
+ false /* fillCutout */, false /* privacyDot */);
+
+ mScreenDecorations.start();
+
+ final ArrayList<DecorProvider> newProviders = new ArrayList<>();
+ assertTrue(mScreenDecorations.hasSameProviders(newProviders));
+
+ newProviders.add(mPrivacyDotTopLeftDecorProvider);
+ assertFalse(mScreenDecorations.hasSameProviders(newProviders));
+
+ newProviders.add(mPrivacyDotTopRightDecorProvider);
+ assertFalse(mScreenDecorations.hasSameProviders(newProviders));
+ }
+
+ @Test
+ public void testHasSameProvidersWithPrivacyDots() {
+ setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+ 0 /* roundedPadding */, false /* multipleRadius */,
+ true /* fillCutout */, true /* privacyDot */);
+
+ mScreenDecorations.start();
+
+ final ArrayList<DecorProvider> newProviders = new ArrayList<>();
+ assertFalse(mScreenDecorations.hasSameProviders(newProviders));
+
+ newProviders.add(mPrivacyDotTopLeftDecorProvider);
+ assertFalse(mScreenDecorations.hasSameProviders(newProviders));
+
+ newProviders.add(mPrivacyDotTopRightDecorProvider);
+ assertFalse(mScreenDecorations.hasSameProviders(newProviders));
+
+ newProviders.add(mPrivacyDotBottomLeftDecorProvider);
+ assertFalse(mScreenDecorations.hasSameProviders(newProviders));
+
+ newProviders.add(mPrivacyDotBottomRightDecorProvider);
+ assertTrue(mScreenDecorations.hasSameProviders(newProviders));
+ }
+
private void setupResources(int radius, int radiusTop, int radiusBottom, int roundedPadding,
boolean multipleRadius, boolean fillCutout, boolean privacyDot) {
mContext.getOrCreateTestableResources().addOverride(
@@ -1336,14 +1409,14 @@
mContext.getOrCreateTestableResources().addOverride(
com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, fillCutout);
- mDecorProviders = new ArrayList<>();
+ mPrivacyDecorProviders = new ArrayList<>();
if (privacyDot) {
- mDecorProviders.add(mPrivacyDotTopLeftDecorProvider);
- mDecorProviders.add(mPrivacyDotTopRightDecorProvider);
- mDecorProviders.add(mPrivacyDotBottomLeftDecorProvider);
- mDecorProviders.add(mPrivacyDotBottomRightDecorProvider);
+ mPrivacyDecorProviders.add(mPrivacyDotTopLeftDecorProvider);
+ mPrivacyDecorProviders.add(mPrivacyDotTopRightDecorProvider);
+ mPrivacyDecorProviders.add(mPrivacyDotBottomLeftDecorProvider);
+ mPrivacyDecorProviders.add(mPrivacyDotBottomRightDecorProvider);
}
- when(mPrivacyDotDecorProviderFactory.getProviders()).thenReturn(mDecorProviders);
+ when(mPrivacyDotDecorProviderFactory.getProviders()).thenReturn(mPrivacyDecorProviders);
when(mPrivacyDotDecorProviderFactory.getHasProviders()).thenReturn(privacyDot);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/OverlayWindowTest.kt b/packages/SystemUI/tests/src/com/android/systemui/decor/OverlayWindowTest.kt
index ca74df0..69366fa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/decor/OverlayWindowTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/decor/OverlayWindowTest.kt
@@ -19,25 +19,19 @@
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.DisplayCutout
-import android.view.LayoutInflater
import android.view.Surface
import android.view.View
-import android.view.ViewGroup
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
-import com.android.systemui.util.mockito.eq
import org.junit.Assert
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Mockito
-import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.never
import org.mockito.Mockito.spy
+import org.mockito.Mockito.times
import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
-import org.mockito.Mockito.`when` as whenever
@RunWith(AndroidTestingRunner::class)
@RunWithLooper(setAsMainLooper = true)
@@ -45,62 +39,144 @@
class OverlayWindowTest : SysuiTestCase() {
companion object {
- private val TEST_DECOR_VIEW_ID = R.id.privacy_dot_bottom_right_container
- private val TEST_DECOR_LAYOUT_ID = R.layout.privacy_dot_bottom_right
+ private val TEST_DECOR_VIEW_ID_1 = R.id.privacy_dot_top_left_container
+ private val TEST_DECOR_VIEW_ID_2 = R.id.privacy_dot_bottom_left_container
+ private val TEST_DECOR_VIEW_ID_3 = R.id.privacy_dot_bottom_right_container
}
private lateinit var overlay: OverlayWindow
-
- @Mock private lateinit var layoutInflater: LayoutInflater
- @Mock private lateinit var decorProvider: DecorProvider
+ private lateinit var decorProvider1: DecorProvider
+ private lateinit var decorProvider2: DecorProvider
+ private lateinit var decorProvider3: DecorProvider
@Before
fun setUp() {
- MockitoAnnotations.initMocks(this)
+ decorProvider1 = spy(PrivacyDotCornerDecorProviderImpl(
+ viewId = TEST_DECOR_VIEW_ID_1,
+ alignedBound1 = DisplayCutout.BOUNDS_POSITION_TOP,
+ alignedBound2 = DisplayCutout.BOUNDS_POSITION_LEFT,
+ layoutId = R.layout.privacy_dot_top_left))
+ decorProvider2 = spy(PrivacyDotCornerDecorProviderImpl(
+ viewId = TEST_DECOR_VIEW_ID_2,
+ alignedBound1 = DisplayCutout.BOUNDS_POSITION_BOTTOM,
+ alignedBound2 = DisplayCutout.BOUNDS_POSITION_LEFT,
+ layoutId = R.layout.privacy_dot_bottom_left))
+ decorProvider3 = spy(PrivacyDotCornerDecorProviderImpl(
+ viewId = TEST_DECOR_VIEW_ID_3,
+ alignedBound1 = DisplayCutout.BOUNDS_POSITION_BOTTOM,
+ alignedBound2 = DisplayCutout.BOUNDS_POSITION_RIGHT,
+ layoutId = R.layout.privacy_dot_bottom_right))
- layoutInflater = spy(LayoutInflater.from(mContext))
-
- overlay = OverlayWindow(layoutInflater, DisplayCutout.BOUNDS_POSITION_RIGHT)
-
- whenever(decorProvider.viewId).thenReturn(TEST_DECOR_VIEW_ID)
- whenever(decorProvider.inflateView(
- eq(layoutInflater),
- eq(overlay.rootView),
- anyInt())
- ).then {
- val layoutInflater = it.getArgument<LayoutInflater>(0)
- val parent = it.getArgument<ViewGroup>(1)
- layoutInflater.inflate(TEST_DECOR_LAYOUT_ID, parent)
- return@then parent.getChildAt(parent.childCount - 1)
- }
- }
-
- @Test
- fun testAnyBoundsPositionShallNoExceptionForConstructor() {
- OverlayWindow(layoutInflater, DisplayCutout.BOUNDS_POSITION_LEFT)
- OverlayWindow(layoutInflater, DisplayCutout.BOUNDS_POSITION_TOP)
- OverlayWindow(layoutInflater, DisplayCutout.BOUNDS_POSITION_RIGHT)
- OverlayWindow(layoutInflater, DisplayCutout.BOUNDS_POSITION_BOTTOM)
+ overlay = OverlayWindow(mContext)
}
@Test
fun testAddProvider() {
@Surface.Rotation val rotation = Surface.ROTATION_270
- overlay.addDecorProvider(decorProvider, rotation)
- verify(decorProvider, Mockito.times(1)).inflateView(
- eq(layoutInflater), eq(overlay.rootView), eq(rotation))
- val viewFoundFromRootView = overlay.rootView.findViewById<View>(TEST_DECOR_VIEW_ID)
- Assert.assertNotNull(viewFoundFromRootView)
- Assert.assertEquals(viewFoundFromRootView, overlay.getView(TEST_DECOR_VIEW_ID))
+ overlay.addDecorProvider(decorProvider1, rotation)
+ overlay.addDecorProvider(decorProvider2, rotation)
+
+ verify(decorProvider1, times(1)).inflateView(
+ mContext, overlay.rootView, rotation)
+ verify(decorProvider2, times(1)).inflateView(
+ mContext, overlay.rootView, rotation)
+
+ val view1FoundFromRootView = overlay.rootView.findViewById<View>(TEST_DECOR_VIEW_ID_1)
+ Assert.assertNotNull(view1FoundFromRootView)
+ Assert.assertEquals(view1FoundFromRootView, overlay.getView(TEST_DECOR_VIEW_ID_1))
+ val view2FoundFromRootView = overlay.rootView.findViewById<View>(TEST_DECOR_VIEW_ID_2)
+ Assert.assertNotNull(view2FoundFromRootView)
+ Assert.assertEquals(view2FoundFromRootView, overlay.getView(TEST_DECOR_VIEW_ID_2))
}
@Test
fun testRemoveView() {
- @Surface.Rotation val rotation = Surface.ROTATION_270
- overlay.addDecorProvider(decorProvider, rotation)
- overlay.removeView(TEST_DECOR_VIEW_ID)
- val viewFoundFromRootView = overlay.rootView.findViewById<View>(TEST_DECOR_VIEW_ID)
+ overlay.addDecorProvider(decorProvider1, Surface.ROTATION_270)
+ overlay.addDecorProvider(decorProvider2, Surface.ROTATION_270)
+ overlay.removeView(TEST_DECOR_VIEW_ID_1)
+
+ val viewFoundFromRootView = overlay.rootView.findViewById<View>(TEST_DECOR_VIEW_ID_1)
Assert.assertNull(viewFoundFromRootView)
- Assert.assertNull(overlay.getView(TEST_DECOR_LAYOUT_ID))
+ Assert.assertNull(overlay.getView(TEST_DECOR_VIEW_ID_1))
+ }
+
+ @Test
+ fun testOnReloadResAndMeasureWithoutIds() {
+ overlay.addDecorProvider(decorProvider1, Surface.ROTATION_0)
+ overlay.addDecorProvider(decorProvider2, Surface.ROTATION_0)
+
+ overlay.onReloadResAndMeasure(
+ reloadToken = 1,
+ rotation = Surface.ROTATION_90,
+ displayUniqueId = null)
+ verify(decorProvider1, times(1)).onReloadResAndMeasure(
+ overlay.getView(TEST_DECOR_VIEW_ID_1)!!, 1, Surface.ROTATION_90, null)
+ verify(decorProvider2, times(1)).onReloadResAndMeasure(
+ overlay.getView(TEST_DECOR_VIEW_ID_2)!!, 1, Surface.ROTATION_90, null)
+ }
+
+ @Test
+ fun testOnReloadResAndMeasureWithIds() {
+ overlay.addDecorProvider(decorProvider1, Surface.ROTATION_0)
+ overlay.addDecorProvider(decorProvider2, Surface.ROTATION_0)
+
+ overlay.onReloadResAndMeasure(
+ filterIds = arrayOf(TEST_DECOR_VIEW_ID_2),
+ reloadToken = 1,
+ rotation = Surface.ROTATION_90,
+ displayUniqueId = null)
+ verify(decorProvider1, never()).onReloadResAndMeasure(
+ overlay.getView(TEST_DECOR_VIEW_ID_1)!!, 1, Surface.ROTATION_90, null)
+ verify(decorProvider2, times(1)).onReloadResAndMeasure(
+ overlay.getView(TEST_DECOR_VIEW_ID_2)!!, 1, Surface.ROTATION_90, null)
+ }
+
+ @Test
+ fun testRemoveRedundantViewsWithNullParameter() {
+ overlay.addDecorProvider(decorProvider1, Surface.ROTATION_270)
+ overlay.addDecorProvider(decorProvider2, Surface.ROTATION_270)
+
+ overlay.removeRedundantViews(null)
+
+ Assert.assertNull(overlay.getView(TEST_DECOR_VIEW_ID_1))
+ Assert.assertNull(overlay.rootView.findViewById(TEST_DECOR_VIEW_ID_1))
+ Assert.assertNull(overlay.getView(TEST_DECOR_VIEW_ID_2))
+ Assert.assertNull(overlay.rootView.findViewById(TEST_DECOR_VIEW_ID_2))
+ }
+
+ @Test
+ fun testRemoveRedundantViewsWith2Providers() {
+ overlay.addDecorProvider(decorProvider1, Surface.ROTATION_270)
+ overlay.addDecorProvider(decorProvider2, Surface.ROTATION_270)
+
+ overlay.removeRedundantViews(IntArray(2).apply {
+ this[0] = TEST_DECOR_VIEW_ID_3
+ this[1] = TEST_DECOR_VIEW_ID_1
+ })
+
+ Assert.assertNotNull(overlay.getView(TEST_DECOR_VIEW_ID_1))
+ Assert.assertNotNull(overlay.rootView.findViewById(TEST_DECOR_VIEW_ID_1))
+ Assert.assertNull(overlay.getView(TEST_DECOR_VIEW_ID_2))
+ Assert.assertNull(overlay.rootView.findViewById(TEST_DECOR_VIEW_ID_2))
+ }
+
+ @Test
+ fun testHasSameProviders() {
+ Assert.assertTrue(overlay.hasSameProviders(emptyList()))
+ Assert.assertFalse(overlay.hasSameProviders(listOf(decorProvider1)))
+ Assert.assertFalse(overlay.hasSameProviders(listOf(decorProvider2)))
+ Assert.assertFalse(overlay.hasSameProviders(listOf(decorProvider2, decorProvider1)))
+
+ overlay.addDecorProvider(decorProvider1, Surface.ROTATION_0)
+ Assert.assertFalse(overlay.hasSameProviders(emptyList()))
+ Assert.assertTrue(overlay.hasSameProviders(listOf(decorProvider1)))
+ Assert.assertFalse(overlay.hasSameProviders(listOf(decorProvider2)))
+ Assert.assertFalse(overlay.hasSameProviders(listOf(decorProvider2, decorProvider1)))
+
+ overlay.addDecorProvider(decorProvider2, Surface.ROTATION_0)
+ Assert.assertFalse(overlay.hasSameProviders(emptyList()))
+ Assert.assertFalse(overlay.hasSameProviders(listOf(decorProvider1)))
+ Assert.assertFalse(overlay.hasSameProviders(listOf(decorProvider2)))
+ Assert.assertTrue(overlay.hasSameProviders(listOf(decorProvider2, decorProvider1)))
}
}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/PrivacyDotDecorProviderFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/decor/PrivacyDotDecorProviderFactoryTest.kt
index bac0817..171b767 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/decor/PrivacyDotDecorProviderFactoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/decor/PrivacyDotDecorProviderFactoryTest.kt
@@ -18,7 +18,6 @@
import android.content.res.Resources
import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper.RunWithLooper
import android.view.DisplayCutout
import androidx.test.filters.SmallTest
import com.android.systemui.R
@@ -32,7 +31,6 @@
import org.mockito.Mockito.`when` as whenever
@RunWith(AndroidTestingRunner::class)
-@RunWithLooper(setAsMainLooper = true)
@SmallTest
class PrivacyDotDecorProviderFactoryTest : SysuiTestCase() {
private lateinit var mPrivacyDotDecorProviderFactory: PrivacyDotDecorProviderFactory
diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerDecorProviderFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerDecorProviderFactoryTest.kt
new file mode 100644
index 0000000..621bcf6
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerDecorProviderFactoryTest.kt
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.decor
+
+import android.testing.AndroidTestingRunner
+import android.util.Size
+import android.view.DisplayCutout
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import org.junit.Assert
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.spy
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class RoundedCornerDecorProviderFactoryTest : SysuiTestCase() {
+
+ @Mock private lateinit var roundedCornerResDelegate: RoundedCornerResDelegate
+ private lateinit var roundedCornerDecorProviderFactory: RoundedCornerDecorProviderFactory
+
+ @Before
+ fun setUp() {
+ roundedCornerResDelegate = spy(RoundedCornerResDelegate(mContext.resources, null))
+ }
+
+ @Test
+ fun testNoRoundedCorners() {
+ Mockito.doReturn(Size(0, 0)).`when`(roundedCornerResDelegate).topRoundedSize
+ Mockito.doReturn(Size(0, 0)).`when`(roundedCornerResDelegate).bottomRoundedSize
+ Mockito.doReturn(false).`when`(roundedCornerResDelegate).isMultipleRadius
+
+ roundedCornerDecorProviderFactory =
+ RoundedCornerDecorProviderFactory(roundedCornerResDelegate)
+
+ Assert.assertEquals(false, roundedCornerDecorProviderFactory.hasProviders)
+ Assert.assertEquals(0, roundedCornerDecorProviderFactory.providers.size)
+ }
+
+ @Test
+ fun testHasRoundedCornersIfTopWidthLargerThan0() {
+ Mockito.doReturn(Size(1, 0)).`when`(roundedCornerResDelegate).topRoundedSize
+ Mockito.doReturn(Size(0, 0)).`when`(roundedCornerResDelegate).bottomRoundedSize
+ Mockito.doReturn(false).`when`(roundedCornerResDelegate).isMultipleRadius
+
+ roundedCornerDecorProviderFactory =
+ RoundedCornerDecorProviderFactory(roundedCornerResDelegate)
+
+ Assert.assertEquals(true, roundedCornerDecorProviderFactory.hasProviders)
+ roundedCornerDecorProviderFactory.providers.let { providers ->
+ Assert.assertEquals(2, providers.size)
+ Assert.assertEquals(1, providers.count {
+ ((it.viewId == R.id.rounded_corner_top_left)
+ and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_TOP)
+ and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_LEFT))
+ })
+ Assert.assertEquals(1, providers.count {
+ ((it.viewId == R.id.rounded_corner_top_right)
+ and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_TOP)
+ and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_RIGHT))
+ })
+ }
+ }
+
+ @Test
+ fun testHasRoundedCornersIfBottomWidthLargerThan0() {
+ Mockito.doReturn(Size(0, 0)).`when`(roundedCornerResDelegate).topRoundedSize
+ Mockito.doReturn(Size(1, 1)).`when`(roundedCornerResDelegate).bottomRoundedSize
+ Mockito.doReturn(false).`when`(roundedCornerResDelegate).isMultipleRadius
+
+ roundedCornerDecorProviderFactory =
+ RoundedCornerDecorProviderFactory(roundedCornerResDelegate)
+
+ Assert.assertEquals(true, roundedCornerDecorProviderFactory.hasProviders)
+ roundedCornerDecorProviderFactory.providers.let { providers ->
+ Assert.assertEquals(2, providers.size)
+ Assert.assertEquals(1, providers.count {
+ ((it.viewId == R.id.rounded_corner_bottom_left)
+ and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_BOTTOM)
+ and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_LEFT))
+ })
+ Assert.assertEquals(1, providers.count {
+ ((it.viewId == R.id.rounded_corner_bottom_right)
+ and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_BOTTOM)
+ and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_RIGHT))
+ })
+ }
+ }
+
+ @Test
+ fun test4CornerDecorProvidersInfo() {
+ Mockito.doReturn(Size(10, 10)).`when`(roundedCornerResDelegate).topRoundedSize
+ Mockito.doReturn(Size(10, 10)).`when`(roundedCornerResDelegate).bottomRoundedSize
+ Mockito.doReturn(true).`when`(roundedCornerResDelegate).isMultipleRadius
+
+ roundedCornerDecorProviderFactory =
+ RoundedCornerDecorProviderFactory(roundedCornerResDelegate)
+
+ Assert.assertEquals(true, roundedCornerDecorProviderFactory.hasProviders)
+ roundedCornerDecorProviderFactory.providers.let { providers ->
+ Assert.assertEquals(4, providers.size)
+ Assert.assertEquals(1, providers.count {
+ ((it.viewId == R.id.rounded_corner_top_left)
+ and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_TOP)
+ and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_LEFT))
+ })
+ Assert.assertEquals(1, providers.count {
+ ((it.viewId == R.id.rounded_corner_top_right)
+ and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_TOP)
+ and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_RIGHT))
+ })
+ Assert.assertEquals(1, providers.count {
+ ((it.viewId == R.id.rounded_corner_bottom_left)
+ and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_BOTTOM)
+ and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_LEFT))
+ })
+ Assert.assertEquals(1, providers.count {
+ ((it.viewId == R.id.rounded_corner_bottom_right)
+ and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_BOTTOM)
+ and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_RIGHT))
+ })
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt
index 2effaec..1fec380 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt
@@ -45,7 +45,7 @@
}
@Test
- fun testReloadAllAndDefaultRadius() {
+ fun testUpdateDisplayUniqueId() {
mContext.orCreateTestableResources.addOverrides(
mockTypeArray = mockTypedArray,
radius = 3,
@@ -65,7 +65,34 @@
radiusTop = 6,
radiusBottom = 0)
- roundedCornerResDelegate.reloadAll("test")
+ roundedCornerResDelegate.updateDisplayUniqueId("test", null)
+
+ assertEquals(Size(6, 6), roundedCornerResDelegate.topRoundedSize)
+ assertEquals(Size(5, 5), roundedCornerResDelegate.bottomRoundedSize)
+ }
+
+ @Test
+ fun testNotUpdateDisplayUniqueIdButChangeRefreshToken() {
+ mContext.orCreateTestableResources.addOverrides(
+ mockTypeArray = mockTypedArray,
+ radius = 3,
+ radiusTop = 0,
+ radiusBottom = 4,
+ multipleRadius = false)
+
+ roundedCornerResDelegate = RoundedCornerResDelegate(mContext.resources, null)
+
+ assertEquals(Size(3, 3), roundedCornerResDelegate.topRoundedSize)
+ assertEquals(Size(4, 4), roundedCornerResDelegate.bottomRoundedSize)
+ assertEquals(false, roundedCornerResDelegate.isMultipleRadius)
+
+ mContext.orCreateTestableResources.addOverrides(
+ mockTypeArray = mockTypedArray,
+ radius = 5,
+ radiusTop = 6,
+ radiusBottom = 0)
+
+ roundedCornerResDelegate.updateDisplayUniqueId(null, 1)
assertEquals(Size(6, 6), roundedCornerResDelegate.topRoundedSize)
assertEquals(Size(5, 5), roundedCornerResDelegate.bottomRoundedSize)
@@ -82,11 +109,21 @@
roundedCornerResDelegate = RoundedCornerResDelegate(mContext.resources, null)
val factor = 5
- roundedCornerResDelegate.updateTuningSizeFactor(factor)
+ roundedCornerResDelegate.updateTuningSizeFactor(factor, 1)
val length = (factor * mContext.resources.displayMetrics.density).toInt()
assertEquals(Size(length, length), roundedCornerResDelegate.topRoundedSize)
assertEquals(Size(length, length), roundedCornerResDelegate.bottomRoundedSize)
+
+ mContext.orCreateTestableResources.addOverrides(
+ mockTypeArray = mockTypedArray,
+ radiusTop = 1,
+ radiusBottom = 2,
+ multipleRadius = false)
+ roundedCornerResDelegate.updateTuningSizeFactor(null, 2)
+
+ assertEquals(Size(1, 1), roundedCornerResDelegate.topRoundedSize)
+ assertEquals(Size(2, 2), roundedCornerResDelegate.bottomRoundedSize)
}
@Test