Make systemui support waterfall

- Status bar content should be always below waterfall. We have to
minus status bar height with waterfall inset top to get the correct
content height and set the top padding/margin to waterfall inset top.

- Update paddings/margins for waterfall insets in below 3 places, which
also move setup rouned corner padding from ScreenDecorations to these 3
places.
   1. PhoneStatusBar
   2. QuickStatusBarHeader
   3. KeyguardStatusBarView

- Adjust notification minimum expand height for waterfall in
NotificationStackScrollLayout.

Bug: 146876976
Test: manual-select waterfall cutout overlay in develop option and check
the status bar.
Test: atest SystemUITests

Change-Id: Ib489e0ac69433635c3be990b5f8e56a3704b4a09
This commit is contained in:
shawnlin
2020-01-29 18:38:49 +08:00
parent 977530517c
commit bd6d0ad8ac
8 changed files with 225 additions and 246 deletions

View File

@@ -22,12 +22,8 @@ import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static com.android.systemui.tuner.TunablePadding.FLAG_END;
import static com.android.systemui.tuner.TunablePadding.FLAG_START;
import android.annotation.Dimension;
import android.app.ActivityManager;
import android.app.Fragment;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -69,13 +65,7 @@ import com.android.internal.util.Preconditions;
import com.android.systemui.RegionInterceptingFrameLayout.RegionInterceptableView;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.qs.SecureSetting;
import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.tuner.TunablePadding;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
import com.android.systemui.util.leak.RotationUtils;
@@ -86,8 +76,6 @@ import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
import dagger.Lazy;
/**
* An overlay that draws screen decorations in software (e.g for rounded corners or display cutout)
* for antialiasing and emulation purposes.
@@ -102,7 +90,6 @@ public class ScreenDecorations extends SystemUI implements Tunable {
private static final boolean DEBUG_SCREENSHOT_ROUNDED_CORNERS =
SystemProperties.getBoolean("debug.screenshot_rounded_corners", false);
private static final boolean VERBOSE = false;
private final Lazy<StatusBar> mStatusBarLazy;
private DisplayManager mDisplayManager;
private final BroadcastDispatcher mBroadcastDispatcher;
@@ -146,12 +133,10 @@ public class ScreenDecorations extends SystemUI implements Tunable {
@Inject
public ScreenDecorations(Context context,
Lazy<StatusBar> statusBarLazy,
@Main Handler handler,
BroadcastDispatcher broadcastDispatcher,
TunerService tunerService) {
super(context);
mStatusBarLazy = statusBarLazy;
mMainHandler = handler;
mBroadcastDispatcher = broadcastDispatcher;
mTunerService = tunerService;
@@ -161,7 +146,6 @@ public class ScreenDecorations extends SystemUI implements Tunable {
public void start() {
mHandler = startHandlerThread();
mHandler.post(this::startOnScreenDecorationsThread);
setupStatusBarPaddingIfNeeded();
}
@VisibleForTesting
@@ -440,42 +424,6 @@ public class ScreenDecorations extends SystemUI implements Tunable {
com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout);
}
private void setupStatusBarPaddingIfNeeded() {
// TODO: This should be moved to a more appropriate place, as it is not related to the
// screen decorations overlay.
int padding = mContext.getResources().getDimensionPixelSize(
R.dimen.rounded_corner_content_padding);
if (padding != 0) {
setupStatusBarPadding(padding);
}
}
private void setupStatusBarPadding(int padding) {
// Add some padding to all the content near the edge of the screen.
StatusBar statusBar = mStatusBarLazy.get();
final View notificationShadeWindowView = statusBar.getNotificationShadeWindowView();
if (notificationShadeWindowView != null) {
TunablePadding.addTunablePadding(
notificationShadeWindowView.findViewById(R.id.keyguard_header),
PADDING, padding, FLAG_END);
final FragmentHostManager fragmentHostManager =
FragmentHostManager.get(notificationShadeWindowView);
fragmentHostManager.addTagListener(QS.TAG,
new TunablePaddingTagListener(padding, R.id.header));
}
final View statusBarWindow = statusBar.getStatusBarWindow();
if (statusBarWindow != null) {
final FragmentHostManager fragmentHostManager =
FragmentHostManager.get(statusBarWindow);
fragmentHostManager.addTagListener(CollapsedStatusBarFragment.TAG,
new TunablePaddingTagListener(padding, R.id.status_bar));
}
}
@VisibleForTesting
WindowManager.LayoutParams getWindowLayoutParams() {
final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
@@ -566,32 +514,6 @@ public class ScreenDecorations extends SystemUI implements Tunable {
view.setLayoutParams(params);
}
@VisibleForTesting
static class TunablePaddingTagListener implements FragmentListener {
private final int mPadding;
private final int mId;
private TunablePadding mTunablePadding;
public TunablePaddingTagListener(int padding, int id) {
mPadding = padding;
mId = id;
}
@Override
public void onFragmentViewCreated(String tag, Fragment fragment) {
if (mTunablePadding != null) {
mTunablePadding.destroy();
}
View view = fragment.getView();
if (mId != 0) {
view = view.findViewById(mId);
}
mTunablePadding = TunablePadding.addTunablePadding(view, PADDING, mPadding,
FLAG_START | FLAG_END);
}
}
public static class DisplayCutoutView extends View implements DisplayManager.DisplayListener,
RegionInterceptableView {
@@ -763,11 +685,11 @@ public class ScreenDecorations extends SystemUI implements Tunable {
return false;
}
if (mStart) {
return displayCutout.getSafeInsetLeft() > 0
|| displayCutout.getSafeInsetTop() > 0;
return !displayCutout.getBoundingRectLeft().isEmpty()
|| !displayCutout.getBoundingRectTop().isEmpty();
} else {
return displayCutout.getSafeInsetRight() > 0
|| displayCutout.getSafeInsetBottom() > 0;
return !displayCutout.getBoundingRectRight().isEmpty()
|| !displayCutout.getBoundingRectBottom().isEmpty();
}
}
@@ -809,15 +731,15 @@ public class ScreenDecorations extends SystemUI implements Tunable {
private int getGravity(DisplayCutout displayCutout) {
if (mStart) {
if (displayCutout.getSafeInsetLeft() > 0) {
if (!displayCutout.getBoundingRectLeft().isEmpty()) {
return Gravity.LEFT;
} else if (displayCutout.getSafeInsetTop() > 0) {
} else if (!displayCutout.getBoundingRectTop().isEmpty()) {
return Gravity.TOP;
}
} else {
if (displayCutout.getSafeInsetRight() > 0) {
if (!displayCutout.getBoundingRectRight().isEmpty()) {
return Gravity.RIGHT;
} else if (displayCutout.getSafeInsetBottom() > 0) {
} else if (!displayCutout.getBoundingRectBottom().isEmpty()) {
return Gravity.BOTTOM;
}
}

View File

@@ -61,9 +61,9 @@ import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.qs.QSDetail.Callback;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.PhoneStatusBarView;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
import com.android.systemui.statusbar.phone.StatusBarWindowView;
import com.android.systemui.statusbar.phone.StatusIconContainer;
import com.android.systemui.statusbar.policy.Clock;
import com.android.systemui.statusbar.policy.DateView;
@@ -146,6 +146,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements
}
};
private boolean mHasTopCutout = false;
private int mRoundedCornerPadding = 0;
@Inject
public QuickStatusBarHeader(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
@@ -325,6 +326,9 @@ public class QuickStatusBarHeader extends RelativeLayout implements
Resources resources = mContext.getResources();
updateMinimumHeight();
mRoundedCornerPadding = resources.getDimensionPixelSize(
R.dimen.rounded_corner_content_padding);
// Update height for a few views, especially due to landscape mode restricting space.
mHeaderTextContainerView.getLayoutParams().height =
resources.getDimensionPixelSize(R.dimen.qs_header_tooltip_height);
@@ -432,16 +436,23 @@ public class QuickStatusBarHeader extends RelativeLayout implements
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
DisplayCutout cutout = insets.getDisplayCutout();
Pair<Integer, Integer> padding = PhoneStatusBarView.cornerCutoutMargins(
cutout, getDisplay());
if (padding == null) {
mSystemIconsView.setPaddingRelative(
getResources().getDimensionPixelSize(R.dimen.status_bar_padding_start), 0,
getResources().getDimensionPixelSize(R.dimen.status_bar_padding_end), 0);
} else {
mSystemIconsView.setPadding(padding.first, 0, padding.second, 0);
}
// Handle padding of QuickStatusBarHeader
Pair<Integer, Integer> cornerCutoutPadding = StatusBarWindowView.cornerCutoutMargins(
cutout, getDisplay());
Pair<Integer, Integer> padding =
StatusBarWindowView.paddingNeededForCutoutAndRoundedCorner(
cutout, cornerCutoutPadding, mRoundedCornerPadding);
setPadding(padding.first, 0, padding.second, getPaddingBottom());
// Handle padding of SystemIconsView
final int waterfallTopInset = cutout == null ? 0 : cutout.getWaterfallInsets().top;
mSystemIconsView.setPaddingRelative(
getResources().getDimensionPixelSize(R.dimen.status_bar_padding_start),
waterfallTopInset,
getResources().getDimensionPixelSize(R.dimen.status_bar_padding_end),
0);
return super.onApplyWindowInsets(insets);
}

View File

@@ -57,6 +57,7 @@ import android.util.Log;
import android.util.MathUtils;
import android.util.Pair;
import android.view.ContextThemeWrapper;
import android.view.DisplayCutout;
import android.view.InputDevice;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -513,6 +514,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
private float mLastSentExpandedHeight;
private boolean mWillExpand;
private int mWaterfallTopInset;
@Inject
public NotificationStackScrollLayout(
@Named(VIEW_CONTEXT) Context context,
@@ -1714,6 +1717,12 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
mBottomInset = insets.getSystemWindowInsetBottom();
mWaterfallTopInset = 0;
final DisplayCutout cutout = insets.getDisplayCutout();
if (cutout != null) {
mWaterfallTopInset = cutout.getWaterfallInsets().top;
}
if (ANCHOR_SCROLLING) {
// TODO
} else {
@@ -5310,7 +5319,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
public int getMinExpansionHeight() {
return mShelf.getIntrinsicHeight() - (mShelf.getIntrinsicHeight() - mStatusBarHeight) / 2;
return mShelf.getIntrinsicHeight()
- (mShelf.getIntrinsicHeight() - mStatusBarHeight + mWaterfallTopInset) / 2
+ mWaterfallTopInset;
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)

View File

@@ -102,6 +102,9 @@ public class KeyguardStatusBarView extends RelativeLayout
*/
private int mCutoutSideNudge = 0;
private DisplayCutout mDisplayCutout;
private int mRoundedCornerPadding = 0;
public KeyguardStatusBarView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@@ -159,9 +162,15 @@ public class KeyguardStatusBarView extends RelativeLayout
getResources().getDimensionPixelSize(R.dimen.keyguard_carrier_text_margin));
mCarrierLabel.setLayoutParams(lp);
lp = (MarginLayoutParams) getLayoutParams();
updateKeyguardStatusBarHeight();
}
private void updateKeyguardStatusBarHeight() {
final int waterfallTop =
mDisplayCutout == null ? 0 : mDisplayCutout.getWaterfallInsets().top;
MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();
lp.height = getResources().getDimensionPixelSize(
R.dimen.status_bar_header_height_keyguard);
R.dimen.status_bar_header_height_keyguard) + waterfallTop;
setLayoutParams(lp);
}
@@ -175,6 +184,8 @@ public class KeyguardStatusBarView extends RelativeLayout
R.dimen.display_cutout_margin_consumption);
mShowPercentAvailable = getContext().getResources().getBoolean(
com.android.internal.R.bool.config_battery_percentage_setting_available);
mRoundedCornerPadding = res.getDimensionPixelSize(
R.dimen.rounded_corner_content_padding);
}
private void updateVisibilities() {
@@ -225,23 +236,26 @@ public class KeyguardStatusBarView extends RelativeLayout
}
private boolean updateLayoutConsideringCutout() {
DisplayCutout dc = getRootWindowInsets().getDisplayCutout();
mDisplayCutout = getRootWindowInsets().getDisplayCutout();
updateKeyguardStatusBarHeight();
Pair<Integer, Integer> cornerCutoutMargins =
PhoneStatusBarView.cornerCutoutMargins(dc, getDisplay());
updateCornerCutoutPadding(cornerCutoutMargins);
if (dc == null || cornerCutoutMargins != null) {
StatusBarWindowView.cornerCutoutMargins(mDisplayCutout, getDisplay());
updatePadding(cornerCutoutMargins);
if (mDisplayCutout == null || cornerCutoutMargins != null) {
return updateLayoutParamsNoCutout();
} else {
return updateLayoutParamsForCutout(dc);
return updateLayoutParamsForCutout();
}
}
private void updateCornerCutoutPadding(Pair<Integer, Integer> cornerCutoutMargins) {
if (cornerCutoutMargins != null) {
setPadding(cornerCutoutMargins.first, 0, cornerCutoutMargins.second, 0);
} else {
setPadding(0, 0, 0, 0);
}
private void updatePadding(Pair<Integer, Integer> cornerCutoutMargins) {
final int waterfallTop =
mDisplayCutout == null ? 0 : mDisplayCutout.getWaterfallInsets().top;
Pair<Integer, Integer> padding =
StatusBarWindowView.paddingNeededForCutoutAndRoundedCorner(
mDisplayCutout, cornerCutoutMargins, mRoundedCornerPadding);
setPadding(padding.first, waterfallTop, padding.second, 0);
}
private boolean updateLayoutParamsNoCutout() {
@@ -268,7 +282,7 @@ public class KeyguardStatusBarView extends RelativeLayout
return true;
}
private boolean updateLayoutParamsForCutout(DisplayCutout dc) {
private boolean updateLayoutParamsForCutout() {
if (mLayoutState == LAYOUT_CUTOUT) {
return false;
}
@@ -279,7 +293,7 @@ public class KeyguardStatusBarView extends RelativeLayout
}
Rect bounds = new Rect();
boundsFromDirection(dc, Gravity.TOP, bounds);
boundsFromDirection(mDisplayCutout, Gravity.TOP, bounds);
mCutoutSpace.setVisibility(View.VISIBLE);
RelativeLayout.LayoutParams lp = (LayoutParams) mCutoutSpace.getLayoutParams();

View File

@@ -88,33 +88,11 @@ public class NotificationShadeWindowView extends FrameLayout {
boolean paddingChanged = insets.top != getPaddingTop()
|| insets.bottom != getPaddingBottom();
int rightCutout = 0;
int leftCutout = 0;
DisplayCutout displayCutout = getRootWindowInsets().getDisplayCutout();
if (displayCutout != null) {
leftCutout = displayCutout.getSafeInsetLeft();
rightCutout = displayCutout.getSafeInsetRight();
}
int targetLeft = Math.max(insets.left, leftCutout);
int targetRight = Math.max(insets.right, rightCutout);
// Super-special right inset handling, because scrims and backdrop need to ignore it.
if (targetRight != mRightInset || targetLeft != mLeftInset) {
mRightInset = targetRight;
mLeftInset = targetLeft;
applyMargins();
}
// Drop top inset, and pass through bottom inset.
if (paddingChanged) {
setPadding(0, 0, 0, 0);
}
} else {
if (mRightInset != 0 || mLeftInset != 0) {
mRightInset = 0;
mLeftInset = 0;
applyMargins();
}
boolean changed = getPaddingLeft() != 0
|| getPaddingRight() != 0
|| getPaddingTop() != 0
@@ -123,6 +101,17 @@ public class NotificationShadeWindowView extends FrameLayout {
setPadding(0, 0, 0, 0);
}
}
mLeftInset = 0;
mRightInset = 0;
DisplayCutout displayCutout = getRootWindowInsets().getDisplayCutout();
if (displayCutout != null) {
mLeftInset = displayCutout.getSafeInsetLeft();
mRightInset = displayCutout.getSafeInsetRight();
}
mLeftInset = Math.max(insets.left, mLeftInset);
mRightInset = Math.max(insets.right, mRightInset);
applyMargins();
return windowInsets;
}

View File

@@ -23,12 +23,10 @@ import static com.android.systemui.ScreenDecorations.DisplayCutoutView.boundsFro
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.EventLog;
import android.util.Pair;
import android.view.Display;
import android.view.DisplayCutout;
import android.view.Gravity;
import android.view.MotionEvent;
@@ -36,7 +34,6 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
import android.view.accessibility.AccessibilityEvent;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import com.android.systemui.Dependency;
@@ -84,6 +81,8 @@ public class PhoneStatusBarView extends PanelBar {
private int mCutoutSideNudge = 0;
private boolean mHeadsUpVisible;
private int mRoundedCornerPadding = 0;
public PhoneStatusBarView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -294,15 +293,25 @@ public class PhoneStatusBarView extends PanelBar {
public void updateResources() {
mCutoutSideNudge = getResources().getDimensionPixelSize(
R.dimen.display_cutout_margin_consumption);
mRoundedCornerPadding = getResources().getDimensionPixelSize(
R.dimen.rounded_corner_content_padding);
updateStatusBarHeight();
}
private void updateStatusBarHeight() {
final int waterfallTopInset =
mDisplayCutout == null ? 0 : mDisplayCutout.getWaterfallInsets().top;
ViewGroup.LayoutParams layoutParams = getLayoutParams();
layoutParams.height = getResources().getDimensionPixelSize(R.dimen.status_bar_height);
layoutParams.height =
getResources().getDimensionPixelSize(R.dimen.status_bar_height) - waterfallTopInset;
setLayoutParams(layoutParams);
}
private void updateLayoutForCutout() {
Pair<Integer, Integer> cornerCutoutMargins = cornerCutoutMargins(mDisplayCutout,
getDisplay());
updateStatusBarHeight();
Pair<Integer, Integer> cornerCutoutMargins =
StatusBarWindowView.cornerCutoutMargins(mDisplayCutout, getDisplay());
updateCutoutLocation(cornerCutoutMargins);
updateSafeInsets(cornerCutoutMargins);
}
@@ -337,47 +346,11 @@ public class PhoneStatusBarView extends PanelBar {
// Depending on our rotation, we may have to work around a cutout in the middle of the view,
// or letterboxing from the right or left sides.
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
if (mDisplayCutout == null || mDisplayCutout.isEmpty()
|| mLastOrientation != ORIENTATION_PORTRAIT || cornerCutoutMargins == null) {
lp.leftMargin = 0;
lp.rightMargin = 0;
return;
}
Pair<Integer, Integer> padding =
StatusBarWindowView.paddingNeededForCutoutAndRoundedCorner(
mDisplayCutout, cornerCutoutMargins, mRoundedCornerPadding);
lp.leftMargin = Math.max(lp.leftMargin, cornerCutoutMargins.first);
lp.rightMargin = Math.max(lp.rightMargin, cornerCutoutMargins.second);
// If we're already inset enough (e.g. on the status bar side), we can have 0 margin
WindowInsets insets = getRootWindowInsets();
int leftInset = insets.getSystemWindowInsetLeft();
int rightInset = insets.getSystemWindowInsetRight();
if (lp.leftMargin <= leftInset) {
lp.leftMargin = 0;
}
if (lp.rightMargin <= rightInset) {
lp.rightMargin = 0;
}
}
public static Pair<Integer, Integer> cornerCutoutMargins(DisplayCutout cutout,
Display display) {
if (cutout == null) {
return null;
}
Point size = new Point();
display.getRealSize(size);
Rect bounds = new Rect();
boundsFromDirection(cutout, Gravity.TOP, bounds);
if (bounds.left <= 0) {
return new Pair<>(bounds.right, 0);
}
if (bounds.right >= size.x) {
return new Pair<>(0, size.x - bounds.left);
}
return null;
setPadding(padding.first, getPaddingTop(), padding.second, getPaddingBottom());
}
public void setHeadsUpVisible(boolean headsUpVisible) {

View File

@@ -16,8 +16,21 @@
package com.android.systemui.statusbar.phone;
import static android.view.WindowInsets.Type.systemBars;
import static com.android.systemui.ScreenDecorations.DisplayCutoutView.boundsFromDirection;
import android.content.Context;
import android.graphics.Insets;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Pair;
import android.view.Display;
import android.view.DisplayCutout;
import android.view.Gravity;
import android.view.View;
import android.view.WindowInsets;
import android.widget.FrameLayout;
/**
@@ -28,7 +41,118 @@ public class StatusBarWindowView extends FrameLayout {
public static final String TAG = "PhoneStatusBarWindowView";
public static final boolean DEBUG = StatusBar.DEBUG;
private int mLeftInset = 0;
private int mRightInset = 0;
private int mTopInset = 0;
public StatusBarWindowView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public WindowInsets onApplyWindowInsets(WindowInsets windowInsets) {
final Insets insets = windowInsets.getInsetsIgnoringVisibility(systemBars());
mLeftInset = 0;
mRightInset = 0;
mTopInset = 0;
DisplayCutout displayCutout = getRootWindowInsets().getDisplayCutout();
if (displayCutout != null) {
mTopInset = displayCutout.getWaterfallInsets().top;
mLeftInset = displayCutout.getSafeInsetLeft();
mRightInset = displayCutout.getSafeInsetRight();
}
mLeftInset = Math.max(insets.left, mLeftInset);
mRightInset = Math.max(insets.right, mRightInset);
applyMargins();
return windowInsets;
}
private void applyMargins() {
final int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
if (child.getLayoutParams() instanceof LayoutParams) {
LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp.rightMargin != mRightInset || lp.leftMargin != mLeftInset
|| lp.topMargin != mTopInset) {
lp.rightMargin = mRightInset;
lp.leftMargin = mLeftInset;
lp.topMargin = mTopInset;
child.requestLayout();
}
}
}
}
/**
* Compute the padding needed for status bar related views, e.g., PhoneStatusBar,
* QuickStatusBarHeader and KeyguardStatusBarView).
*
* @param cutout
* @param cornerCutoutPadding
* @param roundedCornerContentPadding
* @return
*/
public static Pair<Integer, Integer> paddingNeededForCutoutAndRoundedCorner(
DisplayCutout cutout, Pair<Integer, Integer> cornerCutoutPadding,
int roundedCornerContentPadding) {
if (cutout == null) {
return new Pair<>(roundedCornerContentPadding, roundedCornerContentPadding);
}
// compute the padding needed for corner cutout.
final int leftMargin = cutout.getSafeInsetLeft();
final int rightMargin = cutout.getSafeInsetRight();
int leftCornerCutoutPadding = 0;
int rightCornerCutoutPadding = 0;
if (cornerCutoutPadding != null) {
if (cornerCutoutPadding.first > leftMargin) {
leftCornerCutoutPadding = cornerCutoutPadding.first - leftMargin;
}
if (cornerCutoutPadding.second > rightMargin) {
rightCornerCutoutPadding = cornerCutoutPadding.second - rightMargin;
}
}
// compute the padding needed for rounded corner
int leftRoundedCornerPadding = 0;
int rightRoundedCornerPadding = 0;
if (roundedCornerContentPadding > leftMargin) {
leftRoundedCornerPadding = roundedCornerContentPadding - leftMargin;
}
if (roundedCornerContentPadding > rightMargin) {
rightRoundedCornerPadding = roundedCornerContentPadding - rightMargin;
}
return new Pair<>(
Math.max(leftCornerCutoutPadding, leftRoundedCornerPadding),
Math.max(rightCornerCutoutPadding, rightRoundedCornerPadding));
}
/**
* Compute the corner cutout margins
*
* @param cutout
* @param display
* @return
*/
public static Pair<Integer, Integer> cornerCutoutMargins(DisplayCutout cutout,
Display display) {
if (cutout == null) {
return null;
}
Point size = new Point();
display.getRealSize(size);
Rect bounds = new Rect();
boundsFromDirection(cutout, Gravity.TOP, bounds);
if (bounds.left <= 0) {
return new Pair<>(bounds.right, 0);
}
if (bounds.right >= size.x) {
return new Pair<>(0, size.x - bounds.left);
}
return null;
}
}

View File

@@ -17,25 +17,18 @@ package com.android.systemui;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
import static com.android.systemui.ScreenDecorations.rectsToRegion;
import static com.android.systemui.tuner.TunablePadding.FLAG_END;
import static com.android.systemui.tuner.TunablePadding.FLAG_START;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Fragment;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Handler;
@@ -43,21 +36,12 @@ import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
import androidx.test.filters.SmallTest;
import com.android.systemui.R.dimen;
import com.android.systemui.ScreenDecorations.TunablePaddingTagListener;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarWindowView;
import com.android.systemui.tuner.TunablePadding;
import com.android.systemui.tuner.TunablePadding.TunablePaddingService;
import com.android.systemui.tuner.TunerService;
import org.junit.Before;
@@ -68,8 +52,6 @@ import org.mockito.MockitoAnnotations;
import java.util.Collections;
import dagger.Lazy;
@RunWithLooper
@RunWith(AndroidTestingRunner.class)
@SmallTest
@@ -77,19 +59,12 @@ public class ScreenDecorationsTest extends SysuiTestCase {
private TestableLooper mTestableLooper;
private ScreenDecorations mScreenDecorations;
@Mock private StatusBar mStatusBar;
private WindowManager mWindowManager;
private FragmentService mFragmentService;
private FragmentHostManager mFragmentHostManager;
private NotificationShadeWindowView mView;
private StatusBarWindowView mStatusBarWindowView;
private TunablePaddingService mTunablePaddingService;
private Handler mMainHandler;
@Mock
private TunerService mTunerService;
@Mock
private BroadcastDispatcher mBroadcastDispatcher;
@Mock private Lazy<StatusBar> mStatusBarLazy;
@Before
public void setup() {
@@ -97,25 +72,14 @@ public class ScreenDecorationsTest extends SysuiTestCase {
mTestableLooper = TestableLooper.get(this);
mMainHandler = new Handler(mTestableLooper.getLooper());
mTunablePaddingService = mDependency.injectMockDependency(TunablePaddingService.class);
mFragmentService = mDependency.injectMockDependency(FragmentService.class);
mWindowManager = mock(WindowManager.class);
mView = spy(new NotificationShadeWindowView(mContext, null));
mStatusBarWindowView = spy(new StatusBarWindowView(mContext, null));
when(mStatusBarLazy.get()).thenReturn(mStatusBar);
when(mStatusBar.getNotificationShadeWindowView()).thenReturn(mView);
when(mStatusBar.getStatusBarWindow()).thenReturn(mStatusBarWindowView);
Display display = mContext.getSystemService(WindowManager.class).getDefaultDisplay();
when(mWindowManager.getDefaultDisplay()).thenReturn(display);
mContext.addMockSystemService(WindowManager.class, mWindowManager);
mFragmentHostManager = mock(FragmentHostManager.class);
when(mFragmentService.getFragmentHostManager(any())).thenReturn(mFragmentHostManager);
mScreenDecorations = new ScreenDecorations(mContext, mStatusBarLazy, mMainHandler,
mScreenDecorations = new ScreenDecorations(mContext, mMainHandler,
mBroadcastDispatcher, mTunerService) {
@Override
public void start() {
@@ -159,8 +123,6 @@ public class ScreenDecorationsTest extends SysuiTestCase {
mScreenDecorations.start();
// No views added.
verify(mWindowManager, never()).addView(any(), any());
// No Fragments watched.
verify(mFragmentHostManager, never()).addTagListener(any(), any());
// No Tuners tuned.
verify(mTunerService, never()).addTunable(any(), any());
}
@@ -178,12 +140,8 @@ public class ScreenDecorationsTest extends SysuiTestCase {
// Add 2 windows for rounded corners (top and bottom).
verify(mWindowManager, times(2)).addView(any(), any());
// Add 2 tag listeners for each of the fragments that are needed.
verify(mFragmentHostManager, times(2)).addTagListener(any(), any());
// One tunable.
verify(mTunerService, times(1)).addTunable(any(), any());
// One TunablePadding.
verify(mTunablePaddingService, times(1)).add(any(), anyString(), anyInt(), anyInt());
}
@Test
@@ -226,29 +184,6 @@ public class ScreenDecorationsTest extends SysuiTestCase {
is(PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY));
}
@Test
public void testPaddingTagListener() {
TunablePaddingTagListener tagListener = new TunablePaddingTagListener(14, 5);
View v = mock(View.class);
View child = mock(View.class);
Fragment f = mock(Fragment.class);
TunablePadding padding = mock(TunablePadding.class);
when(mTunablePaddingService.add(any(), anyString(), anyInt(), anyInt()))
.thenReturn(padding);
when(f.getView()).thenReturn(v);
when(v.findViewById(5)).thenReturn(child);
// Trigger callback and verify we get a TunablePadding created.
tagListener.onFragmentViewCreated(null, f);
verify(mTunablePaddingService).add(eq(child), eq(ScreenDecorations.PADDING), eq(14),
eq(FLAG_START | FLAG_END));
// Call again and verify destroy is called.
tagListener.onFragmentViewCreated(null, f);
verify(padding).destroy();
}
@Test
public void testUpdateRoundedCorners() {
mContext.getOrCreateTestableResources().addOverride(