blob: 5086c997613adb5131ed5433d5907abbe2391d89 [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
Gus Prevasab336792018-11-14 13:52:20 -050017import static com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE;
18import static com.android.systemui.util.leak.RotationUtils.ROTATION_NONE;
19import static com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE;
20
Jason Monk16fbd9d2017-04-27 14:28:49 -040021import android.animation.Animator;
22import android.animation.AnimatorListenerAdapter;
23import android.animation.AnimatorSet;
24import android.animation.ObjectAnimator;
25import android.content.Context;
26import android.provider.Settings;
27import android.util.AttributeSet;
28import android.view.Gravity;
29import android.view.View;
30import android.view.ViewGroup;
31import android.view.ViewOutlineProvider;
32import android.view.ViewTreeObserver;
Jason Monk16fbd9d2017-04-27 14:28:49 -040033import android.widget.LinearLayout;
Wesley.CW Wang42feebe2018-07-04 17:35:00 +080034
Aaron Heuckroth57d60d22019-03-05 14:00:12 -050035import com.android.systemui.globalactions.GlobalActionsDialog;
Jason Monk16fbd9d2017-04-27 14:28:49 -040036import com.android.systemui.tuner.TunerService;
37import com.android.systemui.tuner.TunerService.Tunable;
Jason Monkfd279662017-06-29 19:37:48 -040038import com.android.systemui.util.leak.RotationUtils;
39
Aaron Heuckroth57d60d22019-03-05 14:00:12 -050040import java.util.ArrayList;
41
Aaron Heuckrothf708d472019-01-10 16:54:51 -050042/**
43 * Layout for placing two containers at a specific physical position on the device, relative to the
44 * device's hardware, regardless of screen rotation.
45 */
46public class HardwareUiLayout extends MultiListLayout implements Tunable {
Jason Monk16fbd9d2017-04-27 14:28:49 -040047
48 private static final String EDGE_BLEED = "sysui_hwui_edge_bleed";
49 private static final String ROUNDED_DIVIDER = "sysui_hwui_rounded_divider";
50 private final int[] mTmp2 = new int[2];
Aaron Heuckrothf708d472019-01-10 16:54:51 -050051 private ViewGroup mList;
52 private ViewGroup mSeparatedView;
Jason Monk16fbd9d2017-04-27 14:28:49 -040053 private int mOldHeight;
54 private boolean mAnimating;
55 private AnimatorSet mAnimation;
56 private View mDivision;
Wesley.CW Wang42feebe2018-07-04 17:35:00 +080057 private HardwareBgDrawable mListBackground;
58 private HardwareBgDrawable mSeparatedViewBackground;
Jason Monk16fbd9d2017-04-27 14:28:49 -040059 private Animator mAnimator;
60 private boolean mCollapse;
61 private int mEndPoint;
62 private boolean mEdgeBleed;
63 private boolean mRoundedDivider;
Jason Monk16fbd9d2017-04-27 14:28:49 -040064 private boolean mRotatedBackground;
Julia Reynoldsf5e41822018-01-23 13:55:18 -050065 private boolean mSwapOrientation = true;
Jason Monk16fbd9d2017-04-27 14:28:49 -040066
67 public HardwareUiLayout(Context context, AttributeSet attrs) {
68 super(context, attrs);
Aaron Heuckrothd0053342019-02-26 14:30:40 -050069 // Manually re-initialize mRotation to portrait-mode, since this view must always
70 // be constructed in portrait mode and rotated into the correct initial position.
71 mRotation = ROTATION_NONE;
Jason Monk16fbd9d2017-04-27 14:28:49 -040072 updateSettings();
73 }
74
75 @Override
Aaron Heuckrothf708d472019-01-10 16:54:51 -050076 protected ViewGroup getSeparatedView() {
77 return findViewById(com.android.systemui.R.id.separated_button);
78 }
79
80 @Override
81 protected ViewGroup getListView() {
82 return findViewById(android.R.id.list);
83 }
84
85 @Override
86 public void removeAllItems() {
87 if (mList != null) {
88 mList.removeAllViews();
89 }
90 if (mSeparatedView != null) {
91 mSeparatedView.removeAllViews();
92 }
93 }
94
95 @Override
Jason Monk16fbd9d2017-04-27 14:28:49 -040096 protected void onAttachedToWindow() {
97 super.onAttachedToWindow();
98 updateSettings();
99 Dependency.get(TunerService.class).addTunable(this, EDGE_BLEED, ROUNDED_DIVIDER);
100 getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsListener);
101 }
102
103 @Override
104 protected void onDetachedFromWindow() {
105 super.onDetachedFromWindow();
106 getViewTreeObserver().removeOnComputeInternalInsetsListener(mInsetsListener);
107 Dependency.get(TunerService.class).removeTunable(this);
108 }
109
110 @Override
111 public void onTuningChanged(String key, String newValue) {
112 updateSettings();
113 }
114
115 private void updateSettings() {
116 mEdgeBleed = Settings.Secure.getInt(getContext().getContentResolver(),
117 EDGE_BLEED, 0) != 0;
118 mRoundedDivider = Settings.Secure.getInt(getContext().getContentResolver(),
Alison Cichowlase1bdc392018-04-19 18:19:58 -0400119 ROUNDED_DIVIDER, 0) != 0;
Jason Monk16fbd9d2017-04-27 14:28:49 -0400120 updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding());
Wesley.CW Wang42feebe2018-07-04 17:35:00 +0800121 mListBackground = new HardwareBgDrawable(mRoundedDivider, !mEdgeBleed, getContext());
122 mSeparatedViewBackground = new HardwareBgDrawable(mRoundedDivider, !mEdgeBleed,
123 getContext());
124 if (mList != null) {
125 mList.setBackground(mListBackground);
126 mSeparatedView.setBackground(mSeparatedViewBackground);
Jason Monk16fbd9d2017-04-27 14:28:49 -0400127 requestLayout();
128 }
129 }
130
131 private void updateEdgeMargin(int edge) {
Wesley.CW Wang42feebe2018-07-04 17:35:00 +0800132 if (mList != null) {
133 MarginLayoutParams params = (MarginLayoutParams) mList.getLayoutParams();
Jason Monkfd279662017-06-29 19:37:48 -0400134 if (mRotation == ROTATION_LANDSCAPE) {
Jason Monk16fbd9d2017-04-27 14:28:49 -0400135 params.topMargin = edge;
Jason Monkfd279662017-06-29 19:37:48 -0400136 } else if (mRotation == ROTATION_SEASCAPE) {
137 params.bottomMargin = edge;
Jason Monk16fbd9d2017-04-27 14:28:49 -0400138 } else {
139 params.rightMargin = edge;
140 }
Wesley.CW Wang42feebe2018-07-04 17:35:00 +0800141 mList.setLayoutParams(params);
Jason Monk16fbd9d2017-04-27 14:28:49 -0400142 }
Wesley.CW Wang3004fcb2018-06-15 16:24:57 +0800143
144 if (mSeparatedView != null) {
145 MarginLayoutParams params = (MarginLayoutParams) mSeparatedView.getLayoutParams();
146 if (mRotation == ROTATION_LANDSCAPE) {
147 params.topMargin = edge;
148 } else if (mRotation == ROTATION_SEASCAPE) {
149 params.bottomMargin = edge;
150 } else {
151 params.rightMargin = edge;
152 }
153 mSeparatedView.setLayoutParams(params);
154 }
Jason Monk16fbd9d2017-04-27 14:28:49 -0400155 }
156
157 private int getEdgePadding() {
158 return getContext().getResources().getDimensionPixelSize(R.dimen.edge_margin);
159 }
160
161 @Override
162 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
163 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Wesley.CW Wang42feebe2018-07-04 17:35:00 +0800164 if (mList == null) {
Jason Monk16fbd9d2017-04-27 14:28:49 -0400165 if (getChildCount() != 0) {
Aaron Heuckrothf708d472019-01-10 16:54:51 -0500166 mList = getListView();
Wesley.CW Wang42feebe2018-07-04 17:35:00 +0800167 mList.setBackground(mListBackground);
Aaron Heuckrothf708d472019-01-10 16:54:51 -0500168 mSeparatedView = getSeparatedView();
Wesley.CW Wang42feebe2018-07-04 17:35:00 +0800169 mSeparatedView.setBackground(mSeparatedViewBackground);
Jason Monk16fbd9d2017-04-27 14:28:49 -0400170 updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding());
Wesley.CW Wang42feebe2018-07-04 17:35:00 +0800171 mOldHeight = mList.getMeasuredHeight();
Aaron Heuckrothd0053342019-02-26 14:30:40 -0500172
173 // Must be called to initialize view rotation correctly.
174 // Requires LayoutParams, hence why this isn't called during the constructor.
175 updateRotation();
Jason Monk16fbd9d2017-04-27 14:28:49 -0400176 } else {
177 return;
178 }
179 }
Wesley.CW Wang42feebe2018-07-04 17:35:00 +0800180 int newHeight = mList.getMeasuredHeight();
Jason Monk16fbd9d2017-04-27 14:28:49 -0400181 if (newHeight != mOldHeight) {
182 animateChild(mOldHeight, newHeight);
183 }
Wesley.CW Wang1096c622018-09-27 20:41:31 +0800184
185 post(() -> updatePaddingAndGravityIfTooTall());
Jason Monk16fbd9d2017-04-27 14:28:49 -0400186 post(() -> updatePosition());
Jason Monkfd279662017-06-29 19:37:48 -0400187 }
188
Julia Reynoldsf5e41822018-01-23 13:55:18 -0500189 public void setSwapOrientation(boolean swapOrientation) {
190 mSwapOrientation = swapOrientation;
191 }
192
Aaron Heuckrothd0053342019-02-26 14:30:40 -0500193 private void updateRotation() {
194 int rotation = RotationUtils.getRotation(getContext());
195 if (rotation != mRotation) {
196 rotate(mRotation, rotation);
197 mRotation = rotation;
198 }
199 }
200
201 /**
202 * Requires LayoutParams to be set to work correctly, and therefore must be run after after
203 * the HardwareUILayout has been added to the view hierarchy.
204 */
Aaron Heuckroth75e249f2019-02-01 15:59:57 -0500205 protected void rotate(int from, int to) {
206 super.rotate(from, to);
Jason Monkfd279662017-06-29 19:37:48 -0400207 if (from != ROTATION_NONE && to != ROTATION_NONE) {
208 // Rather than handling this confusing case, just do 2 rotations.
209 rotate(from, ROTATION_NONE);
210 rotate(ROTATION_NONE, to);
211 return;
212 }
213 if (from == ROTATION_LANDSCAPE || to == ROTATION_SEASCAPE) {
214 rotateRight();
215 } else {
216 rotateLeft();
217 }
Aaron Heuckroth57d60d22019-03-05 14:00:12 -0500218 if (mSeparated) {
Wesley.CW Wang3004fcb2018-06-15 16:24:57 +0800219 if (from == ROTATION_SEASCAPE || to == ROTATION_SEASCAPE) {
220 // Separated view has top margin, so seascape separated view need special rotation,
221 // not a full left or right rotation.
222 swapLeftAndTop(mSeparatedView);
223 } else if (from == ROTATION_LANDSCAPE) {
224 rotateRight(mSeparatedView);
225 } else {
226 rotateLeft(mSeparatedView);
227 }
228 }
Jason Monkfd279662017-06-29 19:37:48 -0400229 if (to != ROTATION_NONE) {
Wesley.CW Wang42feebe2018-07-04 17:35:00 +0800230 if (mList instanceof LinearLayout) {
Jason Monkfd279662017-06-29 19:37:48 -0400231 mRotatedBackground = true;
Wesley.CW Wang42feebe2018-07-04 17:35:00 +0800232 mListBackground.setRotatedBackground(true);
233 mSeparatedViewBackground.setRotatedBackground(true);
234 LinearLayout linearLayout = (LinearLayout) mList;
Julia Reynoldsf5e41822018-01-23 13:55:18 -0500235 if (mSwapOrientation) {
236 linearLayout.setOrientation(LinearLayout.HORIZONTAL);
Wesley.CW Wang3004fcb2018-06-15 16:24:57 +0800237 setOrientation(LinearLayout.HORIZONTAL);
Julia Reynoldsf5e41822018-01-23 13:55:18 -0500238 }
Wesley.CW Wang42feebe2018-07-04 17:35:00 +0800239 swapDimens(mList);
Wesley.CW Wang3004fcb2018-06-15 16:24:57 +0800240 swapDimens(mSeparatedView);
Jason Monkfd279662017-06-29 19:37:48 -0400241 }
242 } else {
Wesley.CW Wang42feebe2018-07-04 17:35:00 +0800243 if (mList instanceof LinearLayout) {
Jason Monkfd279662017-06-29 19:37:48 -0400244 mRotatedBackground = false;
Wesley.CW Wang42feebe2018-07-04 17:35:00 +0800245 mListBackground.setRotatedBackground(false);
246 mSeparatedViewBackground.setRotatedBackground(false);
247 LinearLayout linearLayout = (LinearLayout) mList;
Julia Reynoldsf5e41822018-01-23 13:55:18 -0500248 if (mSwapOrientation) {
249 linearLayout.setOrientation(LinearLayout.VERTICAL);
Wesley.CW Wang3004fcb2018-06-15 16:24:57 +0800250 setOrientation(LinearLayout.VERTICAL);
Julia Reynoldsf5e41822018-01-23 13:55:18 -0500251 }
Wesley.CW Wang42feebe2018-07-04 17:35:00 +0800252 swapDimens(mList);
Wesley.CW Wang3004fcb2018-06-15 16:24:57 +0800253 swapDimens(mSeparatedView);
Jason Monk16fbd9d2017-04-27 14:28:49 -0400254 }
255 }
256 }
257
Aaron Heuckroth57d60d22019-03-05 14:00:12 -0500258 @Override
259 public void onUpdateList() {
260 removeAllItems();
261 ArrayList<GlobalActionsDialog.Action> separatedActions =
262 mAdapter.getSeparatedItems(mSeparated);
263 ArrayList<GlobalActionsDialog.Action> listActions = mAdapter.getListItems(mSeparated);
264
265 for (int i = 0; i < mAdapter.getCount(); i++) {
266 Object action = mAdapter.getItem(i);
267 int separatedIndex = separatedActions.indexOf(action);
268 ViewGroup parent;
269 if (separatedIndex != -1) {
270 parent = getSeparatedView();
271 } else {
272 int listIndex = listActions.indexOf(action);
273 parent = getListView();
274 }
275 View v = mAdapter.getView(i, null, parent);
276 final int pos = i;
277 v.setOnClickListener(view -> mAdapter.onClickItem(pos));
278 v.setOnLongClickListener(view -> mAdapter.onLongClickItem(pos));
279 parent.addView(v);
280 }
281 }
282
Jason Monkfd279662017-06-29 19:37:48 -0400283 private void rotateRight() {
Jason Monk16fbd9d2017-04-27 14:28:49 -0400284 rotateRight(this);
Wesley.CW Wang42feebe2018-07-04 17:35:00 +0800285 rotateRight(mList);
Jason Monk16fbd9d2017-04-27 14:28:49 -0400286 swapDimens(this);
287
Wesley.CW Wang42feebe2018-07-04 17:35:00 +0800288 LayoutParams p = (LayoutParams) mList.getLayoutParams();
Jason Monk16fbd9d2017-04-27 14:28:49 -0400289 p.gravity = rotateGravityRight(p.gravity);
Wesley.CW Wang42feebe2018-07-04 17:35:00 +0800290 mList.setLayoutParams(p);
Wesley.CW Wang3004fcb2018-06-15 16:24:57 +0800291
292 LayoutParams separatedViewLayoutParams = (LayoutParams) mSeparatedView.getLayoutParams();
293 separatedViewLayoutParams.gravity = rotateGravityRight(separatedViewLayoutParams.gravity);
294 mSeparatedView.setLayoutParams(separatedViewLayoutParams);
295
Wesley.CW Wang1096c622018-09-27 20:41:31 +0800296 setGravity(rotateGravityRight(getGravity()));
Jason Monk16fbd9d2017-04-27 14:28:49 -0400297 }
298
299 private void swapDimens(View v) {
300 ViewGroup.LayoutParams params = v.getLayoutParams();
301 int h = params.width;
302 params.width = params.height;
303 params.height = h;
304 v.setLayoutParams(params);
305 }
306
307 private int rotateGravityRight(int gravity) {
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.BOTTOM;
319 break;
320 case Gravity.LEFT:
321 default:
322 retGravity |= Gravity.TOP;
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.LEFT;
332 break;
333 case Gravity.TOP:
334 default:
335 retGravity |= Gravity.RIGHT;
336 break;
337 }
338 return retGravity;
339 }
340
Jason Monkfd279662017-06-29 19:37:48 -0400341 private void rotateLeft() {
Jason Monk16fbd9d2017-04-27 14:28:49 -0400342 rotateLeft(this);
Wesley.CW Wang42feebe2018-07-04 17:35:00 +0800343 rotateLeft(mList);
Jason Monk16fbd9d2017-04-27 14:28:49 -0400344 swapDimens(this);
345
Wesley.CW Wang42feebe2018-07-04 17:35:00 +0800346 LayoutParams p = (LayoutParams) mList.getLayoutParams();
Jason Monk16fbd9d2017-04-27 14:28:49 -0400347 p.gravity = rotateGravityLeft(p.gravity);
Wesley.CW Wang42feebe2018-07-04 17:35:00 +0800348 mList.setLayoutParams(p);
Wesley.CW Wang3004fcb2018-06-15 16:24:57 +0800349
350 LayoutParams separatedViewLayoutParams = (LayoutParams) mSeparatedView.getLayoutParams();
351 separatedViewLayoutParams.gravity = rotateGravityLeft(separatedViewLayoutParams.gravity);
352 mSeparatedView.setLayoutParams(separatedViewLayoutParams);
353
Wesley.CW Wang1096c622018-09-27 20:41:31 +0800354 setGravity(rotateGravityLeft(getGravity()));
Jason Monk16fbd9d2017-04-27 14:28:49 -0400355 }
356
357 private int rotateGravityLeft(int gravity) {
358 if (gravity == -1) {
359 gravity = Gravity.TOP | Gravity.START;
360 }
361 int retGravity = 0;
362 int layoutDirection = getLayoutDirection();
363 final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
364 final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
365
366 switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
367 case Gravity.CENTER_HORIZONTAL:
368 retGravity |= Gravity.CENTER_VERTICAL;
369 break;
370 case Gravity.RIGHT:
371 retGravity |= Gravity.TOP;
372 break;
373 case Gravity.LEFT:
374 default:
375 retGravity |= Gravity.BOTTOM;
376 break;
377 }
378
379 switch (verticalGravity) {
380 case Gravity.CENTER_VERTICAL:
381 retGravity |= Gravity.CENTER_HORIZONTAL;
382 break;
383 case Gravity.BOTTOM:
384 retGravity |= Gravity.RIGHT;
385 break;
386 case Gravity.TOP:
387 default:
388 retGravity |= Gravity.LEFT;
389 break;
390 }
391 return retGravity;
392 }
393
394 private void rotateLeft(View v) {
395 v.setPadding(v.getPaddingTop(), v.getPaddingRight(), v.getPaddingBottom(),
396 v.getPaddingLeft());
397 MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams();
398 params.setMargins(params.topMargin, params.rightMargin, params.bottomMargin,
399 params.leftMargin);
400 v.setLayoutParams(params);
401 }
402
403 private void rotateRight(View v) {
404 v.setPadding(v.getPaddingBottom(), v.getPaddingLeft(), v.getPaddingTop(),
405 v.getPaddingRight());
406 MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams();
407 params.setMargins(params.bottomMargin, params.leftMargin, params.topMargin,
408 params.rightMargin);
409 v.setLayoutParams(params);
410 }
411
Wesley.CW Wang3004fcb2018-06-15 16:24:57 +0800412 private void swapLeftAndTop(View v) {
413 v.setPadding(v.getPaddingTop(), v.getPaddingLeft(), v.getPaddingBottom(),
414 v.getPaddingRight());
415 MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams();
416 params.setMargins(params.topMargin, params.leftMargin, params.bottomMargin,
417 params.rightMargin);
418 v.setLayoutParams(params);
419 }
420
Jason Monk16fbd9d2017-04-27 14:28:49 -0400421 @Override
422 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
423 super.onLayout(changed, left, top, right, bottom);
424 post(() -> updatePosition());
425 }
426
427 private void animateChild(int oldHeight, int newHeight) {
428 if (true) return;
429 if (mAnimating) {
430 mAnimation.cancel();
431 }
432 mAnimating = true;
433 mAnimation = new AnimatorSet();
434 mAnimation.addListener(new AnimatorListenerAdapter() {
435 @Override
436 public void onAnimationEnd(Animator animation) {
437 mAnimating = false;
438 }
439 });
Wesley.CW Wang42feebe2018-07-04 17:35:00 +0800440 int fromTop = mList.getTop();
441 int fromBottom = mList.getBottom();
Jason Monk16fbd9d2017-04-27 14:28:49 -0400442 int toTop = fromTop - ((newHeight - oldHeight) / 2);
443 int toBottom = fromBottom + ((newHeight - oldHeight) / 2);
Wesley.CW Wang42feebe2018-07-04 17:35:00 +0800444 ObjectAnimator top = ObjectAnimator.ofInt(mList, "top", fromTop, toTop);
445 top.addUpdateListener(animation -> mListBackground.invalidateSelf());
Jason Monk16fbd9d2017-04-27 14:28:49 -0400446 mAnimation.playTogether(top,
Wesley.CW Wang42feebe2018-07-04 17:35:00 +0800447 ObjectAnimator.ofInt(mList, "bottom", fromBottom, toBottom));
Jason Monk16fbd9d2017-04-27 14:28:49 -0400448 }
449
450 public void setDivisionView(View v) {
451 mDivision = v;
452 if (mDivision != null) {
453 mDivision.addOnLayoutChangeListener(
454 (v1, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
455 updatePosition());
456 }
457 updatePosition();
458 }
459
460 private void updatePosition() {
Wesley.CW Wang42feebe2018-07-04 17:35:00 +0800461 if (mList == null) return;
Wesley.CW Wang3004fcb2018-06-15 16:24:57 +0800462 // If got separated button, setRotatedBackground to false,
463 // all items won't get white background.
Aaron Heuckroth57d60d22019-03-05 14:00:12 -0500464 mListBackground.setRotatedBackground(mSeparated);
465 mSeparatedViewBackground.setRotatedBackground(mSeparated);
Jason Monk16fbd9d2017-04-27 14:28:49 -0400466 if (mDivision != null && mDivision.getVisibility() == VISIBLE) {
467 int index = mRotatedBackground ? 0 : 1;
468 mDivision.getLocationOnScreen(mTmp2);
469 float trans = mRotatedBackground ? mDivision.getTranslationX()
470 : mDivision.getTranslationY();
471 int viewTop = (int) (mTmp2[index] + trans);
Wesley.CW Wang42feebe2018-07-04 17:35:00 +0800472 mList.getLocationOnScreen(mTmp2);
Jason Monk16fbd9d2017-04-27 14:28:49 -0400473 viewTop -= mTmp2[index];
474 setCutPoint(viewTop);
475 } else {
Wesley.CW Wang42feebe2018-07-04 17:35:00 +0800476 setCutPoint(mList.getMeasuredHeight());
Jason Monk16fbd9d2017-04-27 14:28:49 -0400477 }
478 }
479
480 private void setCutPoint(int point) {
Wesley.CW Wang42feebe2018-07-04 17:35:00 +0800481 int curPoint = mListBackground.getCutPoint();
Jason Monk16fbd9d2017-04-27 14:28:49 -0400482 if (curPoint == point) return;
483 if (getAlpha() == 0 || curPoint == 0) {
Wesley.CW Wang42feebe2018-07-04 17:35:00 +0800484 mListBackground.setCutPoint(point);
Jason Monk16fbd9d2017-04-27 14:28:49 -0400485 return;
486 }
487 if (mAnimator != null) {
488 if (mEndPoint == point) {
489 return;
490 }
491 mAnimator.cancel();
492 }
493 mEndPoint = point;
Wesley.CW Wang42feebe2018-07-04 17:35:00 +0800494 mAnimator = ObjectAnimator.ofInt(mListBackground, "cutPoint", curPoint, point);
Jason Monk16fbd9d2017-04-27 14:28:49 -0400495 if (mCollapse) {
496 mAnimator.setStartDelay(300);
497 mCollapse = false;
498 }
499 mAnimator.start();
500 }
501
Wesley.CW Wang1096c622018-09-27 20:41:31 +0800502 // If current power menu height larger then screen height, remove padding to break power menu
503 // alignment and set menu center vertical within the screen.
504 private void updatePaddingAndGravityIfTooTall() {
505 int defaultTopPadding;
506 int viewsTotalHeight;
507 int separatedViewTopMargin;
508 int screenHeight;
509 int totalHeight;
510 int targetGravity;
511 MarginLayoutParams params = (MarginLayoutParams) mSeparatedView.getLayoutParams();
512 switch (RotationUtils.getRotation(getContext())) {
513 case RotationUtils.ROTATION_LANDSCAPE:
514 defaultTopPadding = getPaddingLeft();
515 viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth();
Aaron Heuckroth57d60d22019-03-05 14:00:12 -0500516 separatedViewTopMargin = mSeparated ? params.leftMargin : 0;
Wesley.CW Wang1096c622018-09-27 20:41:31 +0800517 screenHeight = getMeasuredWidth();
518 targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.TOP;
519 break;
520 case RotationUtils.ROTATION_SEASCAPE:
521 defaultTopPadding = getPaddingRight();
522 viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth();
Aaron Heuckroth57d60d22019-03-05 14:00:12 -0500523 separatedViewTopMargin = mSeparated ? params.leftMargin : 0;
Wesley.CW Wang1096c622018-09-27 20:41:31 +0800524 screenHeight = getMeasuredWidth();
525 targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.BOTTOM;
526 break;
527 default: // Portrait
528 defaultTopPadding = getPaddingTop();
529 viewsTotalHeight = mList.getMeasuredHeight() + mSeparatedView.getMeasuredHeight();
Aaron Heuckroth57d60d22019-03-05 14:00:12 -0500530 separatedViewTopMargin = mSeparated ? params.topMargin : 0;
Wesley.CW Wang1096c622018-09-27 20:41:31 +0800531 screenHeight = getMeasuredHeight();
532 targetGravity = Gravity.CENTER_VERTICAL|Gravity.RIGHT;
533 break;
534 }
535 totalHeight = defaultTopPadding + viewsTotalHeight + separatedViewTopMargin;
536 if (totalHeight >= screenHeight) {
537 setPadding(0, 0, 0, 0);
538 setGravity(targetGravity);
539 }
540 }
541
Jason Monk16fbd9d2017-04-27 14:28:49 -0400542 @Override
543 public ViewOutlineProvider getOutlineProvider() {
544 return super.getOutlineProvider();
545 }
546
Jason Monk16fbd9d2017-04-27 14:28:49 -0400547 public void setCollapse() {
548 mCollapse = true;
549 }
550
Jason Monk16fbd9d2017-04-27 14:28:49 -0400551 private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsListener = inoutInfo -> {
Wesley.CW Wang42feebe2018-07-04 17:35:00 +0800552 if (mHasOutsideTouch || (mList == null)) {
Jason Monk16fbd9d2017-04-27 14:28:49 -0400553 inoutInfo.setTouchableInsets(
554 ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
555 return;
556 }
557 inoutInfo.setTouchableInsets(
558 ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT);
Wesley.CW Wang42feebe2018-07-04 17:35:00 +0800559 inoutInfo.contentInsets.set(mList.getLeft(), mList.getTop(),
560 0, getBottom() - mList.getBottom());
Jason Monk16fbd9d2017-04-27 14:28:49 -0400561 };
Aaron Heuckrothd0053342019-02-26 14:30:40 -0500562}