Fix incorrect pos / id for privacy dot
When only left / right overlays are enabled because of long edge cutout,
we shall assign layout id to correct local variable, and do some
adjustment of layout gravity, and padding.
Bug: 201481944
Bug: 203361384
Test: atest com.android.systemui.ScreenDecorationsTest
Test: manually rotate, enable RTL, disable round corner, long side
cutout, and display size change, to make sure privacy dot is shown
on correct pos
Change-Id: Ife8f81e33f44e11cf2be40f74669ee9a9b31f707
This commit is contained in:
@@ -31,8 +31,7 @@
|
||||
android:id="@+id/privacy_dot_left_container"
|
||||
android:layout_height="@dimen/status_bar_height"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginTop="@dimen/status_bar_padding_top"
|
||||
android:layout_marginLeft="0dp"
|
||||
android:paddingTop="@dimen/status_bar_padding_top"
|
||||
android:layout_gravity="left|bottom"
|
||||
android:visibility="invisible" >
|
||||
<ImageView
|
||||
@@ -51,12 +50,12 @@
|
||||
android:tint="#ff000000"
|
||||
android:layout_gravity="right|bottom"
|
||||
android:src="@drawable/rounded_corner_bottom"/>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/privacy_dot_right_container"
|
||||
android:layout_height="@dimen/status_bar_height"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginTop="@dimen/status_bar_padding_top"
|
||||
android:layout_marginRight="0dp"
|
||||
android:paddingTop="@dimen/status_bar_padding_top"
|
||||
android:layout_gravity="right|bottom"
|
||||
android:visibility="invisible" >
|
||||
<ImageView
|
||||
|
||||
@@ -29,10 +29,9 @@
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/privacy_dot_left_container"
|
||||
android:layout_height="@*android:dimen/status_bar_height_portrait"
|
||||
android:layout_height="@dimen/status_bar_height"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginTop="@dimen/status_bar_padding_top"
|
||||
android:layout_marginLeft="0dp"
|
||||
android:paddingTop="@dimen/status_bar_padding_top"
|
||||
android:layout_gravity="left|top"
|
||||
android:visibility="invisible" >
|
||||
<ImageView
|
||||
@@ -54,10 +53,9 @@
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/privacy_dot_right_container"
|
||||
android:layout_height="@*android:dimen/status_bar_height_portrait"
|
||||
android:layout_height="@dimen/status_bar_height"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginTop="@dimen/status_bar_padding_top"
|
||||
android:layout_marginRight="0dp"
|
||||
android:paddingTop="@dimen/status_bar_padding_top"
|
||||
android:layout_gravity="right|top"
|
||||
android:visibility="invisible" >
|
||||
<ImageView
|
||||
@@ -67,8 +65,6 @@
|
||||
android:layout_gravity="center_vertical|left"
|
||||
android:src="@drawable/system_animation_ongoing_dot"
|
||||
android:visibility="visible" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
</com.android.systemui.RegionInterceptingFrameLayout>
|
||||
|
||||
@@ -161,8 +161,6 @@ public class ScreenDecorations extends SystemUI implements Tunable {
|
||||
private boolean mPendingRotationChange;
|
||||
private boolean mIsRoundedCornerMultipleRadius;
|
||||
private boolean mIsPrivacyDotEnabled;
|
||||
private int mStatusBarHeightPortrait;
|
||||
private int mStatusBarHeightLandscape;
|
||||
private Drawable mRoundedCornerDrawable;
|
||||
private Drawable mRoundedCornerDrawableTop;
|
||||
private Drawable mRoundedCornerDrawableBottom;
|
||||
@@ -315,7 +313,6 @@ public class ScreenDecorations extends SystemUI implements Tunable {
|
||||
|
||||
private void setupDecorations() {
|
||||
if (hasRoundedCorners() || shouldDrawCutout() || mIsPrivacyDotEnabled) {
|
||||
updateStatusBarHeight();
|
||||
final DisplayCutout cutout = getCutout();
|
||||
for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
|
||||
if (shouldShowCutout(i, cutout) || shouldShowRoundedCorner(i, cutout)
|
||||
@@ -326,7 +323,8 @@ public class ScreenDecorations extends SystemUI implements Tunable {
|
||||
}
|
||||
}
|
||||
|
||||
if (mIsPrivacyDotEnabled) {
|
||||
if (mTopLeftDot != null && mTopRightDot != null && mBottomLeftDot != null
|
||||
&& mBottomRightDot != null) {
|
||||
// Overlays have been created, send the dots to the controller
|
||||
//TODO: need a better way to do this
|
||||
mDotViewController.initialize(
|
||||
@@ -430,7 +428,7 @@ public class ScreenDecorations extends SystemUI implements Tunable {
|
||||
if (mOverlays[pos] != null) {
|
||||
return;
|
||||
}
|
||||
mOverlays[pos] = overlayForPosition(pos);
|
||||
mOverlays[pos] = overlayForPosition(pos, cutout);
|
||||
|
||||
mCutoutViews[pos] = new DisplayCutoutView(mContext, pos, this);
|
||||
((ViewGroup) mOverlays[pos]).addView(mCutoutViews[pos]);
|
||||
@@ -462,10 +460,46 @@ public class ScreenDecorations extends SystemUI implements Tunable {
|
||||
/**
|
||||
* Allow overrides for top/bottom positions
|
||||
*/
|
||||
private View overlayForPosition(@BoundsPosition int pos) {
|
||||
private View overlayForPosition(@BoundsPosition int pos, @Nullable DisplayCutout cutout) {
|
||||
final int layoutId = (pos == BOUNDS_POSITION_LEFT || pos == BOUNDS_POSITION_TOP)
|
||||
? R.layout.rounded_corners_top : R.layout.rounded_corners_bottom;
|
||||
return LayoutInflater.from(mContext).inflate(layoutId, null);
|
||||
final ViewGroup vg = (ViewGroup) LayoutInflater.from(mContext).inflate(layoutId, null);
|
||||
initPrivacyDotView(vg, pos, cutout);
|
||||
return vg;
|
||||
}
|
||||
|
||||
private void initPrivacyDotView(@NonNull ViewGroup viewGroup, @BoundsPosition int pos,
|
||||
@Nullable DisplayCutout cutout) {
|
||||
final View left = viewGroup.findViewById(R.id.privacy_dot_left_container);
|
||||
final View right = viewGroup.findViewById(R.id.privacy_dot_right_container);
|
||||
if (!shouldShowPrivacyDot(pos, cutout)) {
|
||||
viewGroup.removeView(left);
|
||||
viewGroup.removeView(right);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (pos) {
|
||||
case BOUNDS_POSITION_LEFT: {
|
||||
mTopLeftDot = left;
|
||||
mBottomLeftDot = right;
|
||||
break;
|
||||
}
|
||||
case BOUNDS_POSITION_TOP: {
|
||||
mTopLeftDot = left;
|
||||
mTopRightDot = right;
|
||||
break;
|
||||
}
|
||||
case BOUNDS_POSITION_RIGHT: {
|
||||
mTopRightDot = left;
|
||||
mBottomRightDot = right;
|
||||
break;
|
||||
}
|
||||
case BOUNDS_POSITION_BOTTOM: {
|
||||
mBottomLeftDot = left;
|
||||
mBottomRightDot = right;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateView(@BoundsPosition int pos, @Nullable DisplayCutout cutout) {
|
||||
@@ -483,8 +517,6 @@ public class ScreenDecorations extends SystemUI implements Tunable {
|
||||
if (mCutoutViews != null && mCutoutViews[pos] != null) {
|
||||
mCutoutViews[pos].setRotation(mRotation);
|
||||
}
|
||||
|
||||
updatePrivacyDotView(pos, cutout);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -671,14 +703,6 @@ public class ScreenDecorations extends SystemUI implements Tunable {
|
||||
}
|
||||
}
|
||||
|
||||
private void updateStatusBarHeight() {
|
||||
mStatusBarHeightLandscape = mContext.getResources().getDimensionPixelSize(
|
||||
com.android.internal.R.dimen.status_bar_height_landscape);
|
||||
mStatusBarHeightPortrait = mContext.getResources().getDimensionPixelSize(
|
||||
com.android.internal.R.dimen.status_bar_height_portrait);
|
||||
mDotViewController.setStatusBarHeights(mStatusBarHeightPortrait, mStatusBarHeightLandscape);
|
||||
}
|
||||
|
||||
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
|
||||
@@ -812,26 +836,6 @@ public class ScreenDecorations extends SystemUI implements Tunable {
|
||||
}
|
||||
}
|
||||
|
||||
private void updatePrivacyDotView(@BoundsPosition int pos, @Nullable DisplayCutout cutout) {
|
||||
final ViewGroup viewGroup = (ViewGroup) mOverlays[pos];
|
||||
|
||||
final View left = viewGroup.findViewById(R.id.privacy_dot_left_container);
|
||||
final View right = viewGroup.findViewById(R.id.privacy_dot_right_container);
|
||||
if (shouldShowPrivacyDot(pos, cutout)) {
|
||||
// TODO (b/201481944) Privacy Dots pos and var are wrong with long side cutout enable
|
||||
if (pos == BOUNDS_POSITION_LEFT || pos == BOUNDS_POSITION_TOP) {
|
||||
mTopLeftDot = left;
|
||||
mTopRightDot = right;
|
||||
} else {
|
||||
mBottomLeftDot = left;
|
||||
mBottomRightDot = right;
|
||||
}
|
||||
} else {
|
||||
viewGroup.removeView(left);
|
||||
viewGroup.removeView(right);
|
||||
}
|
||||
}
|
||||
|
||||
private int getRoundedCornerGravity(@BoundsPosition int pos, boolean isStart) {
|
||||
final int rotatedPos = getBoundPositionFromRotation(pos, mRotation);
|
||||
switch (rotatedPos) {
|
||||
|
||||
@@ -24,7 +24,6 @@ import android.util.Log
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
|
||||
import com.android.internal.annotations.GuardedBy
|
||||
import com.android.systemui.animation.Interpolators
|
||||
import com.android.systemui.R
|
||||
@@ -44,7 +43,6 @@ import com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE
|
||||
import com.android.systemui.util.leak.RotationUtils.ROTATION_UPSIDE_DOWN
|
||||
import com.android.systemui.util.leak.RotationUtils.Rotation
|
||||
|
||||
import java.lang.IllegalStateException
|
||||
import java.util.concurrent.Executor
|
||||
import javax.inject.Inject
|
||||
|
||||
@@ -71,9 +69,6 @@ class PrivacyDotViewController @Inject constructor(
|
||||
private val contentInsetsProvider: StatusBarContentInsetsProvider,
|
||||
private val animationScheduler: SystemStatusAnimationScheduler
|
||||
) {
|
||||
private var sbHeightPortrait = 0
|
||||
private var sbHeightLandscape = 0
|
||||
|
||||
private lateinit var tl: View
|
||||
private lateinit var tr: View
|
||||
private lateinit var bl: View
|
||||
@@ -156,16 +151,12 @@ class PrivacyDotViewController @Inject constructor(
|
||||
|
||||
val newCorner = selectDesignatedCorner(rot, isRtl)
|
||||
val index = newCorner.cornerIndex()
|
||||
val paddingTop = contentInsetsProvider.getStatusBarPaddingTop(rot)
|
||||
|
||||
val h = when (rot) {
|
||||
0, 2 -> sbHeightPortrait
|
||||
1, 3 -> sbHeightLandscape
|
||||
else -> 0
|
||||
}
|
||||
synchronized(lock) {
|
||||
nextViewState = nextViewState.copy(
|
||||
rotation = rot,
|
||||
height = h,
|
||||
paddingTop = paddingTop,
|
||||
designatedCorner = newCorner,
|
||||
cornerIndex = index)
|
||||
}
|
||||
@@ -203,26 +194,17 @@ class PrivacyDotViewController @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private fun updateHeights(rot: Int) {
|
||||
val height = when (rot) {
|
||||
0, 2 -> sbHeightPortrait
|
||||
1, 3 -> sbHeightLandscape
|
||||
else -> 0
|
||||
}
|
||||
|
||||
views.forEach { it.layoutParams.height = height }
|
||||
}
|
||||
|
||||
// Update the gravity and margins of the privacy views
|
||||
@UiThread
|
||||
private fun updateRotations(rotation: Int) {
|
||||
private fun updateRotations(rotation: Int, paddingTop: Int) {
|
||||
// To keep a view in the corner, its gravity is always the description of its current corner
|
||||
// Therefore, just figure out which view is in which corner. This turns out to be something
|
||||
// like (myCorner - rot) mod 4, where topLeft = 0, topRight = 1, etc. and portrait = 0, and
|
||||
// rotating the device counter-clockwise increments rotation by 1
|
||||
|
||||
views.forEach { corner ->
|
||||
corner.setPadding(0, paddingTop, 0, 0)
|
||||
|
||||
val rotatedCorner = rotatedCorner(cornerForView(corner), rotation)
|
||||
(corner.layoutParams as FrameLayout.LayoutParams).apply {
|
||||
gravity = rotatedCorner.toGravity()
|
||||
@@ -265,6 +247,7 @@ class PrivacyDotViewController @Inject constructor(
|
||||
|
||||
var rot = activeRotationForCorner(tl, rtl)
|
||||
var contentInsets = state.contentRectForRotation(rot)
|
||||
tl.setPadding(0, state.paddingTop, 0, 0)
|
||||
(tl.layoutParams as FrameLayout.LayoutParams).apply {
|
||||
height = contentInsets.height()
|
||||
if (rtl) {
|
||||
@@ -276,6 +259,7 @@ class PrivacyDotViewController @Inject constructor(
|
||||
|
||||
rot = activeRotationForCorner(tr, rtl)
|
||||
contentInsets = state.contentRectForRotation(rot)
|
||||
tr.setPadding(0, state.paddingTop, 0, 0)
|
||||
(tr.layoutParams as FrameLayout.LayoutParams).apply {
|
||||
height = contentInsets.height()
|
||||
if (rtl) {
|
||||
@@ -287,6 +271,7 @@ class PrivacyDotViewController @Inject constructor(
|
||||
|
||||
rot = activeRotationForCorner(br, rtl)
|
||||
contentInsets = state.contentRectForRotation(rot)
|
||||
br.setPadding(0, state.paddingTop, 0, 0)
|
||||
(br.layoutParams as FrameLayout.LayoutParams).apply {
|
||||
height = contentInsets.height()
|
||||
if (rtl) {
|
||||
@@ -298,6 +283,7 @@ class PrivacyDotViewController @Inject constructor(
|
||||
|
||||
rot = activeRotationForCorner(bl, rtl)
|
||||
contentInsets = state.contentRectForRotation(rot)
|
||||
bl.setPadding(0, state.paddingTop, 0, 0)
|
||||
(bl.layoutParams as FrameLayout.LayoutParams).apply {
|
||||
height = contentInsets.height()
|
||||
if (rtl) {
|
||||
@@ -412,6 +398,7 @@ class PrivacyDotViewController @Inject constructor(
|
||||
val right = contentInsetsProvider.getStatusBarContentInsetsForRotation(ROTATION_LANDSCAPE)
|
||||
val bottom = contentInsetsProvider
|
||||
.getStatusBarContentInsetsForRotation(ROTATION_UPSIDE_DOWN)
|
||||
val paddingTop = contentInsetsProvider.getStatusBarPaddingTop()
|
||||
|
||||
synchronized(lock) {
|
||||
nextViewState = nextViewState.copy(
|
||||
@@ -422,20 +409,12 @@ class PrivacyDotViewController @Inject constructor(
|
||||
portraitRect = top,
|
||||
landscapeRect = right,
|
||||
upsideDownRect = bottom,
|
||||
paddingTop = paddingTop,
|
||||
layoutRtl = rtl
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the status bar height in portrait and landscape, in pixels. If they are the same you can
|
||||
* pass the same value twice
|
||||
*/
|
||||
fun setStatusBarHeights(portrait: Int, landscape: Int) {
|
||||
sbHeightPortrait = portrait
|
||||
sbHeightLandscape = landscape
|
||||
}
|
||||
|
||||
private fun updateStatusBarState() {
|
||||
synchronized(lock) {
|
||||
nextViewState = nextViewState.copy(shadeExpanded = isShadeInQs())
|
||||
@@ -488,7 +467,7 @@ class PrivacyDotViewController @Inject constructor(
|
||||
|
||||
if (state.rotation != currentViewState.rotation) {
|
||||
// A rotation has started, hide the views to avoid flicker
|
||||
updateRotations(state.rotation)
|
||||
updateRotations(state.rotation, state.paddingTop)
|
||||
}
|
||||
|
||||
if (state.needsLayout(currentViewState)) {
|
||||
@@ -627,7 +606,7 @@ private data class ViewState(
|
||||
val layoutRtl: Boolean = false,
|
||||
|
||||
val rotation: Int = 0,
|
||||
val height: Int = 0,
|
||||
val paddingTop: Int = 0,
|
||||
val cornerIndex: Int = -1,
|
||||
val designatedCorner: View? = null,
|
||||
|
||||
|
||||
@@ -179,6 +179,11 @@ class StatusBarContentInsetsProvider @Inject constructor(
|
||||
minRight)
|
||||
}
|
||||
|
||||
fun getStatusBarPaddingTop(@Rotation rotation: Int? = null): Int {
|
||||
val res = rotation?.let { it -> getResourcesForRotation(it, context) } ?: context.resources
|
||||
return res.getDimensionPixelSize(R.dimen.status_bar_padding_top)
|
||||
}
|
||||
|
||||
override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
|
||||
insetsCache.snapshot().forEach { (key, rect) ->
|
||||
pw.println("$key -> $rect")
|
||||
|
||||
Reference in New Issue
Block a user