blob: b1463a3c53ea1d9da680b8c7a38a49a224b27e6f [file] [log] [blame]
Jason Monk16fbd9d2017-04-27 14:28:49 -04001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5 * except in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the
10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11 * KIND, either express or implied. See the License for the specific language governing
12 * permissions and limitations under the License.
13 */
14
15package com.android.systemui;
16
17import android.animation.Animator;
18import android.animation.AnimatorListenerAdapter;
19import android.animation.AnimatorSet;
20import android.animation.ObjectAnimator;
21import android.content.Context;
Jason Monkfd279662017-06-29 19:37:48 -040022import android.content.res.Configuration;
Jason Monk16fbd9d2017-04-27 14:28:49 -040023import android.provider.Settings;
24import android.util.AttributeSet;
25import android.view.Gravity;
26import android.view.View;
27import android.view.ViewGroup;
28import android.view.ViewOutlineProvider;
29import android.view.ViewTreeObserver;
Jason Monk16fbd9d2017-04-27 14:28:49 -040030import android.widget.LinearLayout;
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +080031
Jason Monk16fbd9d2017-04-27 14:28:49 -040032import com.android.systemui.tuner.TunerService;
33import com.android.systemui.tuner.TunerService.Tunable;
Jason Monkfd279662017-06-29 19:37:48 -040034import com.android.systemui.util.leak.RotationUtils;
35
Jason Monkfd279662017-06-29 19:37:48 -040036import static com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE;
37import static com.android.systemui.util.leak.RotationUtils.ROTATION_NONE;
38import static com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE;
Jason Monk16fbd9d2017-04-27 14:28:49 -040039
Wesley.CW Wangb44f2e52018-06-15 16:24:57 +080040public class HardwareUiLayout extends LinearLayout implements Tunable {
Jason Monk16fbd9d2017-04-27 14:28:49 -040041
42 private static final String EDGE_BLEED = "sysui_hwui_edge_bleed";
43 private static final String ROUNDED_DIVIDER = "sysui_hwui_rounded_divider";
44 private final int[] mTmp2 = new int[2];
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +080045 private View mList;
Wesley.CW Wangb44f2e52018-06-15 16:24:57 +080046 private View mSeparatedView;
Jason Monk16fbd9d2017-04-27 14:28:49 -040047 private int mOldHeight;
48 private boolean mAnimating;
49 private AnimatorSet mAnimation;
50 private View mDivision;
51 private boolean mHasOutsideTouch;
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +080052 private HardwareBgDrawable mListBackground;
53 private HardwareBgDrawable mSeparatedViewBackground;
Jason Monk16fbd9d2017-04-27 14:28:49 -040054 private Animator mAnimator;
55 private boolean mCollapse;
Wesley.CW Wangb44f2e52018-06-15 16:24:57 +080056 private boolean mHasSeparatedButton;
Jason Monk16fbd9d2017-04-27 14:28:49 -040057 private int mEndPoint;
58 private boolean mEdgeBleed;
59 private boolean mRoundedDivider;
Jason Monkfd279662017-06-29 19:37:48 -040060 private int mRotation = ROTATION_NONE;
Jason Monk16fbd9d2017-04-27 14:28:49 -040061 private boolean mRotatedBackground;
Julia Reynoldsf5e41822018-01-23 13:55:18 -050062 private boolean mSwapOrientation = true;
Jason Monk16fbd9d2017-04-27 14:28:49 -040063
64 public HardwareUiLayout(Context context, AttributeSet attrs) {
65 super(context, attrs);
66 updateSettings();
67 }
68
69 @Override
70 protected void onAttachedToWindow() {
71 super.onAttachedToWindow();
72 updateSettings();
73 Dependency.get(TunerService.class).addTunable(this, EDGE_BLEED, ROUNDED_DIVIDER);
74 getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsListener);
75 }
76
77 @Override
78 protected void onDetachedFromWindow() {
79 super.onDetachedFromWindow();
80 getViewTreeObserver().removeOnComputeInternalInsetsListener(mInsetsListener);
81 Dependency.get(TunerService.class).removeTunable(this);
82 }
83
84 @Override
85 public void onTuningChanged(String key, String newValue) {
86 updateSettings();
87 }
88
89 private void updateSettings() {
90 mEdgeBleed = Settings.Secure.getInt(getContext().getContentResolver(),
91 EDGE_BLEED, 0) != 0;
92 mRoundedDivider = Settings.Secure.getInt(getContext().getContentResolver(),
Alison Cichowlase1bdc392018-04-19 18:19:58 -040093 ROUNDED_DIVIDER, 0) != 0;
Jason Monk16fbd9d2017-04-27 14:28:49 -040094 updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding());
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +080095 mListBackground = new HardwareBgDrawable(mRoundedDivider, !mEdgeBleed, getContext());
96 mSeparatedViewBackground = new HardwareBgDrawable(mRoundedDivider, !mEdgeBleed,
97 getContext());
98 if (mList != null) {
99 mList.setBackground(mListBackground);
100 mSeparatedView.setBackground(mSeparatedViewBackground);
Jason Monk16fbd9d2017-04-27 14:28:49 -0400101 requestLayout();
102 }
103 }
104
105 private void updateEdgeMargin(int edge) {
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +0800106 if (mList != null) {
107 MarginLayoutParams params = (MarginLayoutParams) mList.getLayoutParams();
Jason Monkfd279662017-06-29 19:37:48 -0400108 if (mRotation == ROTATION_LANDSCAPE) {
Jason Monk16fbd9d2017-04-27 14:28:49 -0400109 params.topMargin = edge;
Jason Monkfd279662017-06-29 19:37:48 -0400110 } else if (mRotation == ROTATION_SEASCAPE) {
111 params.bottomMargin = edge;
Jason Monk16fbd9d2017-04-27 14:28:49 -0400112 } else {
113 params.rightMargin = edge;
114 }
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +0800115 mList.setLayoutParams(params);
Jason Monk16fbd9d2017-04-27 14:28:49 -0400116 }
Wesley.CW Wangb44f2e52018-06-15 16:24:57 +0800117
118 if (mSeparatedView != null) {
119 MarginLayoutParams params = (MarginLayoutParams) mSeparatedView.getLayoutParams();
120 if (mRotation == ROTATION_LANDSCAPE) {
121 params.topMargin = edge;
122 } else if (mRotation == ROTATION_SEASCAPE) {
123 params.bottomMargin = edge;
124 } else {
125 params.rightMargin = edge;
126 }
127 mSeparatedView.setLayoutParams(params);
128 }
Jason Monk16fbd9d2017-04-27 14:28:49 -0400129 }
130
131 private int getEdgePadding() {
132 return getContext().getResources().getDimensionPixelSize(R.dimen.edge_margin);
133 }
134
135 @Override
136 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
137 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +0800138 if (mList == null) {
Jason Monk16fbd9d2017-04-27 14:28:49 -0400139 if (getChildCount() != 0) {
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +0800140 mList = getChildAt(0);
141 mList.setBackground(mListBackground);
Wesley.CW Wangb44f2e52018-06-15 16:24:57 +0800142 mSeparatedView = getChildAt(1);
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +0800143 mSeparatedView.setBackground(mSeparatedViewBackground);
Jason Monk16fbd9d2017-04-27 14:28:49 -0400144 updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding());
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +0800145 mOldHeight = mList.getMeasuredHeight();
Jason Monkfd279662017-06-29 19:37:48 -0400146 updateRotation();
Jason Monk16fbd9d2017-04-27 14:28:49 -0400147 } else {
148 return;
149 }
150 }
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +0800151 int newHeight = mList.getMeasuredHeight();
Jason Monk16fbd9d2017-04-27 14:28:49 -0400152 if (newHeight != mOldHeight) {
153 animateChild(mOldHeight, newHeight);
154 }
Wesley.CW Wangb429e172018-09-27 20:41:31 +0800155
156 post(() -> updatePaddingAndGravityIfTooTall());
Jason Monk16fbd9d2017-04-27 14:28:49 -0400157 post(() -> updatePosition());
Jason Monkfd279662017-06-29 19:37:48 -0400158 }
159
160 @Override
161 protected void onConfigurationChanged(Configuration newConfig) {
162 super.onConfigurationChanged(newConfig);
163 updateRotation();
164 }
165
Julia Reynoldsf5e41822018-01-23 13:55:18 -0500166 public void setSwapOrientation(boolean swapOrientation) {
167 mSwapOrientation = swapOrientation;
168 }
169
Jason Monkfd279662017-06-29 19:37:48 -0400170 private void updateRotation() {
171 int rotation = RotationUtils.getRotation(getContext());
172 if (rotation != mRotation) {
173 rotate(mRotation, rotation);
174 mRotation = rotation;
175 }
176 }
177
178 private void rotate(int from, int to) {
179 if (from != ROTATION_NONE && to != ROTATION_NONE) {
180 // Rather than handling this confusing case, just do 2 rotations.
181 rotate(from, ROTATION_NONE);
182 rotate(ROTATION_NONE, to);
183 return;
184 }
185 if (from == ROTATION_LANDSCAPE || to == ROTATION_SEASCAPE) {
186 rotateRight();
187 } else {
188 rotateLeft();
189 }
Wesley.CW Wangb44f2e52018-06-15 16:24:57 +0800190 if (mHasSeparatedButton) {
191 if (from == ROTATION_SEASCAPE || to == ROTATION_SEASCAPE) {
192 // Separated view has top margin, so seascape separated view need special rotation,
193 // not a full left or right rotation.
194 swapLeftAndTop(mSeparatedView);
195 } else if (from == ROTATION_LANDSCAPE) {
196 rotateRight(mSeparatedView);
197 } else {
198 rotateLeft(mSeparatedView);
199 }
200 }
Jason Monkfd279662017-06-29 19:37:48 -0400201 if (to != ROTATION_NONE) {
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +0800202 if (mList instanceof LinearLayout) {
Jason Monkfd279662017-06-29 19:37:48 -0400203 mRotatedBackground = true;
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +0800204 mListBackground.setRotatedBackground(true);
205 mSeparatedViewBackground.setRotatedBackground(true);
206 LinearLayout linearLayout = (LinearLayout) mList;
Julia Reynoldsf5e41822018-01-23 13:55:18 -0500207 if (mSwapOrientation) {
208 linearLayout.setOrientation(LinearLayout.HORIZONTAL);
Wesley.CW Wangb44f2e52018-06-15 16:24:57 +0800209 setOrientation(LinearLayout.HORIZONTAL);
Julia Reynoldsf5e41822018-01-23 13:55:18 -0500210 }
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +0800211 swapDimens(mList);
Wesley.CW Wangb44f2e52018-06-15 16:24:57 +0800212 swapDimens(mSeparatedView);
Jason Monkfd279662017-06-29 19:37:48 -0400213 }
214 } else {
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +0800215 if (mList instanceof LinearLayout) {
Jason Monkfd279662017-06-29 19:37:48 -0400216 mRotatedBackground = false;
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +0800217 mListBackground.setRotatedBackground(false);
218 mSeparatedViewBackground.setRotatedBackground(false);
219 LinearLayout linearLayout = (LinearLayout) mList;
Julia Reynoldsf5e41822018-01-23 13:55:18 -0500220 if (mSwapOrientation) {
221 linearLayout.setOrientation(LinearLayout.VERTICAL);
Wesley.CW Wangb44f2e52018-06-15 16:24:57 +0800222 setOrientation(LinearLayout.VERTICAL);
Julia Reynoldsf5e41822018-01-23 13:55:18 -0500223 }
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +0800224 swapDimens(mList);
Wesley.CW Wangb44f2e52018-06-15 16:24:57 +0800225 swapDimens(mSeparatedView);
Jason Monk16fbd9d2017-04-27 14:28:49 -0400226 }
227 }
228 }
229
Jason Monkfd279662017-06-29 19:37:48 -0400230 private void rotateRight() {
Jason Monk16fbd9d2017-04-27 14:28:49 -0400231 rotateRight(this);
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +0800232 rotateRight(mList);
Jason Monk16fbd9d2017-04-27 14:28:49 -0400233 swapDimens(this);
234
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +0800235 LayoutParams p = (LayoutParams) mList.getLayoutParams();
Jason Monk16fbd9d2017-04-27 14:28:49 -0400236 p.gravity = rotateGravityRight(p.gravity);
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +0800237 mList.setLayoutParams(p);
Wesley.CW Wangb44f2e52018-06-15 16:24:57 +0800238
239 LayoutParams separatedViewLayoutParams = (LayoutParams) mSeparatedView.getLayoutParams();
240 separatedViewLayoutParams.gravity = rotateGravityRight(separatedViewLayoutParams.gravity);
241 mSeparatedView.setLayoutParams(separatedViewLayoutParams);
242
Wesley.CW Wangb429e172018-09-27 20:41:31 +0800243 setGravity(rotateGravityRight(getGravity()));
Jason Monk16fbd9d2017-04-27 14:28:49 -0400244 }
245
246 private void swapDimens(View v) {
247 ViewGroup.LayoutParams params = v.getLayoutParams();
248 int h = params.width;
249 params.width = params.height;
250 params.height = h;
251 v.setLayoutParams(params);
252 }
253
254 private int rotateGravityRight(int gravity) {
255 int retGravity = 0;
256 int layoutDirection = getLayoutDirection();
257 final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
258 final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
259
260 switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
261 case Gravity.CENTER_HORIZONTAL:
262 retGravity |= Gravity.CENTER_VERTICAL;
263 break;
264 case Gravity.RIGHT:
265 retGravity |= Gravity.BOTTOM;
266 break;
267 case Gravity.LEFT:
268 default:
269 retGravity |= Gravity.TOP;
270 break;
271 }
272
273 switch (verticalGravity) {
274 case Gravity.CENTER_VERTICAL:
275 retGravity |= Gravity.CENTER_HORIZONTAL;
276 break;
277 case Gravity.BOTTOM:
278 retGravity |= Gravity.LEFT;
279 break;
280 case Gravity.TOP:
281 default:
282 retGravity |= Gravity.RIGHT;
283 break;
284 }
285 return retGravity;
286 }
287
Jason Monkfd279662017-06-29 19:37:48 -0400288 private void rotateLeft() {
Jason Monk16fbd9d2017-04-27 14:28:49 -0400289 rotateLeft(this);
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +0800290 rotateLeft(mList);
Jason Monk16fbd9d2017-04-27 14:28:49 -0400291 swapDimens(this);
292
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +0800293 LayoutParams p = (LayoutParams) mList.getLayoutParams();
Jason Monk16fbd9d2017-04-27 14:28:49 -0400294 p.gravity = rotateGravityLeft(p.gravity);
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +0800295 mList.setLayoutParams(p);
Wesley.CW Wangb44f2e52018-06-15 16:24:57 +0800296
297 LayoutParams separatedViewLayoutParams = (LayoutParams) mSeparatedView.getLayoutParams();
298 separatedViewLayoutParams.gravity = rotateGravityLeft(separatedViewLayoutParams.gravity);
299 mSeparatedView.setLayoutParams(separatedViewLayoutParams);
300
Wesley.CW Wangb429e172018-09-27 20:41:31 +0800301 setGravity(rotateGravityLeft(getGravity()));
Jason Monk16fbd9d2017-04-27 14:28:49 -0400302 }
303
304 private int rotateGravityLeft(int gravity) {
305 if (gravity == -1) {
306 gravity = Gravity.TOP | Gravity.START;
307 }
308 int retGravity = 0;
309 int layoutDirection = getLayoutDirection();
310 final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
311 final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
312
313 switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
314 case Gravity.CENTER_HORIZONTAL:
315 retGravity |= Gravity.CENTER_VERTICAL;
316 break;
317 case Gravity.RIGHT:
318 retGravity |= Gravity.TOP;
319 break;
320 case Gravity.LEFT:
321 default:
322 retGravity |= Gravity.BOTTOM;
323 break;
324 }
325
326 switch (verticalGravity) {
327 case Gravity.CENTER_VERTICAL:
328 retGravity |= Gravity.CENTER_HORIZONTAL;
329 break;
330 case Gravity.BOTTOM:
331 retGravity |= Gravity.RIGHT;
332 break;
333 case Gravity.TOP:
334 default:
335 retGravity |= Gravity.LEFT;
336 break;
337 }
338 return retGravity;
339 }
340
341 private void rotateLeft(View v) {
342 v.setPadding(v.getPaddingTop(), v.getPaddingRight(), v.getPaddingBottom(),
343 v.getPaddingLeft());
344 MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams();
345 params.setMargins(params.topMargin, params.rightMargin, params.bottomMargin,
346 params.leftMargin);
347 v.setLayoutParams(params);
348 }
349
350 private void rotateRight(View v) {
351 v.setPadding(v.getPaddingBottom(), v.getPaddingLeft(), v.getPaddingTop(),
352 v.getPaddingRight());
353 MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams();
354 params.setMargins(params.bottomMargin, params.leftMargin, params.topMargin,
355 params.rightMargin);
356 v.setLayoutParams(params);
357 }
358
Wesley.CW Wangb44f2e52018-06-15 16:24:57 +0800359 private void swapLeftAndTop(View v) {
360 v.setPadding(v.getPaddingTop(), v.getPaddingLeft(), v.getPaddingBottom(),
361 v.getPaddingRight());
362 MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams();
363 params.setMargins(params.topMargin, params.leftMargin, params.bottomMargin,
364 params.rightMargin);
365 v.setLayoutParams(params);
366 }
367
Jason Monk16fbd9d2017-04-27 14:28:49 -0400368 @Override
369 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
370 super.onLayout(changed, left, top, right, bottom);
371 post(() -> updatePosition());
372 }
373
374 private void animateChild(int oldHeight, int newHeight) {
375 if (true) return;
376 if (mAnimating) {
377 mAnimation.cancel();
378 }
379 mAnimating = true;
380 mAnimation = new AnimatorSet();
381 mAnimation.addListener(new AnimatorListenerAdapter() {
382 @Override
383 public void onAnimationEnd(Animator animation) {
384 mAnimating = false;
385 }
386 });
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +0800387 int fromTop = mList.getTop();
388 int fromBottom = mList.getBottom();
Jason Monk16fbd9d2017-04-27 14:28:49 -0400389 int toTop = fromTop - ((newHeight - oldHeight) / 2);
390 int toBottom = fromBottom + ((newHeight - oldHeight) / 2);
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +0800391 ObjectAnimator top = ObjectAnimator.ofInt(mList, "top", fromTop, toTop);
392 top.addUpdateListener(animation -> mListBackground.invalidateSelf());
Jason Monk16fbd9d2017-04-27 14:28:49 -0400393 mAnimation.playTogether(top,
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +0800394 ObjectAnimator.ofInt(mList, "bottom", fromBottom, toBottom));
Jason Monk16fbd9d2017-04-27 14:28:49 -0400395 }
396
397 public void setDivisionView(View v) {
398 mDivision = v;
399 if (mDivision != null) {
400 mDivision.addOnLayoutChangeListener(
401 (v1, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
402 updatePosition());
403 }
404 updatePosition();
405 }
406
407 private void updatePosition() {
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +0800408 if (mList == null) return;
Wesley.CW Wangb44f2e52018-06-15 16:24:57 +0800409 // If got separated button, setRotatedBackground to false,
410 // all items won't get white background.
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +0800411 mListBackground.setRotatedBackground(mHasSeparatedButton);
412 mSeparatedViewBackground.setRotatedBackground(mHasSeparatedButton);
Jason Monk16fbd9d2017-04-27 14:28:49 -0400413 if (mDivision != null && mDivision.getVisibility() == VISIBLE) {
414 int index = mRotatedBackground ? 0 : 1;
415 mDivision.getLocationOnScreen(mTmp2);
416 float trans = mRotatedBackground ? mDivision.getTranslationX()
417 : mDivision.getTranslationY();
418 int viewTop = (int) (mTmp2[index] + trans);
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +0800419 mList.getLocationOnScreen(mTmp2);
Jason Monk16fbd9d2017-04-27 14:28:49 -0400420 viewTop -= mTmp2[index];
421 setCutPoint(viewTop);
422 } else {
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +0800423 setCutPoint(mList.getMeasuredHeight());
Jason Monk16fbd9d2017-04-27 14:28:49 -0400424 }
425 }
426
427 private void setCutPoint(int point) {
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +0800428 int curPoint = mListBackground.getCutPoint();
Jason Monk16fbd9d2017-04-27 14:28:49 -0400429 if (curPoint == point) return;
430 if (getAlpha() == 0 || curPoint == 0) {
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +0800431 mListBackground.setCutPoint(point);
Jason Monk16fbd9d2017-04-27 14:28:49 -0400432 return;
433 }
434 if (mAnimator != null) {
435 if (mEndPoint == point) {
436 return;
437 }
438 mAnimator.cancel();
439 }
440 mEndPoint = point;
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +0800441 mAnimator = ObjectAnimator.ofInt(mListBackground, "cutPoint", curPoint, point);
Jason Monk16fbd9d2017-04-27 14:28:49 -0400442 if (mCollapse) {
443 mAnimator.setStartDelay(300);
444 mCollapse = false;
445 }
446 mAnimator.start();
447 }
448
Wesley.CW Wangb429e172018-09-27 20:41:31 +0800449 // If current power menu height larger then screen height, remove padding to break power menu
450 // alignment and set menu center vertical within the screen.
451 private void updatePaddingAndGravityIfTooTall() {
452 int defaultTopPadding;
453 int viewsTotalHeight;
454 int separatedViewTopMargin;
455 int screenHeight;
456 int totalHeight;
457 int targetGravity;
458 MarginLayoutParams params = (MarginLayoutParams) mSeparatedView.getLayoutParams();
459 switch (RotationUtils.getRotation(getContext())) {
460 case RotationUtils.ROTATION_LANDSCAPE:
461 defaultTopPadding = getPaddingLeft();
462 viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth();
463 separatedViewTopMargin = mHasSeparatedButton ? params.leftMargin : 0;
464 screenHeight = getMeasuredWidth();
465 targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.TOP;
466 break;
467 case RotationUtils.ROTATION_SEASCAPE:
468 defaultTopPadding = getPaddingRight();
469 viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth();
470 separatedViewTopMargin = mHasSeparatedButton ? params.leftMargin : 0;
471 screenHeight = getMeasuredWidth();
472 targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.BOTTOM;
473 break;
474 default: // Portrait
475 defaultTopPadding = getPaddingTop();
476 viewsTotalHeight = mList.getMeasuredHeight() + mSeparatedView.getMeasuredHeight();
477 separatedViewTopMargin = mHasSeparatedButton ? params.topMargin : 0;
478 screenHeight = getMeasuredHeight();
479 targetGravity = Gravity.CENTER_VERTICAL|Gravity.RIGHT;
480 break;
481 }
482 totalHeight = defaultTopPadding + viewsTotalHeight + separatedViewTopMargin;
483 if (totalHeight >= screenHeight) {
484 setPadding(0, 0, 0, 0);
485 setGravity(targetGravity);
486 }
487 }
488
Jason Monk16fbd9d2017-04-27 14:28:49 -0400489 @Override
490 public ViewOutlineProvider getOutlineProvider() {
491 return super.getOutlineProvider();
492 }
493
494 public void setOutsideTouchListener(OnClickListener onClickListener) {
495 mHasOutsideTouch = true;
496 requestLayout();
497 setOnClickListener(onClickListener);
498 setClickable(true);
499 setFocusable(true);
500 }
501
502 public void setCollapse() {
503 mCollapse = true;
504 }
505
Wesley.CW Wangb44f2e52018-06-15 16:24:57 +0800506 public void setHasSeparatedButton(boolean hasSeparatedButton) {
507 mHasSeparatedButton = hasSeparatedButton;
508 }
509
Jason Monk16fbd9d2017-04-27 14:28:49 -0400510 public static HardwareUiLayout get(View v) {
511 if (v instanceof HardwareUiLayout) return (HardwareUiLayout) v;
512 if (v.getParent() instanceof View) {
513 return get((View) v.getParent());
514 }
515 return null;
516 }
517
518 private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsListener = inoutInfo -> {
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +0800519 if (mHasOutsideTouch || (mList == null)) {
Jason Monk16fbd9d2017-04-27 14:28:49 -0400520 inoutInfo.setTouchableInsets(
521 ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
522 return;
523 }
524 inoutInfo.setTouchableInsets(
525 ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT);
Wesley.CW Wang3b0aa462018-07-04 17:35:00 +0800526 inoutInfo.contentInsets.set(mList.getLeft(), mList.getTop(),
527 0, getBottom() - mList.getBottom());
Jason Monk16fbd9d2017-04-27 14:28:49 -0400528 };
529}