• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.MotionEvent.ACTION_DOWN;
20 import static android.view.MotionEvent.ACTION_MOVE;
21 import static android.view.MotionEvent.ACTION_UP;
22 import static android.view.WindowInsets.Type.systemBars;
23 
24 import static com.android.systemui.ScreenDecorations.DisplayCutoutView.boundsFromDirection;
25 
26 import android.content.Context;
27 import android.graphics.Insets;
28 import android.graphics.Point;
29 import android.graphics.Rect;
30 import android.util.AttributeSet;
31 import android.util.Pair;
32 import android.view.Display;
33 import android.view.DisplayCutout;
34 import android.view.Gravity;
35 import android.view.MotionEvent;
36 import android.view.View;
37 import android.view.WindowInsets;
38 import android.widget.FrameLayout;
39 
40 import androidx.annotation.NonNull;
41 
42 import com.android.systemui.util.leak.RotationUtils;
43 
44 /**
45  * Status bar view.
46  */
47 public class StatusBarWindowView extends FrameLayout {
48 
49     public static final String TAG = "PhoneStatusBarWindowView";
50     public static final boolean DEBUG = StatusBar.DEBUG;
51 
52     private int mLeftInset = 0;
53     private int mRightInset = 0;
54     private int mTopInset = 0;
55 
56     private float mTouchDownY = 0;
57 
StatusBarWindowView(Context context, AttributeSet attrs)58     public StatusBarWindowView(Context context, AttributeSet attrs) {
59         super(context, attrs);
60     }
61 
62     @Override
onApplyWindowInsets(WindowInsets windowInsets)63     public WindowInsets onApplyWindowInsets(WindowInsets windowInsets) {
64         final Insets insets = windowInsets.getInsetsIgnoringVisibility(systemBars());
65         mLeftInset = insets.left;
66         mRightInset = insets.right;
67         mTopInset = 0;
68         DisplayCutout displayCutout = getRootWindowInsets().getDisplayCutout();
69         if (displayCutout != null) {
70             mTopInset = displayCutout.getWaterfallInsets().top;
71         }
72         applyMargins();
73         return windowInsets;
74     }
75 
76     /**
77      * This is specifically for pulling down the status bar as a consistent motion in the visual
78      * immersive mode. In the visual immersive mode, after the system detects a system gesture
79      * motion from the top, we show permanent bars, and then forward the touch events from the
80      * focused window to the status bar window. However, since the first relayed event is out of
81      * bound of the status bar view, in order for the touch event to be correctly dispatched down,
82      * we jot down the position Y of the initial touch down event, offset it to 0 in the y-axis,
83      * and calculate the movement based on first touch down position.
84      */
85     @Override
dispatchTouchEvent(MotionEvent ev)86     public boolean dispatchTouchEvent(MotionEvent ev) {
87         if (ev.getAction() == ACTION_DOWN && ev.getRawY() > getHeight()) {
88             mTouchDownY = ev.getRawY();
89             ev.setLocation(ev.getRawX(), mTopInset);
90         } else if (ev.getAction() == ACTION_MOVE && mTouchDownY != 0) {
91             ev.setLocation(ev.getRawX(), mTopInset + ev.getRawY() - mTouchDownY);
92         } else if (ev.getAction() == ACTION_UP) {
93             mTouchDownY = 0;
94         }
95         return super.dispatchTouchEvent(ev);
96     }
97 
applyMargins()98     private void applyMargins() {
99         final int count = getChildCount();
100         for (int i = 0; i < count; i++) {
101             View child = getChildAt(i);
102             if (child.getLayoutParams() instanceof LayoutParams) {
103                 LayoutParams lp = (LayoutParams) child.getLayoutParams();
104                 if (lp.rightMargin != mRightInset || lp.leftMargin != mLeftInset
105                         || lp.topMargin != mTopInset) {
106                     lp.rightMargin = mRightInset;
107                     lp.leftMargin = mLeftInset;
108                     lp.topMargin = mTopInset;
109                     child.requestLayout();
110                 }
111             }
112         }
113     }
114 
115     /**
116      * Compute the padding needed for status bar related views, e.g., PhoneStatusBar,
117      * QuickStatusBarHeader and KeyguardStatusBarView).
118      *
119      * @param cutout
120      * @param cornerCutoutPadding
121      * @param roundedCornerContentPadding
122      * @return
123      */
124     @NonNull
paddingNeededForCutoutAndRoundedCorner( DisplayCutout cutout, Pair<Integer, Integer> cornerCutoutPadding, int roundedCornerContentPadding)125     public static Pair<Integer, Integer> paddingNeededForCutoutAndRoundedCorner(
126             DisplayCutout cutout, Pair<Integer, Integer> cornerCutoutPadding,
127             int roundedCornerContentPadding) {
128         if (cutout == null) {
129             return new Pair<>(roundedCornerContentPadding, roundedCornerContentPadding);
130         }
131 
132         // padding needed for corner cutout.
133         int leftCornerCutoutPadding = cutout.getSafeInsetLeft();
134         int rightCornerCutoutPadding = cutout.getSafeInsetRight();
135         if (cornerCutoutPadding != null) {
136             leftCornerCutoutPadding = Math.max(leftCornerCutoutPadding, cornerCutoutPadding.first);
137             rightCornerCutoutPadding = Math.max(rightCornerCutoutPadding,
138                     cornerCutoutPadding.second);
139         }
140 
141         return new Pair<>(
142                 Math.max(leftCornerCutoutPadding, roundedCornerContentPadding),
143                 Math.max(rightCornerCutoutPadding, roundedCornerContentPadding));
144     }
145 
146 
147     /**
148      * Compute the corner cutout margins in portrait mode
149      */
cornerCutoutMargins(DisplayCutout cutout, Display display)150     public static Pair<Integer, Integer> cornerCutoutMargins(DisplayCutout cutout,
151             Display display) {
152         return statusBarCornerCutoutMargins(cutout, display, RotationUtils.ROTATION_NONE, 0);
153     }
154 
155     /**
156      * Compute the corner cutout margins in the given orientation (exactRotation)
157      */
statusBarCornerCutoutMargins(DisplayCutout cutout, Display display, int exactRotation, int statusBarHeight)158     public static Pair<Integer, Integer> statusBarCornerCutoutMargins(DisplayCutout cutout,
159             Display display, int exactRotation, int statusBarHeight) {
160         if (cutout == null) {
161             return null;
162         }
163         Point size = new Point();
164         display.getRealSize(size);
165 
166         Rect bounds = new Rect();
167         switch (exactRotation) {
168             case RotationUtils.ROTATION_LANDSCAPE:
169                 boundsFromDirection(cutout, Gravity.LEFT, bounds);
170                 break;
171             case RotationUtils.ROTATION_SEASCAPE:
172                 boundsFromDirection(cutout, Gravity.RIGHT, bounds);
173                 break;
174             case RotationUtils.ROTATION_NONE:
175                 boundsFromDirection(cutout, Gravity.TOP, bounds);
176                 break;
177             case RotationUtils.ROTATION_UPSIDE_DOWN:
178                 // we assume the cutout is always on top in portrait mode
179                 return null;
180         }
181 
182         if (statusBarHeight >= 0 && bounds.top > statusBarHeight) {
183             return null;
184         }
185 
186         if (bounds.left <= 0) {
187             return new Pair<>(bounds.right, 0);
188         }
189 
190         if (bounds.right >= size.x) {
191             return new Pair<>(0, size.x - bounds.left);
192         }
193 
194         return null;
195     }
196 }
197