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