1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.statusbar.phone; 18 19 import static android.view.WindowInsets.Type.systemBars; 20 21 import static com.android.systemui.ScreenDecorations.DisplayCutoutView.boundsFromDirection; 22 23 import android.content.Context; 24 import android.graphics.Insets; 25 import android.graphics.Point; 26 import android.graphics.Rect; 27 import android.util.AttributeSet; 28 import android.util.Pair; 29 import android.view.Display; 30 import android.view.DisplayCutout; 31 import android.view.Gravity; 32 import android.view.View; 33 import android.view.WindowInsets; 34 import android.widget.FrameLayout; 35 36 import com.android.systemui.util.leak.RotationUtils; 37 38 /** 39 * Status bar view. 40 */ 41 public class StatusBarWindowView extends FrameLayout { 42 43 public static final String TAG = "PhoneStatusBarWindowView"; 44 public static final boolean DEBUG = StatusBar.DEBUG; 45 46 private int mLeftInset = 0; 47 private int mRightInset = 0; 48 private int mTopInset = 0; 49 StatusBarWindowView(Context context, AttributeSet attrs)50 public StatusBarWindowView(Context context, AttributeSet attrs) { 51 super(context, attrs); 52 } 53 54 @Override onApplyWindowInsets(WindowInsets windowInsets)55 public WindowInsets onApplyWindowInsets(WindowInsets windowInsets) { 56 final Insets insets = windowInsets.getInsetsIgnoringVisibility(systemBars()); 57 mLeftInset = insets.left; 58 mRightInset = insets.right; 59 mTopInset = 0; 60 DisplayCutout displayCutout = getRootWindowInsets().getDisplayCutout(); 61 if (displayCutout != null) { 62 mTopInset = displayCutout.getWaterfallInsets().top; 63 } 64 applyMargins(); 65 return windowInsets; 66 } 67 applyMargins()68 private void applyMargins() { 69 final int count = getChildCount(); 70 for (int i = 0; i < count; i++) { 71 View child = getChildAt(i); 72 if (child.getLayoutParams() instanceof LayoutParams) { 73 LayoutParams lp = (LayoutParams) child.getLayoutParams(); 74 if (lp.rightMargin != mRightInset || lp.leftMargin != mLeftInset 75 || lp.topMargin != mTopInset) { 76 lp.rightMargin = mRightInset; 77 lp.leftMargin = mLeftInset; 78 lp.topMargin = mTopInset; 79 child.requestLayout(); 80 } 81 } 82 } 83 } 84 85 /** 86 * Compute the padding needed for status bar related views, e.g., PhoneStatusBar, 87 * QuickStatusBarHeader and KeyguardStatusBarView). 88 * 89 * @param cutout 90 * @param cornerCutoutPadding 91 * @param roundedCornerContentPadding 92 * @return 93 */ paddingNeededForCutoutAndRoundedCorner( DisplayCutout cutout, Pair<Integer, Integer> cornerCutoutPadding, int roundedCornerContentPadding)94 public static Pair<Integer, Integer> paddingNeededForCutoutAndRoundedCorner( 95 DisplayCutout cutout, Pair<Integer, Integer> cornerCutoutPadding, 96 int roundedCornerContentPadding) { 97 if (cutout == null) { 98 return new Pair<>(roundedCornerContentPadding, roundedCornerContentPadding); 99 } 100 101 // padding needed for corner cutout. 102 int leftCornerCutoutPadding = cutout.getSafeInsetLeft(); 103 int rightCornerCutoutPadding = cutout.getSafeInsetRight(); 104 if (cornerCutoutPadding != null) { 105 leftCornerCutoutPadding = Math.max(leftCornerCutoutPadding, cornerCutoutPadding.first); 106 rightCornerCutoutPadding = Math.max(rightCornerCutoutPadding, 107 cornerCutoutPadding.second); 108 } 109 110 return new Pair<>( 111 Math.max(leftCornerCutoutPadding, roundedCornerContentPadding), 112 Math.max(rightCornerCutoutPadding, roundedCornerContentPadding)); 113 } 114 115 116 /** 117 * Compute the corner cutout margins in portrait mode 118 */ cornerCutoutMargins(DisplayCutout cutout, Display display)119 public static Pair<Integer, Integer> cornerCutoutMargins(DisplayCutout cutout, 120 Display display) { 121 return statusBarCornerCutoutMargins(cutout, display, RotationUtils.ROTATION_NONE, 0); 122 } 123 124 /** 125 * Compute the corner cutout margins in the given orientation (exactRotation) 126 */ statusBarCornerCutoutMargins(DisplayCutout cutout, Display display, int exactRotation, int statusBarHeight)127 public static Pair<Integer, Integer> statusBarCornerCutoutMargins(DisplayCutout cutout, 128 Display display, int exactRotation, int statusBarHeight) { 129 if (cutout == null) { 130 return null; 131 } 132 Point size = new Point(); 133 display.getRealSize(size); 134 135 Rect bounds = new Rect(); 136 switch (exactRotation) { 137 case RotationUtils.ROTATION_LANDSCAPE: 138 boundsFromDirection(cutout, Gravity.LEFT, bounds); 139 break; 140 case RotationUtils.ROTATION_SEASCAPE: 141 boundsFromDirection(cutout, Gravity.RIGHT, bounds); 142 break; 143 case RotationUtils.ROTATION_NONE: 144 boundsFromDirection(cutout, Gravity.TOP, bounds); 145 break; 146 case RotationUtils.ROTATION_UPSIDE_DOWN: 147 // we assume the cutout is always on top in portrait mode 148 return null; 149 } 150 151 if (statusBarHeight >= 0 && bounds.top > statusBarHeight) { 152 return null; 153 } 154 155 if (bounds.left <= 0) { 156 return new Pair<>(bounds.right, 0); 157 } 158 159 if (bounds.right >= size.x) { 160 return new Pair<>(0, size.x - bounds.left); 161 } 162 163 return null; 164 } 165 } 166