blob: 0fd0a05e98ab6255f9e007dacdaacbac51f2e944 [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
Adrian Roos6a4fa0e2018-03-05 19:50:16 +010021import static com.android.systemui.ScreenDecorations.DisplayCutoutView.boundsFromDirection;
22
Evan Laird058c8ae2018-01-12 14:26:10 -050023import android.annotation.Nullable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024import android.content.Context;
Evan Laird058c8ae2018-01-12 14:26:10 -050025import android.content.res.Configuration;
Adrian Roos13836052018-03-15 21:06:37 +010026import android.graphics.Point;
Evan Laird058c8ae2018-01-12 14:26:10 -050027import android.graphics.Rect;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.util.AttributeSet;
Chris Wren64161cc2012-12-17 16:49:30 -050029import android.util.EventLog;
Adrian Roos13836052018-03-15 21:06:37 +010030import android.util.Pair;
31import android.view.Display;
Evan Laird058c8ae2018-01-12 14:26:10 -050032import android.view.DisplayCutout;
Adrian Roos6a4fa0e2018-03-05 19:50:16 +010033import android.view.Gravity;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.view.MotionEvent;
35import android.view.View;
Selim Cinek3e7592d2016-04-11 09:35:54 +080036import android.view.ViewGroup;
Adrian Roosedfab3b2018-03-08 18:39:20 +010037import android.view.WindowInsets;
Svetoslav Ganov6179ea32011-06-28 01:12:41 -070038import android.view.accessibility.AccessibilityEvent;
Evan Laird058c8ae2018-01-12 14:26:10 -050039import android.widget.FrameLayout;
40import android.widget.LinearLayout;
Adrian Roos13836052018-03-15 21:06:37 +010041
Jason Monkaa573e92017-01-27 17:00:29 -050042import com.android.systemui.Dependency;
Chris Wren64161cc2012-12-17 16:49:30 -050043import com.android.systemui.EventLogTags;
Selim Cinek3e7592d2016-04-11 09:35:54 +080044import com.android.systemui.R;
Jason Monkaa573e92017-01-27 17:00:29 -050045import com.android.systemui.statusbar.policy.DarkIconDispatcher;
46import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
Adrian Roosedfab3b2018-03-08 18:39:20 +010047
48import java.util.Objects;
Joe Onorato79de0c52010-05-26 17:03:26 -040049
Daniel Sandler08d05e32012-08-08 16:39:54 -040050public class PhoneStatusBarView extends PanelBar {
Joe Onoratofd52b182010-11-10 18:00:52 -080051 private static final String TAG = "PhoneStatusBarView";
Jason Monk2a6ea9c2017-01-26 11:14:51 -050052 private static final boolean DEBUG = StatusBar.DEBUG;
Christoph Studer934025e2014-11-25 12:53:55 +010053 private static final boolean DEBUG_GESTURES = false;
Evan Laird058c8ae2018-01-12 14:26:10 -050054 private static final int NO_VALUE = Integer.MIN_VALUE;
Daniel Sandler198a0302012-08-17 16:04:31 -040055
Jason Monk2a6ea9c2017-01-26 11:14:51 -050056 StatusBar mBar;
Daniel Sandler5a8aefa2012-09-25 01:21:12 -040057
Xiaohui Chen9f967112016-01-07 14:14:06 -080058 boolean mIsFullyOpenedPanel = false;
John Spurlock7edfbca2013-09-14 11:58:55 -040059 private final PhoneStatusBarTransitions mBarTransitions;
Jorim Jaggiecc798e2014-05-26 18:14:37 +020060 private ScrimController mScrimController;
Selim Cinek3d395c62015-06-16 19:37:37 -070061 private float mMinFraction;
62 private float mPanelFraction;
Selim Cinek80c2abe2015-06-17 15:37:30 -070063 private Runnable mHideExpandedRunnable = new Runnable() {
64 @Override
65 public void run() {
Selim Cinek529c5322016-04-06 20:03:45 -070066 if (mPanelFraction == 0.0f) {
67 mBar.makeExpandedInvisible();
68 }
Selim Cinek80c2abe2015-06-17 15:37:30 -070069 }
70 };
Jason Monkaa573e92017-01-27 17:00:29 -050071 private DarkReceiver mBattery;
Evan Laird058c8ae2018-01-12 14:26:10 -050072 private int mLastOrientation;
Evan Lairdcda685d2018-01-22 18:25:17 -050073 @Nullable
Evan Laird058c8ae2018-01-12 14:26:10 -050074 private View mCutoutSpace;
75 @Nullable
76 private DisplayCutout mDisplayCutout;
Joe Onorato119a4012010-06-30 14:49:51 -040077
Joe Onoratofd52b182010-11-10 18:00:52 -080078 public PhoneStatusBarView(Context context, AttributeSet attrs) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079 super(context, attrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080
John Spurlock7edfbca2013-09-14 11:58:55 -040081 mBarTransitions = new PhoneStatusBarTransitions(this);
John Spurlocke932e302013-08-12 10:16:29 -040082 }
83
84 public BarTransitions getBarTransitions() {
85 return mBarTransitions;
Daniel Sandler1c1edaa2012-08-14 11:14:45 -040086 }
87
Jason Monk2a6ea9c2017-01-26 11:14:51 -050088 public void setBar(StatusBar bar) {
Daniel Sandlerefb0faf2012-10-10 14:15:34 -070089 mBar = bar;
90 }
91
Jorim Jaggiecc798e2014-05-26 18:14:37 +020092 public void setScrimController(ScrimController scrimController) {
93 mScrimController = scrimController;
94 }
95
Daniel Sandlerefb0faf2012-10-10 14:15:34 -070096 @Override
Jorim Jaggiacea1002014-05-10 01:30:10 +020097 public void onFinishInflate() {
John Spurlocke6f0a712013-09-03 16:23:49 -040098 mBarTransitions.init();
Alan Viverette51efddb2017-04-05 10:00:01 -040099 mBattery = findViewById(R.id.battery);
Evan Laird058c8ae2018-01-12 14:26:10 -0500100 mCutoutSpace = findViewById(R.id.cutout_space_view);
Jason Monkaa573e92017-01-27 17:00:29 -0500101 }
102
103 @Override
104 protected void onAttachedToWindow() {
105 super.onAttachedToWindow();
106 // Always have Battery meters in the status bar observe the dark/light modes.
107 Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mBattery);
Evan Laird058c8ae2018-01-12 14:26:10 -0500108 if (updateOrientationAndCutout(getResources().getConfiguration().orientation)) {
Adrian Roosedfab3b2018-03-08 18:39:20 +0100109 updateLayoutForCutout();
Evan Laird058c8ae2018-01-12 14:26:10 -0500110 }
Jason Monkaa573e92017-01-27 17:00:29 -0500111 }
112
113 @Override
114 protected void onDetachedFromWindow() {
115 super.onDetachedFromWindow();
116 Dependency.get(DarkIconDispatcher.class).removeDarkReceiver(mBattery);
Evan Laird058c8ae2018-01-12 14:26:10 -0500117 mDisplayCutout = null;
118 }
119
120 @Override
121 protected void onConfigurationChanged(Configuration newConfig) {
122 super.onConfigurationChanged(newConfig);
123
124 // May trigger cutout space layout-ing
125 if (updateOrientationAndCutout(newConfig.orientation)) {
Adrian Roosedfab3b2018-03-08 18:39:20 +0100126 updateLayoutForCutout();
127 requestLayout();
Evan Laird058c8ae2018-01-12 14:26:10 -0500128 }
129 }
130
Adrian Roosedfab3b2018-03-08 18:39:20 +0100131 @Override
132 public WindowInsets onApplyWindowInsets(WindowInsets insets) {
133 if (updateOrientationAndCutout(mLastOrientation)) {
134 updateLayoutForCutout();
135 requestLayout();
136 }
137 return super.onApplyWindowInsets(insets);
138 }
139
Evan Laird058c8ae2018-01-12 14:26:10 -0500140 /**
141 *
142 * @param newOrientation may pass NO_VALUE for no change
143 * @return boolean indicating if we need to update the cutout location / margins
144 */
145 private boolean updateOrientationAndCutout(int newOrientation) {
146 boolean changed = false;
147 if (newOrientation != NO_VALUE) {
148 if (mLastOrientation != newOrientation) {
149 changed = true;
150 mLastOrientation = newOrientation;
151 }
152 }
153
Adrian Roosedfab3b2018-03-08 18:39:20 +0100154 if (!Objects.equals(getRootWindowInsets().getDisplayCutout(), mDisplayCutout)) {
155 changed = true;
156 mDisplayCutout = getRootWindowInsets().getDisplayCutout();
Evan Laird058c8ae2018-01-12 14:26:10 -0500157 }
158
159 return changed;
Daniel Sandlerefb0faf2012-10-10 14:15:34 -0700160 }
161
Daniel Sandler1c1edaa2012-08-14 11:14:45 -0400162 @Override
Xiaohui Chen9f967112016-01-07 14:14:06 -0800163 public boolean panelEnabled() {
John Spurlock97642182013-07-29 17:58:39 -0400164 return mBar.panelsEnabled();
Daniel Sandler1e8feef2012-08-16 11:37:41 -0400165 }
166
167 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -0800168 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
Alan Viverette5b046752015-01-08 11:13:06 -0800169 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Svetoslav Ganov6179ea32011-06-28 01:12:41 -0700170 // The status bar is very small so augment the view that the user is touching
171 // with the content of the status bar a whole. This way an accessibility service
172 // may announce the current item as well as the entire content if appropriate.
173 AccessibilityEvent record = AccessibilityEvent.obtain();
174 onInitializeAccessibilityEvent(record);
175 dispatchPopulateAccessibilityEvent(record);
176 event.appendRecord(record);
177 return true;
178 }
179 return false;
180 }
Daniel Sandler08d05e32012-08-08 16:39:54 -0400181
182 @Override
183 public void onPanelPeeked() {
184 super.onPanelPeeked();
Jorim Jaggifa505a72014-04-28 20:04:11 +0200185 mBar.makeExpandedVisible(false);
Daniel Sandler67eab792012-10-02 17:08:23 -0400186 }
187
188 @Override
Xiaohui Chen9f967112016-01-07 14:14:06 -0800189 public void onPanelCollapsed() {
190 super.onPanelCollapsed();
Jorim Jaggi2580a9762014-06-25 03:08:25 +0200191 // Close the status bar in the next frame so we can show the end of the animation.
Jorim Jaggi45e2d8f2017-05-16 14:23:19 +0200192 post(mHideExpandedRunnable);
Xiaohui Chen9f967112016-01-07 14:14:06 -0800193 mIsFullyOpenedPanel = false;
Daniel Sandler8e72c9e2012-08-15 00:09:26 -0400194 }
195
Selim Cinek80c2abe2015-06-17 15:37:30 -0700196 public void removePendingHideExpandedRunnables() {
Jorim Jaggi45e2d8f2017-05-16 14:23:19 +0200197 removeCallbacks(mHideExpandedRunnable);
Selim Cinek80c2abe2015-06-17 15:37:30 -0700198 }
199
Daniel Sandler8e72c9e2012-08-15 00:09:26 -0400200 @Override
Xiaohui Chen9f967112016-01-07 14:14:06 -0800201 public void onPanelFullyOpened() {
202 super.onPanelFullyOpened();
203 if (!mIsFullyOpenedPanel) {
204 mPanel.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700205 }
Xiaohui Chen9f967112016-01-07 14:14:06 -0800206 mIsFullyOpenedPanel = true;
Daniel Sandler08d05e32012-08-08 16:39:54 -0400207 }
208
209 @Override
210 public boolean onTouchEvent(MotionEvent event) {
Chris Wren64161cc2012-12-17 16:49:30 -0500211 boolean barConsumedEvent = mBar.interceptTouchEvent(event);
212
213 if (DEBUG_GESTURES) {
214 if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
215 EventLog.writeEvent(EventLogTags.SYSUI_PANELBAR_TOUCH,
216 event.getActionMasked(), (int) event.getX(), (int) event.getY(),
217 barConsumedEvent ? 1 : 0);
218 }
219 }
220
221 return barConsumedEvent || super.onTouchEvent(event);
Daniel Sandler08d05e32012-08-08 16:39:54 -0400222 }
223
224 @Override
Xiaohui Chen9f967112016-01-07 14:14:06 -0800225 public void onTrackingStarted() {
226 super.onTrackingStarted();
Jorim Jaggie70d31f2014-04-24 22:08:30 +0200227 mBar.onTrackingStarted();
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200228 mScrimController.onTrackingStarted();
Selim Cinek529c5322016-04-06 20:03:45 -0700229 removePendingHideExpandedRunnables();
Jorim Jaggie70d31f2014-04-24 22:08:30 +0200230 }
231
232 @Override
Selim Cinekdbbcfbe2014-10-24 17:52:35 +0200233 public void onClosingFinished() {
234 super.onClosingFinished();
235 mBar.onClosingFinished();
236 }
237
238 @Override
Xiaohui Chen9f967112016-01-07 14:14:06 -0800239 public void onTrackingStopped(boolean expand) {
240 super.onTrackingStopped(expand);
Jorim Jaggi2fbad7b2014-05-26 22:38:00 +0200241 mBar.onTrackingStopped(expand);
242 }
243
244 @Override
245 public void onExpandingFinished() {
246 super.onExpandingFinished();
247 mScrimController.onExpandingFinished();
Jorim Jaggie70d31f2014-04-24 22:08:30 +0200248 }
249
250 @Override
Daniel Sandler08d05e32012-08-08 16:39:54 -0400251 public boolean onInterceptTouchEvent(MotionEvent event) {
252 return mBar.interceptTouchEvent(event) || super.onInterceptTouchEvent(event);
253 }
254
255 @Override
Selim Cinek3d395c62015-06-16 19:37:37 -0700256 public void panelScrimMinFractionChanged(float minFraction) {
257 if (mMinFraction != minFraction) {
258 mMinFraction = minFraction;
259 updateScrimFraction();
260 }
261 }
262
263 @Override
Xiaohui Chen9f967112016-01-07 14:14:06 -0800264 public void panelExpansionChanged(float frac, boolean expanded) {
265 super.panelExpansionChanged(frac, expanded);
Selim Cinek3d395c62015-06-16 19:37:37 -0700266 mPanelFraction = frac;
267 updateScrimFraction();
Matthew Ng78f88d12018-01-23 12:39:55 -0800268 if ((frac == 0 || frac == 1) && mBar.getNavigationBarView() != null) {
269 mBar.getNavigationBarView().onPanelExpandedChange(expanded);
270 }
Selim Cinek3d395c62015-06-16 19:37:37 -0700271 }
272
273 private void updateScrimFraction() {
Selim Cinekae76b4c2017-03-07 16:49:43 -0800274 float scrimFraction = mPanelFraction;
275 if (mMinFraction < 1.0f) {
276 scrimFraction = Math.max((mPanelFraction - mMinFraction) / (1.0f - mMinFraction),
277 0);
278 }
Selim Cinek3d395c62015-06-16 19:37:37 -0700279 mScrimController.setPanelExpansion(scrimFraction);
Daniel Sandler08d05e32012-08-08 16:39:54 -0400280 }
Selim Cinek3e7592d2016-04-11 09:35:54 +0800281
Adrian Roos22af6502018-02-22 16:57:08 +0100282 public void updateResources() {
Selim Cinek3e7592d2016-04-11 09:35:54 +0800283 ViewGroup.LayoutParams layoutParams = getLayoutParams();
284 layoutParams.height = getResources().getDimensionPixelSize(
285 R.dimen.status_bar_height);
286 setLayoutParams(layoutParams);
287 }
Evan Laird058c8ae2018-01-12 14:26:10 -0500288
289 private void updateLayoutForCutout() {
Adrian Roos13836052018-03-15 21:06:37 +0100290 Pair<Integer, Integer> cornerCutoutMargins = cornerCutoutMargins(mDisplayCutout,
291 getDisplay());
292 updateCutoutLocation(cornerCutoutMargins);
293 updateSafeInsets(cornerCutoutMargins);
Evan Laird058c8ae2018-01-12 14:26:10 -0500294 }
295
Adrian Roos13836052018-03-15 21:06:37 +0100296 private void updateCutoutLocation(Pair<Integer, Integer> cornerCutoutMargins) {
Evan Lairdcda685d2018-01-22 18:25:17 -0500297 // Not all layouts have a cutout (e.g., Car)
298 if (mCutoutSpace == null) {
299 return;
300 }
301
Evan Laird058c8ae2018-01-12 14:26:10 -0500302 if (mDisplayCutout == null || mDisplayCutout.isEmpty()
Adrian Roos13836052018-03-15 21:06:37 +0100303 || mLastOrientation != ORIENTATION_PORTRAIT || cornerCutoutMargins != null) {
Evan Laird058c8ae2018-01-12 14:26:10 -0500304 mCutoutSpace.setVisibility(View.GONE);
305 return;
306 }
307
308 mCutoutSpace.setVisibility(View.VISIBLE);
309 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mCutoutSpace.getLayoutParams();
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100310
311 Rect bounds = new Rect();
312 boundsFromDirection(mDisplayCutout, Gravity.TOP, bounds);
313
314 lp.width = bounds.width();
315 lp.height = bounds.height();
Evan Laird058c8ae2018-01-12 14:26:10 -0500316 }
317
Adrian Roos13836052018-03-15 21:06:37 +0100318 private void updateSafeInsets(Pair<Integer, Integer> cornerCutoutMargins) {
Evan Laird058c8ae2018-01-12 14:26:10 -0500319 // Depending on our rotation, we may have to work around a cutout in the middle of the view,
320 // or letterboxing from the right or left sides.
321
322 FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
Adrian Roosedfab3b2018-03-08 18:39:20 +0100323 if (mDisplayCutout == null) {
Evan Laird058c8ae2018-01-12 14:26:10 -0500324 lp.leftMargin = 0;
325 lp.rightMargin = 0;
326 return;
327 }
328
Adrian Roosedfab3b2018-03-08 18:39:20 +0100329 lp.leftMargin = mDisplayCutout.getSafeInsetLeft();
330 lp.rightMargin = mDisplayCutout.getSafeInsetRight();
Adrian Roos13836052018-03-15 21:06:37 +0100331
332 if (cornerCutoutMargins != null) {
333 lp.leftMargin = Math.max(lp.leftMargin, cornerCutoutMargins.first);
334 lp.rightMargin = Math.max(lp.rightMargin, cornerCutoutMargins.second);
335 }
336 }
337
338 public static Pair<Integer, Integer> cornerCutoutMargins(DisplayCutout cutout,
339 Display display) {
340 if (cutout == null) {
341 return null;
342 }
343 Point size = new Point();
344 display.getRealSize(size);
345
346 Rect bounds = new Rect();
347 boundsFromDirection(cutout, Gravity.TOP, bounds);
348
349 if (bounds.left <= 0) {
350 return new Pair<>(bounds.right, 0);
351 }
352 if (bounds.right >= size.x) {
353 return new Pair<>(0, size.x - bounds.left);
354 }
355 return null;
Evan Laird058c8ae2018-01-12 14:26:10 -0500356 }
Svetoslav Ganov6179ea32011-06-28 01:12:41 -0700357}