Merge "Revert "Move rounded corner to provider"" into tm-dev
This commit is contained in:
40
packages/SystemUI/res/layout/rounded_corners_bottom.xml
Normal file
40
packages/SystemUI/res/layout/rounded_corners_bottom.xml
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<?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>
|
||||||
40
packages/SystemUI/res/layout/rounded_corners_top.xml
Normal file
40
packages/SystemUI/res/layout/rounded_corners_top.xml
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<?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>
|
||||||
@@ -167,11 +167,5 @@
|
|||||||
<item type="id" name="action_move_bottom_right"/>
|
<item type="id" name="action_move_bottom_right"/>
|
||||||
<item type="id" name="action_move_to_edge_and_hide"/>
|
<item type="id" name="action_move_to_edge_and_hide"/>
|
||||||
<item type="id" name="action_move_out_edge_and_show"/>
|
<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>
|
</resources>
|
||||||
|
|
||||||
|
|||||||
@@ -369,15 +369,10 @@ class ScreenDecorHwcLayer(context: Context, displayDecorationSupport: DisplayDec
|
|||||||
* Update the rounded corner size.
|
* Update the rounded corner size.
|
||||||
*/
|
*/
|
||||||
fun updateRoundedCornerSize(top: Int, bottom: Int) {
|
fun updateRoundedCornerSize(top: Int, bottom: Int) {
|
||||||
if (roundedCornerTopSize == top && roundedCornerBottomSize == bottom) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
roundedCornerTopSize = top
|
roundedCornerTopSize = top
|
||||||
roundedCornerBottomSize = bottom
|
roundedCornerBottomSize = bottom
|
||||||
updateRoundedCornerDrawableBounds()
|
updateRoundedCornerDrawableBounds()
|
||||||
|
invalidate()
|
||||||
// Use requestLayout() to trigger transparent region recalculated
|
|
||||||
requestLayout()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateRoundedCornerDrawableBounds() {
|
private fun updateRoundedCornerDrawableBounds() {
|
||||||
|
|||||||
@@ -77,7 +77,6 @@ import com.android.systemui.decor.DecorProviderFactory;
|
|||||||
import com.android.systemui.decor.DecorProviderKt;
|
import com.android.systemui.decor.DecorProviderKt;
|
||||||
import com.android.systemui.decor.OverlayWindow;
|
import com.android.systemui.decor.OverlayWindow;
|
||||||
import com.android.systemui.decor.PrivacyDotDecorProviderFactory;
|
import com.android.systemui.decor.PrivacyDotDecorProviderFactory;
|
||||||
import com.android.systemui.decor.RoundedCornerDecorProviderFactory;
|
|
||||||
import com.android.systemui.decor.RoundedCornerResDelegate;
|
import com.android.systemui.decor.RoundedCornerResDelegate;
|
||||||
import com.android.systemui.qs.SettingObserver;
|
import com.android.systemui.qs.SettingObserver;
|
||||||
import com.android.systemui.settings.UserTracker;
|
import com.android.systemui.settings.UserTracker;
|
||||||
@@ -139,9 +138,6 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
protected RoundedCornerResDelegate mRoundedCornerResDelegate;
|
protected RoundedCornerResDelegate mRoundedCornerResDelegate;
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
protected DecorProviderFactory mRoundedCornerFactory;
|
|
||||||
private int mProviderRefreshToken = 0;
|
|
||||||
@VisibleForTesting
|
|
||||||
protected OverlayWindow[] mOverlays = null;
|
protected OverlayWindow[] mOverlays = null;
|
||||||
@Nullable
|
@Nullable
|
||||||
private DisplayCutoutView[] mCutoutViews;
|
private DisplayCutoutView[] mCutoutViews;
|
||||||
@@ -296,11 +292,11 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
|
|||||||
mDisplayUniqueId = mContext.getDisplay().getUniqueId();
|
mDisplayUniqueId = mContext.getDisplay().getUniqueId();
|
||||||
mRoundedCornerResDelegate = new RoundedCornerResDelegate(mContext.getResources(),
|
mRoundedCornerResDelegate = new RoundedCornerResDelegate(mContext.getResources(),
|
||||||
mDisplayUniqueId);
|
mDisplayUniqueId);
|
||||||
mRoundedCornerFactory = new RoundedCornerDecorProviderFactory(mRoundedCornerResDelegate);
|
|
||||||
mWindowManager = mContext.getSystemService(WindowManager.class);
|
mWindowManager = mContext.getSystemService(WindowManager.class);
|
||||||
mDisplayManager = mContext.getSystemService(DisplayManager.class);
|
mDisplayManager = mContext.getSystemService(DisplayManager.class);
|
||||||
mHwcScreenDecorationSupport = mContext.getDisplay().getDisplayDecorationSupport();
|
mHwcScreenDecorationSupport = mContext.getDisplay().getDisplayDecorationSupport();
|
||||||
updateHwLayerRoundedCornerDrawable();
|
updateRoundedCornerDrawable();
|
||||||
|
updateRoundedCornerRadii();
|
||||||
setupDecorations();
|
setupDecorations();
|
||||||
setupCameraListener();
|
setupCameraListener();
|
||||||
|
|
||||||
@@ -352,7 +348,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
|
|||||||
final String newUniqueId = mContext.getDisplay().getUniqueId();
|
final String newUniqueId = mContext.getDisplay().getUniqueId();
|
||||||
if (!Objects.equals(newUniqueId, mDisplayUniqueId)) {
|
if (!Objects.equals(newUniqueId, mDisplayUniqueId)) {
|
||||||
mDisplayUniqueId = newUniqueId;
|
mDisplayUniqueId = newUniqueId;
|
||||||
mRoundedCornerResDelegate.updateDisplayUniqueId(newUniqueId, null);
|
mRoundedCornerResDelegate.reloadAll(newUniqueId);
|
||||||
final DisplayDecorationSupport newScreenDecorationSupport =
|
final DisplayDecorationSupport newScreenDecorationSupport =
|
||||||
mContext.getDisplay().getDisplayDecorationSupport();
|
mContext.getDisplay().getDisplayDecorationSupport();
|
||||||
// When the value of mSupportHwcScreenDecoration is changed, re-setup the whole
|
// When the value of mSupportHwcScreenDecoration is changed, re-setup the whole
|
||||||
@@ -363,12 +359,12 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
|
|||||||
setupDecorations();
|
setupDecorations();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
updateHwLayerRoundedCornerDrawable();
|
updateRoundedCornerDrawable();
|
||||||
}
|
}
|
||||||
if (mScreenDecorHwcLayer != null) {
|
if (mScreenDecorHwcLayer != null) {
|
||||||
mScreenDecorHwcLayer.onDisplayChanged(displayId);
|
mScreenDecorHwcLayer.onDisplayChanged(displayId);
|
||||||
}
|
}
|
||||||
updateView();
|
updateOrientation();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -410,22 +406,22 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setupDecorations() {
|
private void setupDecorations() {
|
||||||
if (hasRoundedCorners() || shouldDrawCutout() || isPrivacyDotEnabled()) {
|
List<DecorProvider> decorProviders = mDotFactory.getProviders();
|
||||||
List<DecorProvider> decorProviders = new ArrayList<>(mDotFactory.getProviders());
|
|
||||||
|
if (hasRoundedCorners() || shouldDrawCutout() || !decorProviders.isEmpty()) {
|
||||||
if (mHwcScreenDecorationSupport != null) {
|
if (mHwcScreenDecorationSupport != null) {
|
||||||
createHwcOverlay();
|
createHwcOverlay();
|
||||||
} else {
|
} else {
|
||||||
removeHwcOverlay();
|
removeHwcOverlay();
|
||||||
decorProviders.addAll(mRoundedCornerFactory.getProviders());
|
|
||||||
}
|
}
|
||||||
final DisplayCutout cutout = getCutout();
|
final DisplayCutout cutout = getCutout();
|
||||||
for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
|
for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
|
||||||
if (shouldShowSwLayerCutout(i, cutout) || shouldShowSwLayerRoundedCorner(i, cutout)
|
if (shouldShowCutout(i, cutout) || shouldShowRoundedCorner(i, cutout)
|
||||||
|| shouldShowSwLayerPrivacyDot(i, cutout)) {
|
|| shouldShowPrivacyDot(i, cutout)) {
|
||||||
Pair<List<DecorProvider>, List<DecorProvider>> pair =
|
Pair<List<DecorProvider>, List<DecorProvider>> pair =
|
||||||
DecorProviderKt.partitionAlignedBound(decorProviders, i);
|
DecorProviderKt.partitionAlignedBound(decorProviders, i);
|
||||||
decorProviders = pair.getSecond();
|
decorProviders = pair.getSecond();
|
||||||
createOverlay(i, pair.getFirst());
|
createOverlay(i, cutout, pair.getFirst());
|
||||||
} else {
|
} else {
|
||||||
removeOverlay(i);
|
removeOverlay(i);
|
||||||
}
|
}
|
||||||
@@ -526,6 +522,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
|
|||||||
|
|
||||||
private void createOverlay(
|
private void createOverlay(
|
||||||
@BoundsPosition int pos,
|
@BoundsPosition int pos,
|
||||||
|
@Nullable DisplayCutout cutout,
|
||||||
@NonNull List<DecorProvider> decorProviders) {
|
@NonNull List<DecorProvider> decorProviders) {
|
||||||
if (mOverlays == null) {
|
if (mOverlays == null) {
|
||||||
mOverlays = new OverlayWindow[BOUNDS_POSITION_LENGTH];
|
mOverlays = new OverlayWindow[BOUNDS_POSITION_LENGTH];
|
||||||
@@ -550,7 +547,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
|
|||||||
mCutoutViews[pos] = new DisplayCutoutView(mContext, pos);
|
mCutoutViews[pos] = new DisplayCutoutView(mContext, pos);
|
||||||
mCutoutViews[pos].setColor(mTintColor);
|
mCutoutViews[pos].setColor(mTintColor);
|
||||||
overlayView.addView(mCutoutViews[pos]);
|
overlayView.addView(mCutoutViews[pos]);
|
||||||
mCutoutViews[pos].updateRotation(mRotation);
|
updateView(pos, cutout);
|
||||||
}
|
}
|
||||||
|
|
||||||
mWindowManager.addView(overlayView, getWindowLayoutParams(pos));
|
mWindowManager.addView(overlayView, getWindowLayoutParams(pos));
|
||||||
@@ -606,7 +603,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
|
|||||||
private OverlayWindow overlayForPosition(
|
private OverlayWindow overlayForPosition(
|
||||||
@BoundsPosition int pos,
|
@BoundsPosition int pos,
|
||||||
@NonNull List<DecorProvider> decorProviders) {
|
@NonNull List<DecorProvider> decorProviders) {
|
||||||
final OverlayWindow currentOverlay = new OverlayWindow(mContext);
|
final OverlayWindow currentOverlay = new OverlayWindow(LayoutInflater.from(mContext), pos);
|
||||||
decorProviders.forEach(provider -> {
|
decorProviders.forEach(provider -> {
|
||||||
removeOverlayView(provider.getViewId());
|
removeOverlayView(provider.getViewId());
|
||||||
currentOverlay.addDecorProvider(provider, mRotation);
|
currentOverlay.addDecorProvider(provider, mRotation);
|
||||||
@@ -620,16 +617,22 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
|
|||||||
return currentOverlay;
|
return currentOverlay;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateView() {
|
private void updateView(@BoundsPosition int pos, @Nullable DisplayCutout cutout) {
|
||||||
if (mOverlays == null) {
|
if (mOverlays == null || mOverlays[pos] == null || mHwcScreenDecorationSupport != null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
++mProviderRefreshToken;
|
|
||||||
for (final OverlayWindow overlay: mOverlays) {
|
// update rounded corner view rotation
|
||||||
if (overlay == null) {
|
updateRoundedCornerView(pos, R.id.left, cutout);
|
||||||
continue;
|
updateRoundedCornerView(pos, R.id.right, cutout);
|
||||||
}
|
updateRoundedCornerSize(
|
||||||
overlay.onReloadResAndMeasure(null, mProviderRefreshToken, mRotation, mDisplayUniqueId);
|
mRoundedCornerResDelegate.getTopRoundedSize(),
|
||||||
|
mRoundedCornerResDelegate.getBottomRoundedSize());
|
||||||
|
updateRoundedCornerImageView();
|
||||||
|
|
||||||
|
// update cutout view rotation
|
||||||
|
if (mCutoutViews != null && mCutoutViews[pos] != null) {
|
||||||
|
mCutoutViews[pos].updateRotation(mRotation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -803,6 +806,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
|
|||||||
int oldRotation = mRotation;
|
int oldRotation = mRotation;
|
||||||
mPendingRotationChange = false;
|
mPendingRotationChange = false;
|
||||||
updateOrientation();
|
updateOrientation();
|
||||||
|
updateRoundedCornerRadii();
|
||||||
if (DEBUG) Log.i(TAG, "onConfigChanged from rot " + oldRotation + " to " + mRotation);
|
if (DEBUG) Log.i(TAG, "onConfigChanged from rot " + oldRotation + " to " + mRotation);
|
||||||
setupDecorations();
|
setupDecorations();
|
||||||
if (mOverlays != null) {
|
if (mOverlays != null) {
|
||||||
@@ -862,32 +866,109 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
|
|||||||
mDotViewController.setNewRotation(newRotation);
|
mDotViewController.setNewRotation(newRotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mPendingRotationChange && newRotation != mRotation) {
|
if (mPendingRotationChange) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (newRotation != mRotation) {
|
||||||
mRotation = newRotation;
|
mRotation = newRotation;
|
||||||
if (mScreenDecorHwcLayer != null) {
|
if (mScreenDecorHwcLayer != null) {
|
||||||
mScreenDecorHwcLayer.pendingRotationChange = false;
|
mScreenDecorHwcLayer.pendingRotationChange = false;
|
||||||
mScreenDecorHwcLayer.updateRotation(mRotation);
|
mScreenDecorHwcLayer.updateRotation(mRotation);
|
||||||
updateHwLayerRoundedCornerSize();
|
|
||||||
updateHwLayerRoundedCornerDrawable();
|
|
||||||
}
|
}
|
||||||
updateLayoutParams();
|
if (mOverlays != null) {
|
||||||
// update cutout view rotation
|
updateLayoutParams();
|
||||||
if (mCutoutViews != null) {
|
final DisplayCutout cutout = getCutout();
|
||||||
for (final DisplayCutoutView cutoutView: mCutoutViews) {
|
for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
|
||||||
if (cutoutView == null) {
|
if (mOverlays[i] == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
cutoutView.updateRotation(mRotation);
|
updateView(i, cutout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// update views
|
|
||||||
updateView();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 (shouldShowRoundedCorner(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() {
|
private boolean hasRoundedCorners() {
|
||||||
return mRoundedCornerFactory.getHasProviders();
|
return mRoundedCornerResDelegate.getBottomRoundedSize().getWidth() > 0
|
||||||
|
|| mRoundedCornerResDelegate.getTopRoundedSize().getWidth() > 0
|
||||||
|
|| mRoundedCornerResDelegate.isMultipleRadius();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isDefaultShownOverlayPos(@BoundsPosition int pos,
|
private boolean isDefaultShownOverlayPos(@BoundsPosition int pos,
|
||||||
@@ -906,19 +987,17 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean shouldShowSwLayerRoundedCorner(@BoundsPosition int pos,
|
private boolean shouldShowRoundedCorner(@BoundsPosition int pos,
|
||||||
@Nullable DisplayCutout cutout) {
|
@Nullable DisplayCutout cutout) {
|
||||||
return hasRoundedCorners() && isDefaultShownOverlayPos(pos, cutout)
|
return hasRoundedCorners() && isDefaultShownOverlayPos(pos, cutout)
|
||||||
&& mHwcScreenDecorationSupport == null;
|
&& mHwcScreenDecorationSupport == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean shouldShowSwLayerPrivacyDot(@BoundsPosition int pos,
|
private boolean shouldShowPrivacyDot(@BoundsPosition int pos, @Nullable DisplayCutout cutout) {
|
||||||
@Nullable DisplayCutout cutout) {
|
|
||||||
return isPrivacyDotEnabled() && isDefaultShownOverlayPos(pos, cutout);
|
return isPrivacyDotEnabled() && isDefaultShownOverlayPos(pos, cutout);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean shouldShowSwLayerCutout(@BoundsPosition int pos,
|
private boolean shouldShowCutout(@BoundsPosition int pos, @Nullable DisplayCutout cutout) {
|
||||||
@Nullable DisplayCutout cutout) {
|
|
||||||
final Rect[] bounds = cutout == null ? null : cutout.getBoundingRectsAll();
|
final Rect[] bounds = cutout == null ? null : cutout.getBoundingRectsAll();
|
||||||
final int rotatedPos = getBoundPositionFromRotation(pos, mRotation);
|
final int rotatedPos = getBoundPositionFromRotation(pos, mRotation);
|
||||||
return (bounds != null && !bounds[rotatedPos].isEmpty()
|
return (bounds != null && !bounds[rotatedPos].isEmpty()
|
||||||
@@ -953,33 +1032,54 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mExecutor.execute(() -> {
|
mExecutor.execute(() -> {
|
||||||
if (mOverlays == null || !SIZE.equals(key)) {
|
if (mOverlays == null) return;
|
||||||
return;
|
if (SIZE.equals(key)) {
|
||||||
}
|
if (newValue != null) {
|
||||||
++mProviderRefreshToken;
|
try {
|
||||||
try {
|
mRoundedCornerResDelegate.updateTuningSizeFactor(
|
||||||
final int sizeFactor = Integer.parseInt(newValue);
|
Integer.parseInt(newValue));
|
||||||
mRoundedCornerResDelegate.updateTuningSizeFactor(sizeFactor, mProviderRefreshToken);
|
} catch (Exception e) {
|
||||||
} 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,
|
updateRoundedCornerSize(
|
||||||
mDisplayUniqueId);
|
mRoundedCornerResDelegate.getTopRoundedSize(),
|
||||||
|
mRoundedCornerResDelegate.getBottomRoundedSize());
|
||||||
}
|
}
|
||||||
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() {
|
private void updateHwLayerRoundedCornerDrawable() {
|
||||||
if (mScreenDecorHwcLayer == null) {
|
if (mScreenDecorHwcLayer == null) {
|
||||||
return;
|
return;
|
||||||
@@ -994,6 +1094,25 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
|
|||||||
mScreenDecorHwcLayer.updateRoundedCornerDrawable(topDrawable, bottomDrawable);
|
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() {
|
private void updateHwLayerRoundedCornerSize() {
|
||||||
if (mScreenDecorHwcLayer == null) {
|
if (mScreenDecorHwcLayer == null) {
|
||||||
return;
|
return;
|
||||||
@@ -1005,6 +1124,28 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
|
|||||||
mScreenDecorHwcLayer.updateRoundedCornerSize(topWidth, bottomWidth);
|
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
|
@VisibleForTesting
|
||||||
protected void setSize(View view, Size pixelSize) {
|
protected void setSize(View view, Size pixelSize) {
|
||||||
LayoutParams params = view.getLayoutParams();
|
LayoutParams params = view.getLayoutParams();
|
||||||
|
|||||||
@@ -15,8 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.systemui.decor
|
package com.android.systemui.decor
|
||||||
import android.content.Context
|
|
||||||
import android.view.DisplayCutout
|
import android.view.DisplayCutout
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.Surface
|
import android.view.Surface
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@@ -38,20 +38,9 @@ abstract class DecorProvider {
|
|||||||
/** The aligned bounds for the view which is created through inflateView() */
|
/** The aligned bounds for the view which is created through inflateView() */
|
||||||
abstract val alignedBounds: List<Int>
|
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 */
|
/** Inflate view into parent as current rotation */
|
||||||
abstract fun inflateView(
|
abstract fun inflateView(
|
||||||
context: Context,
|
inflater: LayoutInflater,
|
||||||
parent: ViewGroup,
|
parent: ViewGroup,
|
||||||
@Surface.Rotation rotation: Int
|
@Surface.Rotation rotation: Int
|
||||||
): View
|
): View
|
||||||
|
|||||||
@@ -16,22 +16,31 @@
|
|||||||
package com.android.systemui.decor
|
package com.android.systemui.decor
|
||||||
|
|
||||||
import android.annotation.IdRes
|
import android.annotation.IdRes
|
||||||
import android.content.Context
|
import android.view.DisplayCutout
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.Surface
|
import android.view.Surface
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import com.android.systemui.RegionInterceptingFrameLayout
|
import com.android.systemui.R
|
||||||
|
import java.util.HashMap
|
||||||
|
|
||||||
class OverlayWindow(private val context: Context) {
|
class OverlayWindow(private val layoutInflater: LayoutInflater, private val pos: Int) {
|
||||||
|
|
||||||
val rootView = RegionInterceptingFrameLayout(context) as ViewGroup
|
private val layoutId: Int
|
||||||
private val viewProviderMap = mutableMapOf<Int, Pair<View, DecorProvider>>()
|
get() {
|
||||||
|
return if (pos == DisplayCutout.BOUNDS_POSITION_LEFT ||
|
||||||
|
pos == DisplayCutout.BOUNDS_POSITION_TOP) {
|
||||||
|
R.layout.rounded_corners_top
|
||||||
|
} else {
|
||||||
|
R.layout.rounded_corners_bottom
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun addDecorProvider(
|
val rootView = layoutInflater.inflate(layoutId, null) as ViewGroup
|
||||||
decorProvider: DecorProvider,
|
private val viewProviderMap: MutableMap<Int, Pair<View, DecorProvider>> = HashMap()
|
||||||
@Surface.Rotation rotation: Int
|
|
||||||
) {
|
fun addDecorProvider(decorProvider: DecorProvider, @Surface.Rotation rotation: Int) {
|
||||||
val view = decorProvider.inflateView(context, rootView, rotation)
|
val view = decorProvider.inflateView(layoutInflater, rootView, rotation)
|
||||||
viewProviderMap[decorProvider.viewId] = Pair(view, decorProvider)
|
viewProviderMap[decorProvider.viewId] = Pair(view, decorProvider)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,35 +56,4 @@ class OverlayWindow(private val context: Context) {
|
|||||||
viewProviderMap.remove(id)
|
viewProviderMap.remove(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package com.android.systemui.decor
|
package com.android.systemui.decor
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.view.DisplayCutout
|
import android.view.DisplayCutout
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
@@ -77,21 +76,12 @@ class PrivacyDotCornerDecorProviderImpl(
|
|||||||
private val layoutId: Int
|
private val layoutId: Int
|
||||||
) : CornerDecorProvider() {
|
) : CornerDecorProvider() {
|
||||||
|
|
||||||
override fun onReloadResAndMeasure(
|
|
||||||
view: View,
|
|
||||||
reloadToken: Int,
|
|
||||||
rotation: Int,
|
|
||||||
displayUniqueId: String?
|
|
||||||
) {
|
|
||||||
// Do nothing here because it is handled inside PrivacyDotViewController
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun inflateView(
|
override fun inflateView(
|
||||||
context: Context,
|
inflater: LayoutInflater,
|
||||||
parent: ViewGroup,
|
parent: ViewGroup,
|
||||||
@Surface.Rotation rotation: Int
|
@Surface.Rotation rotation: Int
|
||||||
): View {
|
): View {
|
||||||
LayoutInflater.from(context).inflate(layoutId, parent, true)
|
inflater.inflate(layoutId, parent, true)
|
||||||
return parent.getChildAt(parent.childCount - 1 /* latest new added child */)
|
return parent.getChildAt(parent.childCount - 1 /* latest new added child */)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,86 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,192 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
||||||
}
|
|
||||||
@@ -36,8 +36,6 @@ class RoundedCornerResDelegate(
|
|||||||
private val density: Float
|
private val density: Float
|
||||||
get() = res.displayMetrics.density
|
get() = res.displayMetrics.density
|
||||||
|
|
||||||
private var reloadToken: Int = 0
|
|
||||||
|
|
||||||
var isMultipleRadius: Boolean = false
|
var isMultipleRadius: Boolean = false
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@@ -62,26 +60,12 @@ class RoundedCornerResDelegate(
|
|||||||
reloadMeasures()
|
reloadMeasures()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun reloadAll(newReloadToken: Int) {
|
fun reloadAll(newDisplayUniqueId: String?) {
|
||||||
if (reloadToken == newReloadToken) {
|
displayUniqueId = newDisplayUniqueId
|
||||||
return
|
|
||||||
}
|
|
||||||
reloadToken = newReloadToken
|
|
||||||
reloadDrawables()
|
reloadDrawables()
|
||||||
reloadMeasures()
|
reloadMeasures()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateDisplayUniqueId(newDisplayUniqueId: String?, newReloadToken: Int?) {
|
|
||||||
if (displayUniqueId != newDisplayUniqueId) {
|
|
||||||
displayUniqueId = newDisplayUniqueId
|
|
||||||
newReloadToken ?.let { reloadToken = it }
|
|
||||||
reloadDrawables()
|
|
||||||
reloadMeasures()
|
|
||||||
} else {
|
|
||||||
newReloadToken?.let { reloadAll(it) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun reloadDrawables() {
|
private fun reloadDrawables() {
|
||||||
val configIdx = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId)
|
val configIdx = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId)
|
||||||
isMultipleRadius = getIsMultipleRadius(configIdx)
|
isMultipleRadius = getIsMultipleRadius(configIdx)
|
||||||
@@ -101,6 +85,34 @@ class RoundedCornerResDelegate(
|
|||||||
arrayResId = R.array.config_roundedCornerBottomDrawableArray,
|
arrayResId = R.array.config_roundedCornerBottomDrawableArray,
|
||||||
backupDrawableId = R.drawable.rounded_corner_bottom
|
backupDrawableId = R.drawable.rounded_corner_bottom
|
||||||
) ?: roundedDrawable
|
) ?: roundedDrawable
|
||||||
|
|
||||||
|
// If config_roundedCornerMultipleRadius set as true, ScreenDecorations respect the
|
||||||
|
// (width, height) size of drawable/rounded.xml instead of rounded_corner_radius
|
||||||
|
if (isMultipleRadius) {
|
||||||
|
roundedSize = Size(
|
||||||
|
roundedDrawable?.intrinsicWidth ?: 0,
|
||||||
|
roundedDrawable?.intrinsicHeight ?: 0)
|
||||||
|
topRoundedDrawable?.let {
|
||||||
|
topRoundedSize = Size(it.intrinsicWidth, it.intrinsicHeight)
|
||||||
|
}
|
||||||
|
bottomRoundedDrawable?.let {
|
||||||
|
bottomRoundedSize = Size(it.intrinsicWidth, it.intrinsicHeight)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val defaultRadius = RoundedCorners.getRoundedCornerRadius(res, displayUniqueId)
|
||||||
|
val topRadius = RoundedCorners.getRoundedCornerTopRadius(res, displayUniqueId)
|
||||||
|
val bottomRadius = RoundedCorners.getRoundedCornerBottomRadius(res, displayUniqueId)
|
||||||
|
roundedSize = Size(defaultRadius, defaultRadius)
|
||||||
|
topRoundedSize = Size(topRadius, topRadius)
|
||||||
|
bottomRoundedSize = Size(bottomRadius, bottomRadius)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (topRoundedSize.width == 0) {
|
||||||
|
topRoundedSize = roundedSize
|
||||||
|
}
|
||||||
|
if (bottomRoundedSize.width == 0) {
|
||||||
|
bottomRoundedSize = roundedSize
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun reloadMeasures(roundedSizeFactor: Int? = null) {
|
private fun reloadMeasures(roundedSizeFactor: Int? = null) {
|
||||||
@@ -125,8 +137,8 @@ class RoundedCornerResDelegate(
|
|||||||
bottomRoundedSize = Size(bottomRadius, bottomRadius)
|
bottomRoundedSize = Size(bottomRadius, bottomRadius)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (roundedSizeFactor != null && roundedSizeFactor > 0) {
|
roundedSizeFactor ?.let {
|
||||||
val length: Int = (roundedSizeFactor * density).toInt()
|
val length: Int = (it * density).toInt()
|
||||||
roundedSize = Size(length, length)
|
roundedSize = Size(length, length)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,11 +150,7 @@ class RoundedCornerResDelegate(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateTuningSizeFactor(factor: Int?, newReloadToken: Int) {
|
fun updateTuningSizeFactor(factor: Int) {
|
||||||
if (reloadToken == newReloadToken) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
reloadToken = newReloadToken
|
|
||||||
reloadMeasures(factor)
|
reloadMeasures(factor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import static org.junit.Assert.assertThat;
|
|||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.ArgumentMatchers.isA;
|
import static org.mockito.ArgumentMatchers.isA;
|
||||||
|
import static org.mockito.Mockito.atLeastOnce;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
@@ -60,11 +61,9 @@ import android.util.Size;
|
|||||||
import android.view.Display;
|
import android.view.Display;
|
||||||
import android.view.DisplayCutout;
|
import android.view.DisplayCutout;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.view.WindowMetrics;
|
import android.view.WindowMetrics;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
@@ -103,7 +102,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
|
|||||||
private SecureSettings mSecureSettings;
|
private SecureSettings mSecureSettings;
|
||||||
private final FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
|
private final FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
|
||||||
private FakeThreadFactory mThreadFactory;
|
private FakeThreadFactory mThreadFactory;
|
||||||
private ArrayList<DecorProvider> mPrivacyDecorProviders;
|
private ArrayList<DecorProvider> mDecorProviders;
|
||||||
@Mock
|
@Mock
|
||||||
private Display mDisplay;
|
private Display mDisplay;
|
||||||
@Mock
|
@Mock
|
||||||
@@ -198,43 +197,17 @@ public class ScreenDecorationsTest extends SysuiTestCase {
|
|||||||
reset(mTunerService);
|
reset(mTunerService);
|
||||||
}
|
}
|
||||||
|
|
||||||
@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(
|
private void verifyRoundedCornerViewsVisibility(
|
||||||
@DisplayCutout.BoundsPosition final int overlayId,
|
@DisplayCutout.BoundsPosition final int overlayId,
|
||||||
@View.Visibility final boolean isExist) {
|
@View.Visibility final int visibility) {
|
||||||
final View overlay = mScreenDecorations.mOverlays[overlayId].getRootView();
|
final View overlay = mScreenDecorations.mOverlays[overlayId].getRootView();
|
||||||
for (int id: getRoundCornerIdsFromOverlayId(overlayId)) {
|
final View left = overlay.findViewById(R.id.left);
|
||||||
final View view = overlay.findViewById(id);
|
final View right = overlay.findViewById(R.id.right);
|
||||||
if (isExist) {
|
assertNotNull(left);
|
||||||
assertNotNull(view);
|
assertNotNull(right);
|
||||||
assertThat(view.getVisibility()).isEqualTo(View.VISIBLE);
|
assertThat(left.getVisibility()).isEqualTo(visibility);
|
||||||
} else {
|
assertThat(right.getVisibility()).isEqualTo(visibility);
|
||||||
assertNull(view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -378,8 +351,8 @@ public class ScreenDecorationsTest extends SysuiTestCase {
|
|||||||
verifyOverlaysExistAndAdded(false, true, false, true);
|
verifyOverlaysExistAndAdded(false, true, false, true);
|
||||||
|
|
||||||
// Rounded corner views shall not exist
|
// Rounded corner views shall not exist
|
||||||
verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, false);
|
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.GONE);
|
||||||
verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, false);
|
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.GONE);
|
||||||
|
|
||||||
// Privacy dots shall exist but invisible
|
// Privacy dots shall exist but invisible
|
||||||
verifyDotViewsVisibility(View.INVISIBLE);
|
verifyDotViewsVisibility(View.INVISIBLE);
|
||||||
@@ -407,8 +380,8 @@ public class ScreenDecorationsTest extends SysuiTestCase {
|
|||||||
verifyOverlaysExistAndAdded(false, true, false, true);
|
verifyOverlaysExistAndAdded(false, true, false, true);
|
||||||
|
|
||||||
// Rounded corner views shall exist
|
// Rounded corner views shall exist
|
||||||
verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, true);
|
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE);
|
||||||
verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, true);
|
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.VISIBLE);
|
||||||
|
|
||||||
// Privacy dots shall not exist
|
// Privacy dots shall not exist
|
||||||
verifyDotViewsNullable(true);
|
verifyDotViewsNullable(true);
|
||||||
@@ -435,8 +408,8 @@ public class ScreenDecorationsTest extends SysuiTestCase {
|
|||||||
verifyOverlaysExistAndAdded(false, true, false, true);
|
verifyOverlaysExistAndAdded(false, true, false, true);
|
||||||
|
|
||||||
// Rounded corner views shall exist
|
// Rounded corner views shall exist
|
||||||
verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, true);
|
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE);
|
||||||
verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, true);
|
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.VISIBLE);
|
||||||
|
|
||||||
// Privacy dots shall exist but invisible
|
// Privacy dots shall exist but invisible
|
||||||
verifyDotViewsVisibility(View.INVISIBLE);
|
verifyDotViewsVisibility(View.INVISIBLE);
|
||||||
@@ -476,26 +449,21 @@ public class ScreenDecorationsTest extends SysuiTestCase {
|
|||||||
|
|
||||||
mScreenDecorations.start();
|
mScreenDecorations.start();
|
||||||
View leftRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP].getRootView()
|
View leftRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP].getRootView()
|
||||||
.findViewById(R.id.rounded_corner_top_left);
|
.findViewById(R.id.left);
|
||||||
View rightRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP].getRootView()
|
View rightRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP].getRootView()
|
||||||
.findViewById(R.id.rounded_corner_top_right);
|
.findViewById(R.id.right);
|
||||||
ViewGroup.LayoutParams leftParams = leftRoundedCorner.getLayoutParams();
|
verify(mScreenDecorations, atLeastOnce())
|
||||||
ViewGroup.LayoutParams rightParams = rightRoundedCorner.getLayoutParams();
|
.setSize(leftRoundedCorner, new Size(testTopRadius, testTopRadius));
|
||||||
assertEquals(leftParams.width, testTopRadius);
|
verify(mScreenDecorations, atLeastOnce())
|
||||||
assertEquals(leftParams.height, testTopRadius);
|
.setSize(rightRoundedCorner, new Size(testTopRadius, testTopRadius));
|
||||||
assertEquals(rightParams.width, testTopRadius);
|
|
||||||
assertEquals(rightParams.height, testTopRadius);
|
|
||||||
|
|
||||||
leftRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM].getRootView()
|
leftRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM].getRootView()
|
||||||
.findViewById(R.id.rounded_corner_bottom_left);
|
.findViewById(R.id.left);
|
||||||
rightRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM].getRootView()
|
rightRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM].getRootView()
|
||||||
.findViewById(R.id.rounded_corner_bottom_right);
|
.findViewById(R.id.right);
|
||||||
leftParams = leftRoundedCorner.getLayoutParams();
|
verify(mScreenDecorations, atLeastOnce())
|
||||||
rightParams = rightRoundedCorner.getLayoutParams();
|
.setSize(leftRoundedCorner, new Size(testBottomRadius, testBottomRadius));
|
||||||
assertEquals(leftParams.width, testBottomRadius);
|
verify(mScreenDecorations, atLeastOnce())
|
||||||
assertEquals(leftParams.height, testBottomRadius);
|
.setSize(rightRoundedCorner, new Size(testBottomRadius, testBottomRadius));
|
||||||
assertEquals(rightParams.width, testBottomRadius);
|
|
||||||
assertEquals(rightParams.height, testBottomRadius);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -511,27 +479,31 @@ public class ScreenDecorationsTest extends SysuiTestCase {
|
|||||||
.when(mScreenDecorations).getCutout();
|
.when(mScreenDecorations).getCutout();
|
||||||
|
|
||||||
mScreenDecorations.start();
|
mScreenDecorations.start();
|
||||||
View topRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT].getRootView()
|
final Size topRadius = new Size(testTopRadius, testTopRadius);
|
||||||
.findViewById(R.id.rounded_corner_top_left);
|
final Size bottomRadius = new Size(testBottomRadius, testBottomRadius);
|
||||||
View bottomRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT].getRootView()
|
View leftRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT].getRootView()
|
||||||
.findViewById(R.id.rounded_corner_bottom_left);
|
.findViewById(R.id.left);
|
||||||
ViewGroup.LayoutParams topParams = topRoundedCorner.getLayoutParams();
|
boolean isTop = mScreenDecorations.isTopRoundedCorner(BOUNDS_POSITION_LEFT, R.id.left);
|
||||||
ViewGroup.LayoutParams bottomParams = bottomRoundedCorner.getLayoutParams();
|
verify(mScreenDecorations, atLeastOnce())
|
||||||
assertEquals(topParams.width, testTopRadius);
|
.setSize(leftRoundedCorner, isTop ? topRadius : bottomRadius);
|
||||||
assertEquals(topParams.height, testTopRadius);
|
|
||||||
assertEquals(bottomParams.width, testBottomRadius);
|
|
||||||
assertEquals(bottomParams.height, testBottomRadius);
|
|
||||||
|
|
||||||
topRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT].getRootView()
|
View rightRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT].getRootView()
|
||||||
.findViewById(R.id.rounded_corner_top_right);
|
.findViewById(R.id.right);
|
||||||
bottomRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT].getRootView()
|
isTop = mScreenDecorations.isTopRoundedCorner(BOUNDS_POSITION_LEFT, R.id.right);
|
||||||
.findViewById(R.id.rounded_corner_bottom_right);
|
verify(mScreenDecorations, atLeastOnce())
|
||||||
topParams = topRoundedCorner.getLayoutParams();
|
.setSize(rightRoundedCorner, isTop ? topRadius : bottomRadius);
|
||||||
bottomParams = bottomRoundedCorner.getLayoutParams();
|
|
||||||
assertEquals(topParams.width, testTopRadius);
|
leftRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT].getRootView()
|
||||||
assertEquals(topParams.height, testTopRadius);
|
.findViewById(R.id.left);
|
||||||
assertEquals(bottomParams.width, testBottomRadius);
|
isTop = mScreenDecorations.isTopRoundedCorner(BOUNDS_POSITION_RIGHT, R.id.left);
|
||||||
assertEquals(bottomParams.height, testBottomRadius);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -551,8 +523,8 @@ public class ScreenDecorationsTest extends SysuiTestCase {
|
|||||||
verifyOverlaysExistAndAdded(false, true, false, true);
|
verifyOverlaysExistAndAdded(false, true, false, true);
|
||||||
|
|
||||||
// Rounded corner views shall exist
|
// Rounded corner views shall exist
|
||||||
verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, true);
|
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE);
|
||||||
verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, true);
|
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.VISIBLE);
|
||||||
|
|
||||||
// Privacy dots shall not exist
|
// Privacy dots shall not exist
|
||||||
verifyDotViewsNullable(true);
|
verifyDotViewsNullable(true);
|
||||||
@@ -585,8 +557,8 @@ public class ScreenDecorationsTest extends SysuiTestCase {
|
|||||||
verifyOverlaysExistAndAdded(false, true, false, true);
|
verifyOverlaysExistAndAdded(false, true, false, true);
|
||||||
|
|
||||||
// Rounded corner views shall exist
|
// Rounded corner views shall exist
|
||||||
verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, true);
|
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE);
|
||||||
verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, true);
|
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.VISIBLE);
|
||||||
|
|
||||||
// Privacy dots shall exist but invisible
|
// Privacy dots shall exist but invisible
|
||||||
verifyDotViewsVisibility(View.INVISIBLE);
|
verifyDotViewsVisibility(View.INVISIBLE);
|
||||||
@@ -645,10 +617,10 @@ public class ScreenDecorationsTest extends SysuiTestCase {
|
|||||||
|
|
||||||
// Top rounded corner views shall exist because of cutout
|
// Top rounded corner views shall exist because of cutout
|
||||||
// but be gone because of no rounded corner
|
// but be gone because of no rounded corner
|
||||||
verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, false);
|
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.GONE);
|
||||||
// Bottom rounded corner views shall exist because of privacy dot
|
// Bottom rounded corner views shall exist because of privacy dot
|
||||||
// but be gone because of no rounded corner
|
// but be gone because of no rounded corner
|
||||||
verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, false);
|
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.GONE);
|
||||||
|
|
||||||
// Privacy dots shall exist but invisible
|
// Privacy dots shall exist but invisible
|
||||||
verifyDotViewsVisibility(View.INVISIBLE);
|
verifyDotViewsVisibility(View.INVISIBLE);
|
||||||
@@ -676,7 +648,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
|
|||||||
|
|
||||||
// Left rounded corner views shall exist because of cutout
|
// Left rounded corner views shall exist because of cutout
|
||||||
// but be gone because of no rounded corner
|
// but be gone because of no rounded corner
|
||||||
verifyRoundedCornerViewsExist(BOUNDS_POSITION_LEFT, false);
|
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_LEFT, View.GONE);
|
||||||
|
|
||||||
// Top privacy dots shall not exist because of no privacy
|
// Top privacy dots shall not exist because of no privacy
|
||||||
verifyDotViewsNullable(true);
|
verifyDotViewsNullable(true);
|
||||||
@@ -728,8 +700,8 @@ public class ScreenDecorationsTest extends SysuiTestCase {
|
|||||||
verifyOverlaysExistAndAdded(false, true, false, true);
|
verifyOverlaysExistAndAdded(false, true, false, true);
|
||||||
|
|
||||||
// Rounded corner views shall exist
|
// Rounded corner views shall exist
|
||||||
verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, true);
|
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE);
|
||||||
verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, true);
|
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.VISIBLE);
|
||||||
|
|
||||||
// Top privacy dots shall not exist because of no privacy dot
|
// Top privacy dots shall not exist because of no privacy dot
|
||||||
verifyDotViewsNullable(true);
|
verifyDotViewsNullable(true);
|
||||||
@@ -756,8 +728,8 @@ public class ScreenDecorationsTest extends SysuiTestCase {
|
|||||||
verifyOverlaysExistAndAdded(false, true, false, true);
|
verifyOverlaysExistAndAdded(false, true, false, true);
|
||||||
|
|
||||||
// Rounded corner views shall exist
|
// Rounded corner views shall exist
|
||||||
verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, true);
|
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE);
|
||||||
verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, true);
|
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.VISIBLE);
|
||||||
|
|
||||||
// Top privacy dots shall exist but invisible
|
// Top privacy dots shall exist but invisible
|
||||||
verifyDotViewsVisibility(View.INVISIBLE);
|
verifyDotViewsVisibility(View.INVISIBLE);
|
||||||
@@ -887,7 +859,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
|
|||||||
verifyOverlaysExistAndAdded(true, false, true, false);
|
verifyOverlaysExistAndAdded(true, false, true, false);
|
||||||
|
|
||||||
// Verify each privacy dot id appears only once
|
// Verify each privacy dot id appears only once
|
||||||
mPrivacyDecorProviders.stream().map(DecorProvider::getViewId).forEach(viewId -> {
|
mDecorProviders.stream().map(DecorProvider::getViewId).forEach(viewId -> {
|
||||||
int findCount = 0;
|
int findCount = 0;
|
||||||
for (OverlayWindow overlay: mScreenDecorations.mOverlays) {
|
for (OverlayWindow overlay: mScreenDecorations.mOverlays) {
|
||||||
if (overlay == null) {
|
if (overlay == null) {
|
||||||
@@ -941,8 +913,8 @@ public class ScreenDecorationsTest extends SysuiTestCase {
|
|||||||
// Both top and bottom windows should be added because of privacy dot,
|
// Both top and bottom windows should be added because of privacy dot,
|
||||||
// but their visibility shall be gone because of no rounding.
|
// but their visibility shall be gone because of no rounding.
|
||||||
verifyOverlaysExistAndAdded(false, true, false, true);
|
verifyOverlaysExistAndAdded(false, true, false, true);
|
||||||
verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, false);
|
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.GONE);
|
||||||
verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, false);
|
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.GONE);
|
||||||
|
|
||||||
when(mContext.getResources().getBoolean(
|
when(mContext.getResources().getBoolean(
|
||||||
com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout))
|
com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout))
|
||||||
@@ -953,8 +925,8 @@ public class ScreenDecorationsTest extends SysuiTestCase {
|
|||||||
// Both top and bottom windows should be added because of privacy dot,
|
// Both top and bottom windows should be added because of privacy dot,
|
||||||
// but their visibility shall be gone because of no rounding.
|
// but their visibility shall be gone because of no rounding.
|
||||||
verifyOverlaysExistAndAdded(false, true, false, true);
|
verifyOverlaysExistAndAdded(false, true, false, true);
|
||||||
verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, false);
|
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.GONE);
|
||||||
verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, false);
|
verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -1202,14 +1174,14 @@ public class ScreenDecorationsTest extends SysuiTestCase {
|
|||||||
mContext.getOrCreateTestableResources().addOverride(
|
mContext.getOrCreateTestableResources().addOverride(
|
||||||
com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, fillCutout);
|
com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, fillCutout);
|
||||||
|
|
||||||
mPrivacyDecorProviders = new ArrayList<>();
|
mDecorProviders = new ArrayList<>();
|
||||||
if (privacyDot) {
|
if (privacyDot) {
|
||||||
mPrivacyDecorProviders.add(mPrivacyDotTopLeftDecorProvider);
|
mDecorProviders.add(mPrivacyDotTopLeftDecorProvider);
|
||||||
mPrivacyDecorProviders.add(mPrivacyDotTopRightDecorProvider);
|
mDecorProviders.add(mPrivacyDotTopRightDecorProvider);
|
||||||
mPrivacyDecorProviders.add(mPrivacyDotBottomLeftDecorProvider);
|
mDecorProviders.add(mPrivacyDotBottomLeftDecorProvider);
|
||||||
mPrivacyDecorProviders.add(mPrivacyDotBottomRightDecorProvider);
|
mDecorProviders.add(mPrivacyDotBottomRightDecorProvider);
|
||||||
}
|
}
|
||||||
when(mPrivacyDotDecorProviderFactory.getProviders()).thenReturn(mPrivacyDecorProviders);
|
when(mPrivacyDotDecorProviderFactory.getProviders()).thenReturn(mDecorProviders);
|
||||||
when(mPrivacyDotDecorProviderFactory.getHasProviders()).thenReturn(privacyDot);
|
when(mPrivacyDotDecorProviderFactory.getHasProviders()).thenReturn(privacyDot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,19 +19,25 @@ package com.android.systemui.decor
|
|||||||
import android.testing.AndroidTestingRunner
|
import android.testing.AndroidTestingRunner
|
||||||
import android.testing.TestableLooper.RunWithLooper
|
import android.testing.TestableLooper.RunWithLooper
|
||||||
import android.view.DisplayCutout
|
import android.view.DisplayCutout
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.Surface
|
import android.view.Surface
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
||||||
import com.android.systemui.R
|
import com.android.systemui.R
|
||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.util.mockito.eq
|
||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.mockito.Mockito.never
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito
|
||||||
|
import org.mockito.Mockito.anyInt
|
||||||
import org.mockito.Mockito.spy
|
import org.mockito.Mockito.spy
|
||||||
import org.mockito.Mockito.times
|
|
||||||
import org.mockito.Mockito.verify
|
import org.mockito.Mockito.verify
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
import org.mockito.Mockito.`when` as whenever
|
||||||
|
|
||||||
@RunWith(AndroidTestingRunner::class)
|
@RunWith(AndroidTestingRunner::class)
|
||||||
@RunWithLooper(setAsMainLooper = true)
|
@RunWithLooper(setAsMainLooper = true)
|
||||||
@@ -39,88 +45,62 @@ import org.mockito.Mockito.verify
|
|||||||
class OverlayWindowTest : SysuiTestCase() {
|
class OverlayWindowTest : SysuiTestCase() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val TEST_DECOR_VIEW_ID_1 = R.id.privacy_dot_top_left_container
|
private val TEST_DECOR_VIEW_ID = R.id.privacy_dot_bottom_right_container
|
||||||
private val TEST_DECOR_VIEW_ID_2 = R.id.privacy_dot_bottom_right_container
|
private val TEST_DECOR_LAYOUT_ID = R.layout.privacy_dot_bottom_right
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var overlay: OverlayWindow
|
private lateinit var overlay: OverlayWindow
|
||||||
private lateinit var decorProvider1: DecorProvider
|
|
||||||
private lateinit var decorProvider2: DecorProvider
|
@Mock private lateinit var layoutInflater: LayoutInflater
|
||||||
|
@Mock private lateinit var decorProvider: DecorProvider
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
decorProvider1 = spy(PrivacyDotCornerDecorProviderImpl(
|
MockitoAnnotations.initMocks(this)
|
||||||
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_RIGHT,
|
|
||||||
layoutId = R.layout.privacy_dot_bottom_right))
|
|
||||||
|
|
||||||
overlay = OverlayWindow(mContext)
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testAddProvider() {
|
fun testAddProvider() {
|
||||||
@Surface.Rotation val rotation = Surface.ROTATION_270
|
@Surface.Rotation val rotation = Surface.ROTATION_270
|
||||||
overlay.addDecorProvider(decorProvider1, rotation)
|
overlay.addDecorProvider(decorProvider, rotation)
|
||||||
overlay.addDecorProvider(decorProvider2, rotation)
|
verify(decorProvider, Mockito.times(1)).inflateView(
|
||||||
|
eq(layoutInflater), eq(overlay.rootView), eq(rotation))
|
||||||
verify(decorProvider1, times(1)).inflateView(
|
val viewFoundFromRootView = overlay.rootView.findViewById<View>(TEST_DECOR_VIEW_ID)
|
||||||
mContext, overlay.rootView, rotation)
|
Assert.assertNotNull(viewFoundFromRootView)
|
||||||
verify(decorProvider2, times(1)).inflateView(
|
Assert.assertEquals(viewFoundFromRootView, overlay.getView(TEST_DECOR_VIEW_ID))
|
||||||
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
|
@Test
|
||||||
fun testRemoveView() {
|
fun testRemoveView() {
|
||||||
overlay.addDecorProvider(decorProvider1, Surface.ROTATION_270)
|
@Surface.Rotation val rotation = Surface.ROTATION_270
|
||||||
overlay.addDecorProvider(decorProvider2, Surface.ROTATION_270)
|
overlay.addDecorProvider(decorProvider, rotation)
|
||||||
overlay.removeView(TEST_DECOR_VIEW_ID_1)
|
overlay.removeView(TEST_DECOR_VIEW_ID)
|
||||||
|
val viewFoundFromRootView = overlay.rootView.findViewById<View>(TEST_DECOR_VIEW_ID)
|
||||||
val viewFoundFromRootView = overlay.rootView.findViewById<View>(TEST_DECOR_VIEW_ID_1)
|
|
||||||
Assert.assertNull(viewFoundFromRootView)
|
Assert.assertNull(viewFoundFromRootView)
|
||||||
Assert.assertNull(overlay.getView(TEST_DECOR_VIEW_ID_1))
|
Assert.assertNull(overlay.getView(TEST_DECOR_LAYOUT_ID))
|
||||||
}
|
|
||||||
|
|
||||||
@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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -18,6 +18,7 @@ package com.android.systemui.decor
|
|||||||
|
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.testing.AndroidTestingRunner
|
import android.testing.AndroidTestingRunner
|
||||||
|
import android.testing.TestableLooper.RunWithLooper
|
||||||
import android.view.DisplayCutout
|
import android.view.DisplayCutout
|
||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
||||||
import com.android.systemui.R
|
import com.android.systemui.R
|
||||||
@@ -31,6 +32,7 @@ import org.mockito.Mockito.spy
|
|||||||
import org.mockito.Mockito.`when` as whenever
|
import org.mockito.Mockito.`when` as whenever
|
||||||
|
|
||||||
@RunWith(AndroidTestingRunner::class)
|
@RunWith(AndroidTestingRunner::class)
|
||||||
|
@RunWithLooper(setAsMainLooper = true)
|
||||||
@SmallTest
|
@SmallTest
|
||||||
class PrivacyDotDecorProviderFactoryTest : SysuiTestCase() {
|
class PrivacyDotDecorProviderFactoryTest : SysuiTestCase() {
|
||||||
private lateinit var mPrivacyDotDecorProviderFactory: PrivacyDotDecorProviderFactory
|
private lateinit var mPrivacyDotDecorProviderFactory: PrivacyDotDecorProviderFactory
|
||||||
|
|||||||
@@ -1,142 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -45,7 +45,7 @@ class RoundedCornerResDelegateTest : SysuiTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testUpdateDisplayUniqueId() {
|
fun testReloadAllAndDefaultRadius() {
|
||||||
mContext.orCreateTestableResources.addOverrides(
|
mContext.orCreateTestableResources.addOverrides(
|
||||||
mockTypeArray = mockTypedArray,
|
mockTypeArray = mockTypedArray,
|
||||||
radius = 3,
|
radius = 3,
|
||||||
@@ -65,34 +65,7 @@ class RoundedCornerResDelegateTest : SysuiTestCase() {
|
|||||||
radiusTop = 6,
|
radiusTop = 6,
|
||||||
radiusBottom = 0)
|
radiusBottom = 0)
|
||||||
|
|
||||||
roundedCornerResDelegate.updateDisplayUniqueId("test", null)
|
roundedCornerResDelegate.reloadAll("test")
|
||||||
|
|
||||||
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(6, 6), roundedCornerResDelegate.topRoundedSize)
|
||||||
assertEquals(Size(5, 5), roundedCornerResDelegate.bottomRoundedSize)
|
assertEquals(Size(5, 5), roundedCornerResDelegate.bottomRoundedSize)
|
||||||
@@ -109,21 +82,11 @@ class RoundedCornerResDelegateTest : SysuiTestCase() {
|
|||||||
roundedCornerResDelegate = RoundedCornerResDelegate(mContext.resources, null)
|
roundedCornerResDelegate = RoundedCornerResDelegate(mContext.resources, null)
|
||||||
|
|
||||||
val factor = 5
|
val factor = 5
|
||||||
roundedCornerResDelegate.updateTuningSizeFactor(factor, 1)
|
roundedCornerResDelegate.updateTuningSizeFactor(factor)
|
||||||
val length = (factor * mContext.resources.displayMetrics.density).toInt()
|
val length = (factor * mContext.resources.displayMetrics.density).toInt()
|
||||||
|
|
||||||
assertEquals(Size(length, length), roundedCornerResDelegate.topRoundedSize)
|
assertEquals(Size(length, length), roundedCornerResDelegate.topRoundedSize)
|
||||||
assertEquals(Size(length, length), roundedCornerResDelegate.bottomRoundedSize)
|
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
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user