blob: b1812125535343023b1db253870df7cb325b0b26 [file] [log] [blame]
Kenny Root15a4d2f2010-03-11 18:20:12 -08001/*
2 * Copyright (C) 2008 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
Joe Onoratofd52b182010-11-10 18:00:52 -080017package com.android.systemui.statusbar.phone;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080018
Evan Laird058c8ae2018-01-12 14:26:10 -050019import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
20
21import android.annotation.Nullable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.content.Context;
Evan Laird058c8ae2018-01-12 14:26:10 -050023import android.content.res.Configuration;
24import android.graphics.Rect;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.util.AttributeSet;
Chris Wren64161cc2012-12-17 16:49:30 -050026import android.util.EventLog;
Evan Laird058c8ae2018-01-12 14:26:10 -050027import android.view.DisplayCutout;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.view.MotionEvent;
29import android.view.View;
Selim Cinek3e7592d2016-04-11 09:35:54 +080030import android.view.ViewGroup;
Svetoslav Ganov6179ea32011-06-28 01:12:41 -070031import android.view.accessibility.AccessibilityEvent;
Chris Wren64161cc2012-12-17 16:49:30 -050032
Evan Laird058c8ae2018-01-12 14:26:10 -050033import android.widget.FrameLayout;
34import android.widget.LinearLayout;
Jason Monkaa573e92017-01-27 17:00:29 -050035import com.android.systemui.Dependency;
Chris Wren64161cc2012-12-17 16:49:30 -050036import com.android.systemui.EventLogTags;
Selim Cinek3e7592d2016-04-11 09:35:54 +080037import com.android.systemui.R;
Jason Monkaa573e92017-01-27 17:00:29 -050038import com.android.systemui.statusbar.policy.DarkIconDispatcher;
39import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
Evan Laird058c8ae2018-01-12 14:26:10 -050040import com.android.systemui.util.leak.RotationUtils;
Joe Onorato79de0c52010-05-26 17:03:26 -040041
Daniel Sandler08d05e32012-08-08 16:39:54 -040042public class PhoneStatusBarView extends PanelBar {
Joe Onoratofd52b182010-11-10 18:00:52 -080043 private static final String TAG = "PhoneStatusBarView";
Jason Monk2a6ea9c2017-01-26 11:14:51 -050044 private static final boolean DEBUG = StatusBar.DEBUG;
Christoph Studer934025e2014-11-25 12:53:55 +010045 private static final boolean DEBUG_GESTURES = false;
Evan Laird058c8ae2018-01-12 14:26:10 -050046 private static final int NO_VALUE = Integer.MIN_VALUE;
Daniel Sandler198a0302012-08-17 16:04:31 -040047
Jason Monk2a6ea9c2017-01-26 11:14:51 -050048 StatusBar mBar;
Daniel Sandler5a8aefa2012-09-25 01:21:12 -040049
Xiaohui Chen9f967112016-01-07 14:14:06 -080050 boolean mIsFullyOpenedPanel = false;
John Spurlock7edfbca2013-09-14 11:58:55 -040051 private final PhoneStatusBarTransitions mBarTransitions;
Jorim Jaggiecc798e2014-05-26 18:14:37 +020052 private ScrimController mScrimController;
Selim Cinek3d395c62015-06-16 19:37:37 -070053 private float mMinFraction;
54 private float mPanelFraction;
Selim Cinek80c2abe2015-06-17 15:37:30 -070055 private Runnable mHideExpandedRunnable = new Runnable() {
56 @Override
57 public void run() {
Selim Cinek529c5322016-04-06 20:03:45 -070058 if (mPanelFraction == 0.0f) {
59 mBar.makeExpandedInvisible();
60 }
Selim Cinek80c2abe2015-06-17 15:37:30 -070061 }
62 };
Jason Monkaa573e92017-01-27 17:00:29 -050063 private DarkReceiver mBattery;
Evan Laird058c8ae2018-01-12 14:26:10 -050064 private int mLastOrientation;
Evan Lairdcda685d2018-01-22 18:25:17 -050065 @Nullable
Evan Laird058c8ae2018-01-12 14:26:10 -050066 private View mCutoutSpace;
67 @Nullable
68 private DisplayCutout mDisplayCutout;
Joe Onorato119a4012010-06-30 14:49:51 -040069
Joe Onoratofd52b182010-11-10 18:00:52 -080070 public PhoneStatusBarView(Context context, AttributeSet attrs) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071 super(context, attrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072
John Spurlock7edfbca2013-09-14 11:58:55 -040073 mBarTransitions = new PhoneStatusBarTransitions(this);
John Spurlocke932e302013-08-12 10:16:29 -040074 }
75
76 public BarTransitions getBarTransitions() {
77 return mBarTransitions;
Daniel Sandler1c1edaa2012-08-14 11:14:45 -040078 }
79
Jason Monk2a6ea9c2017-01-26 11:14:51 -050080 public void setBar(StatusBar bar) {
Daniel Sandlerefb0faf2012-10-10 14:15:34 -070081 mBar = bar;
82 }
83
Jorim Jaggiecc798e2014-05-26 18:14:37 +020084 public void setScrimController(ScrimController scrimController) {
85 mScrimController = scrimController;
86 }
87
Daniel Sandlerefb0faf2012-10-10 14:15:34 -070088 @Override
Jorim Jaggiacea1002014-05-10 01:30:10 +020089 public void onFinishInflate() {
John Spurlocke6f0a712013-09-03 16:23:49 -040090 mBarTransitions.init();
Alan Viverette51efddb2017-04-05 10:00:01 -040091 mBattery = findViewById(R.id.battery);
Evan Laird058c8ae2018-01-12 14:26:10 -050092 mCutoutSpace = findViewById(R.id.cutout_space_view);
Jason Monkaa573e92017-01-27 17:00:29 -050093 }
94
95 @Override
96 protected void onAttachedToWindow() {
97 super.onAttachedToWindow();
98 // Always have Battery meters in the status bar observe the dark/light modes.
99 Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mBattery);
Evan Laird058c8ae2018-01-12 14:26:10 -0500100 if (updateOrientationAndCutout(getResources().getConfiguration().orientation)) {
101 postUpdateLayoutForCutout();
102 }
Jason Monkaa573e92017-01-27 17:00:29 -0500103 }
104
105 @Override
106 protected void onDetachedFromWindow() {
107 super.onDetachedFromWindow();
108 Dependency.get(DarkIconDispatcher.class).removeDarkReceiver(mBattery);
Evan Laird058c8ae2018-01-12 14:26:10 -0500109 mDisplayCutout = null;
110 }
111
112 @Override
113 protected void onConfigurationChanged(Configuration newConfig) {
114 super.onConfigurationChanged(newConfig);
115
116 // May trigger cutout space layout-ing
117 if (updateOrientationAndCutout(newConfig.orientation)) {
118 postUpdateLayoutForCutout();
119 }
120 }
121
122 /**
123 *
124 * @param newOrientation may pass NO_VALUE for no change
125 * @return boolean indicating if we need to update the cutout location / margins
126 */
127 private boolean updateOrientationAndCutout(int newOrientation) {
128 boolean changed = false;
129 if (newOrientation != NO_VALUE) {
130 if (mLastOrientation != newOrientation) {
131 changed = true;
132 mLastOrientation = newOrientation;
133 }
134 }
135
136 if (mDisplayCutout == null) {
137 DisplayCutout cutout = getRootWindowInsets().getDisplayCutout();
138 if (cutout != null) {
139 changed = true;
140 mDisplayCutout = cutout;
141 }
142 }
143
144 return changed;
Daniel Sandlerefb0faf2012-10-10 14:15:34 -0700145 }
146
Daniel Sandler1c1edaa2012-08-14 11:14:45 -0400147 @Override
Xiaohui Chen9f967112016-01-07 14:14:06 -0800148 public boolean panelEnabled() {
John Spurlock97642182013-07-29 17:58:39 -0400149 return mBar.panelsEnabled();
Daniel Sandler1e8feef2012-08-16 11:37:41 -0400150 }
151
152 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -0800153 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
Alan Viverette5b046752015-01-08 11:13:06 -0800154 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Svetoslav Ganov6179ea32011-06-28 01:12:41 -0700155 // The status bar is very small so augment the view that the user is touching
156 // with the content of the status bar a whole. This way an accessibility service
157 // may announce the current item as well as the entire content if appropriate.
158 AccessibilityEvent record = AccessibilityEvent.obtain();
159 onInitializeAccessibilityEvent(record);
160 dispatchPopulateAccessibilityEvent(record);
161 event.appendRecord(record);
162 return true;
163 }
164 return false;
165 }
Daniel Sandler08d05e32012-08-08 16:39:54 -0400166
167 @Override
168 public void onPanelPeeked() {
169 super.onPanelPeeked();
Jorim Jaggifa505a72014-04-28 20:04:11 +0200170 mBar.makeExpandedVisible(false);
Daniel Sandler67eab792012-10-02 17:08:23 -0400171 }
172
173 @Override
Xiaohui Chen9f967112016-01-07 14:14:06 -0800174 public void onPanelCollapsed() {
175 super.onPanelCollapsed();
Jorim Jaggi2580a9762014-06-25 03:08:25 +0200176 // Close the status bar in the next frame so we can show the end of the animation.
Jorim Jaggi45e2d8f2017-05-16 14:23:19 +0200177 post(mHideExpandedRunnable);
Xiaohui Chen9f967112016-01-07 14:14:06 -0800178 mIsFullyOpenedPanel = false;
Daniel Sandler8e72c9e2012-08-15 00:09:26 -0400179 }
180
Selim Cinek80c2abe2015-06-17 15:37:30 -0700181 public void removePendingHideExpandedRunnables() {
Jorim Jaggi45e2d8f2017-05-16 14:23:19 +0200182 removeCallbacks(mHideExpandedRunnable);
Selim Cinek80c2abe2015-06-17 15:37:30 -0700183 }
184
Daniel Sandler8e72c9e2012-08-15 00:09:26 -0400185 @Override
Xiaohui Chen9f967112016-01-07 14:14:06 -0800186 public void onPanelFullyOpened() {
187 super.onPanelFullyOpened();
188 if (!mIsFullyOpenedPanel) {
189 mPanel.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700190 }
Xiaohui Chen9f967112016-01-07 14:14:06 -0800191 mIsFullyOpenedPanel = true;
Daniel Sandler08d05e32012-08-08 16:39:54 -0400192 }
193
194 @Override
195 public boolean onTouchEvent(MotionEvent event) {
Chris Wren64161cc2012-12-17 16:49:30 -0500196 boolean barConsumedEvent = mBar.interceptTouchEvent(event);
197
198 if (DEBUG_GESTURES) {
199 if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
200 EventLog.writeEvent(EventLogTags.SYSUI_PANELBAR_TOUCH,
201 event.getActionMasked(), (int) event.getX(), (int) event.getY(),
202 barConsumedEvent ? 1 : 0);
203 }
204 }
205
206 return barConsumedEvent || super.onTouchEvent(event);
Daniel Sandler08d05e32012-08-08 16:39:54 -0400207 }
208
209 @Override
Xiaohui Chen9f967112016-01-07 14:14:06 -0800210 public void onTrackingStarted() {
211 super.onTrackingStarted();
Jorim Jaggie70d31f2014-04-24 22:08:30 +0200212 mBar.onTrackingStarted();
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200213 mScrimController.onTrackingStarted();
Selim Cinek529c5322016-04-06 20:03:45 -0700214 removePendingHideExpandedRunnables();
Jorim Jaggie70d31f2014-04-24 22:08:30 +0200215 }
216
217 @Override
Selim Cinekdbbcfbe2014-10-24 17:52:35 +0200218 public void onClosingFinished() {
219 super.onClosingFinished();
220 mBar.onClosingFinished();
221 }
222
223 @Override
Xiaohui Chen9f967112016-01-07 14:14:06 -0800224 public void onTrackingStopped(boolean expand) {
225 super.onTrackingStopped(expand);
Jorim Jaggi2fbad7b2014-05-26 22:38:00 +0200226 mBar.onTrackingStopped(expand);
227 }
228
229 @Override
230 public void onExpandingFinished() {
231 super.onExpandingFinished();
232 mScrimController.onExpandingFinished();
Jorim Jaggie70d31f2014-04-24 22:08:30 +0200233 }
234
235 @Override
Daniel Sandler08d05e32012-08-08 16:39:54 -0400236 public boolean onInterceptTouchEvent(MotionEvent event) {
237 return mBar.interceptTouchEvent(event) || super.onInterceptTouchEvent(event);
238 }
239
240 @Override
Selim Cinek3d395c62015-06-16 19:37:37 -0700241 public void panelScrimMinFractionChanged(float minFraction) {
242 if (mMinFraction != minFraction) {
243 mMinFraction = minFraction;
244 updateScrimFraction();
245 }
246 }
247
248 @Override
Xiaohui Chen9f967112016-01-07 14:14:06 -0800249 public void panelExpansionChanged(float frac, boolean expanded) {
250 super.panelExpansionChanged(frac, expanded);
Selim Cinek3d395c62015-06-16 19:37:37 -0700251 mPanelFraction = frac;
252 updateScrimFraction();
253 }
254
255 private void updateScrimFraction() {
Selim Cinekae76b4c2017-03-07 16:49:43 -0800256 float scrimFraction = mPanelFraction;
257 if (mMinFraction < 1.0f) {
258 scrimFraction = Math.max((mPanelFraction - mMinFraction) / (1.0f - mMinFraction),
259 0);
260 }
Selim Cinek3d395c62015-06-16 19:37:37 -0700261 mScrimController.setPanelExpansion(scrimFraction);
Daniel Sandler08d05e32012-08-08 16:39:54 -0400262 }
Selim Cinek3e7592d2016-04-11 09:35:54 +0800263
264 public void onDensityOrFontScaleChanged() {
265 ViewGroup.LayoutParams layoutParams = getLayoutParams();
266 layoutParams.height = getResources().getDimensionPixelSize(
267 R.dimen.status_bar_height);
268 setLayoutParams(layoutParams);
269 }
Evan Laird058c8ae2018-01-12 14:26:10 -0500270
271 private void updateLayoutForCutout() {
272 updateCutoutLocation();
273 updateSafeInsets();
274 }
275
276 private void postUpdateLayoutForCutout() {
277 Runnable r = new Runnable() {
278 @Override
279 public void run() {
280 updateLayoutForCutout();
281 }
282 };
283 // Let the cutout emulation draw first
284 postDelayed(r, 0);
285 }
286
287 private void updateCutoutLocation() {
Evan Lairdcda685d2018-01-22 18:25:17 -0500288 // Not all layouts have a cutout (e.g., Car)
289 if (mCutoutSpace == null) {
290 return;
291 }
292
Evan Laird058c8ae2018-01-12 14:26:10 -0500293 if (mDisplayCutout == null || mDisplayCutout.isEmpty()
294 || mLastOrientation != ORIENTATION_PORTRAIT) {
295 mCutoutSpace.setVisibility(View.GONE);
296 return;
297 }
298
299 mCutoutSpace.setVisibility(View.VISIBLE);
300 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mCutoutSpace.getLayoutParams();
301 lp.width = mDisplayCutout.getBoundingRect().width();
302 lp.height = mDisplayCutout.getBoundingRect().height();
303 }
304
305 private void updateSafeInsets() {
306 // Depending on our rotation, we may have to work around a cutout in the middle of the view,
307 // or letterboxing from the right or left sides.
308
309 FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
310 if (mDisplayCutout == null || mDisplayCutout.isEmpty()) {
311 lp.leftMargin = 0;
312 lp.rightMargin = 0;
313 return;
314 }
315
316 int leftMargin = 0;
317 int rightMargin = 0;
318 switch (RotationUtils.getRotation(getContext())) {
319 /*
320 * Landscape: <-|
321 * Seascape: |->
322 */
323 case RotationUtils.ROTATION_LANDSCAPE:
324 leftMargin = getDisplayCutoutHeight();
325 break;
326 case RotationUtils.ROTATION_SEASCAPE:
327 rightMargin = getDisplayCutoutHeight();
328 break;
329 default:
330 break;
331 }
332
333 lp.leftMargin = leftMargin;
334 lp.rightMargin = rightMargin;
335 }
336
337 //TODO: Find a better way
338 private int getDisplayCutoutHeight() {
339 if (mDisplayCutout == null || mDisplayCutout.isEmpty()) {
340 return 0;
341 }
342
343 Rect r = mDisplayCutout.getBoundingRect();
344 return r.bottom - r.top;
345 }
Svetoslav Ganov6179ea32011-06-28 01:12:41 -0700346}