blob: 198a4e6cedb88de4d36434531f679446a7269f2c [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 Wangdb357c72018-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 Wang00e2fcf2018-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 Wangdb357c72018-07-04 17:35:00 +080045 private View mList;
Wesley.CW Wang00e2fcf2018-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 Wangdb357c72018-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 Wang00e2fcf2018-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 Wangdb357c72018-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 Wangdb357c72018-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 Wangdb357c72018-07-04 17:35:00 +0800115 mList.setLayoutParams(params);
Jason Monk16fbd9d2017-04-27 14:28:49 -0400116 }
Wesley.CW Wang00e2fcf2018-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 Wangdb357c72018-07-04 17:35:00 +0800138 if (mList == null) {
Jason Monk16fbd9d2017-04-27 14:28:49 -0400139 if (getChildCount() != 0) {
Wesley.CW Wangdb357c72018-07-04 17:35:00 +0800140 mList = getChildAt(0);
141 mList.setBackground(mListBackground);
Wesley.CW Wang00e2fcf2018-06-15 16:24:57 +0800142 mSeparatedView = getChildAt(1);
Wesley.CW Wangdb357c72018-07-04 17:35:00 +0800143 mSeparatedView.setBackground(mSeparatedViewBackground);
Jason Monk16fbd9d2017-04-27 14:28:49 -0400144 updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding());
Wesley.CW Wangdb357c72018-07-04 17:35:00 +0800145 mOldHeight = mList.getMeasuredHeight();
146 mList.addOnLayoutChangeListener(
Jason Monk16fbd9d2017-04-27 14:28:49 -0400147 (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
148 updatePosition());
Jason Monkfd279662017-06-29 19:37:48 -0400149 updateRotation();
Jason Monk16fbd9d2017-04-27 14:28:49 -0400150 } else {
151 return;
152 }
153 }
Wesley.CW Wangdb357c72018-07-04 17:35:00 +0800154 int newHeight = mList.getMeasuredHeight();
Jason Monk16fbd9d2017-04-27 14:28:49 -0400155 if (newHeight != mOldHeight) {
156 animateChild(mOldHeight, newHeight);
157 }
158 post(() -> updatePosition());
Jason Monkfd279662017-06-29 19:37:48 -0400159 }
160
161 @Override
162 protected void onConfigurationChanged(Configuration newConfig) {
163 super.onConfigurationChanged(newConfig);
164 updateRotation();
165 }
166
Julia Reynoldsf5e41822018-01-23 13:55:18 -0500167 public void setSwapOrientation(boolean swapOrientation) {
168 mSwapOrientation = swapOrientation;
169 }
170
Jason Monkfd279662017-06-29 19:37:48 -0400171 private void updateRotation() {
172 int rotation = RotationUtils.getRotation(getContext());
173 if (rotation != mRotation) {
174 rotate(mRotation, rotation);
175 mRotation = rotation;
176 }
177 }
178
179 private void rotate(int from, int to) {
180 if (from != ROTATION_NONE && to != ROTATION_NONE) {
181 // Rather than handling this confusing case, just do 2 rotations.
182 rotate(from, ROTATION_NONE);
183 rotate(ROTATION_NONE, to);
184 return;
185 }
186 if (from == ROTATION_LANDSCAPE || to == ROTATION_SEASCAPE) {
187 rotateRight();
188 } else {
189 rotateLeft();
190 }
Wesley.CW Wang00e2fcf2018-06-15 16:24:57 +0800191 if (mHasSeparatedButton) {
192 if (from == ROTATION_SEASCAPE || to == ROTATION_SEASCAPE) {
193 // Separated view has top margin, so seascape separated view need special rotation,
194 // not a full left or right rotation.
195 swapLeftAndTop(mSeparatedView);
196 } else if (from == ROTATION_LANDSCAPE) {
197 rotateRight(mSeparatedView);
198 } else {
199 rotateLeft(mSeparatedView);
200 }
201 }
Jason Monkfd279662017-06-29 19:37:48 -0400202 if (to != ROTATION_NONE) {
Wesley.CW Wangdb357c72018-07-04 17:35:00 +0800203 if (mList instanceof LinearLayout) {
Jason Monkfd279662017-06-29 19:37:48 -0400204 mRotatedBackground = true;
Wesley.CW Wangdb357c72018-07-04 17:35:00 +0800205 mListBackground.setRotatedBackground(true);
206 mSeparatedViewBackground.setRotatedBackground(true);
207 LinearLayout linearLayout = (LinearLayout) mList;
Julia Reynoldsf5e41822018-01-23 13:55:18 -0500208 if (mSwapOrientation) {
209 linearLayout.setOrientation(LinearLayout.HORIZONTAL);
Wesley.CW Wang00e2fcf2018-06-15 16:24:57 +0800210 setOrientation(LinearLayout.HORIZONTAL);
Julia Reynoldsf5e41822018-01-23 13:55:18 -0500211 }
Wesley.CW Wangdb357c72018-07-04 17:35:00 +0800212 swapDimens(mList);
Wesley.CW Wang00e2fcf2018-06-15 16:24:57 +0800213 swapDimens(mSeparatedView);
Jason Monkfd279662017-06-29 19:37:48 -0400214 }
215 } else {
Wesley.CW Wangdb357c72018-07-04 17:35:00 +0800216 if (mList instanceof LinearLayout) {
Jason Monkfd279662017-06-29 19:37:48 -0400217 mRotatedBackground = false;
Wesley.CW Wangdb357c72018-07-04 17:35:00 +0800218 mListBackground.setRotatedBackground(false);
219 mSeparatedViewBackground.setRotatedBackground(false);
220 LinearLayout linearLayout = (LinearLayout) mList;
Julia Reynoldsf5e41822018-01-23 13:55:18 -0500221 if (mSwapOrientation) {
222 linearLayout.setOrientation(LinearLayout.VERTICAL);
Wesley.CW Wang00e2fcf2018-06-15 16:24:57 +0800223 setOrientation(LinearLayout.VERTICAL);
Julia Reynoldsf5e41822018-01-23 13:55:18 -0500224 }
Wesley.CW Wangdb357c72018-07-04 17:35:00 +0800225 swapDimens(mList);
Wesley.CW Wang00e2fcf2018-06-15 16:24:57 +0800226 swapDimens(mSeparatedView);
Jason Monk16fbd9d2017-04-27 14:28:49 -0400227 }
228 }
229 }
230
Jason Monkfd279662017-06-29 19:37:48 -0400231 private void rotateRight() {
Jason Monk16fbd9d2017-04-27 14:28:49 -0400232 rotateRight(this);
Wesley.CW Wangdb357c72018-07-04 17:35:00 +0800233 rotateRight(mList);
Jason Monk16fbd9d2017-04-27 14:28:49 -0400234 swapDimens(this);
235
Wesley.CW Wangdb357c72018-07-04 17:35:00 +0800236 LayoutParams p = (LayoutParams) mList.getLayoutParams();
Jason Monk16fbd9d2017-04-27 14:28:49 -0400237 p.gravity = rotateGravityRight(p.gravity);
Wesley.CW Wangdb357c72018-07-04 17:35:00 +0800238 mList.setLayoutParams(p);
Wesley.CW Wang00e2fcf2018-06-15 16:24:57 +0800239
240 LayoutParams separatedViewLayoutParams = (LayoutParams) mSeparatedView.getLayoutParams();
241 separatedViewLayoutParams.gravity = rotateGravityRight(separatedViewLayoutParams.gravity);
242 mSeparatedView.setLayoutParams(separatedViewLayoutParams);
243
244 setGravity(p.gravity);
Jason Monk16fbd9d2017-04-27 14:28:49 -0400245 }
246
247 private void swapDimens(View v) {
248 ViewGroup.LayoutParams params = v.getLayoutParams();
249 int h = params.width;
250 params.width = params.height;
251 params.height = h;
252 v.setLayoutParams(params);
253 }
254
255 private int rotateGravityRight(int gravity) {
256 int retGravity = 0;
257 int layoutDirection = getLayoutDirection();
258 final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
259 final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
260
261 switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
262 case Gravity.CENTER_HORIZONTAL:
263 retGravity |= Gravity.CENTER_VERTICAL;
264 break;
265 case Gravity.RIGHT:
266 retGravity |= Gravity.BOTTOM;
267 break;
268 case Gravity.LEFT:
269 default:
270 retGravity |= Gravity.TOP;
271 break;
272 }
273
274 switch (verticalGravity) {
275 case Gravity.CENTER_VERTICAL:
276 retGravity |= Gravity.CENTER_HORIZONTAL;
277 break;
278 case Gravity.BOTTOM:
279 retGravity |= Gravity.LEFT;
280 break;
281 case Gravity.TOP:
282 default:
283 retGravity |= Gravity.RIGHT;
284 break;
285 }
286 return retGravity;
287 }
288
Jason Monkfd279662017-06-29 19:37:48 -0400289 private void rotateLeft() {
Jason Monk16fbd9d2017-04-27 14:28:49 -0400290 rotateLeft(this);
Wesley.CW Wangdb357c72018-07-04 17:35:00 +0800291 rotateLeft(mList);
Jason Monk16fbd9d2017-04-27 14:28:49 -0400292 swapDimens(this);
293
Wesley.CW Wangdb357c72018-07-04 17:35:00 +0800294 LayoutParams p = (LayoutParams) mList.getLayoutParams();
Jason Monk16fbd9d2017-04-27 14:28:49 -0400295 p.gravity = rotateGravityLeft(p.gravity);
Wesley.CW Wangdb357c72018-07-04 17:35:00 +0800296 mList.setLayoutParams(p);
Wesley.CW Wang00e2fcf2018-06-15 16:24:57 +0800297
298 LayoutParams separatedViewLayoutParams = (LayoutParams) mSeparatedView.getLayoutParams();
299 separatedViewLayoutParams.gravity = rotateGravityLeft(separatedViewLayoutParams.gravity);
300 mSeparatedView.setLayoutParams(separatedViewLayoutParams);
301
302 setGravity(p.gravity);
Jason Monk16fbd9d2017-04-27 14:28:49 -0400303 }
304
305 private int rotateGravityLeft(int gravity) {
306 if (gravity == -1) {
307 gravity = Gravity.TOP | Gravity.START;
308 }
309 int retGravity = 0;
310 int layoutDirection = getLayoutDirection();
311 final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
312 final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
313
314 switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
315 case Gravity.CENTER_HORIZONTAL:
316 retGravity |= Gravity.CENTER_VERTICAL;
317 break;
318 case Gravity.RIGHT:
319 retGravity |= Gravity.TOP;
320 break;
321 case Gravity.LEFT:
322 default:
323 retGravity |= Gravity.BOTTOM;
324 break;
325 }
326
327 switch (verticalGravity) {
328 case Gravity.CENTER_VERTICAL:
329 retGravity |= Gravity.CENTER_HORIZONTAL;
330 break;
331 case Gravity.BOTTOM:
332 retGravity |= Gravity.RIGHT;
333 break;
334 case Gravity.TOP:
335 default:
336 retGravity |= Gravity.LEFT;
337 break;
338 }
339 return retGravity;
340 }
341
342 private void rotateLeft(View v) {
343 v.setPadding(v.getPaddingTop(), v.getPaddingRight(), v.getPaddingBottom(),
344 v.getPaddingLeft());
345 MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams();
346 params.setMargins(params.topMargin, params.rightMargin, params.bottomMargin,
347 params.leftMargin);
348 v.setLayoutParams(params);
349 }
350
351 private void rotateRight(View v) {
352 v.setPadding(v.getPaddingBottom(), v.getPaddingLeft(), v.getPaddingTop(),
353 v.getPaddingRight());
354 MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams();
355 params.setMargins(params.bottomMargin, params.leftMargin, params.topMargin,
356 params.rightMargin);
357 v.setLayoutParams(params);
358 }
359
Wesley.CW Wang00e2fcf2018-06-15 16:24:57 +0800360 private void swapLeftAndTop(View v) {
361 v.setPadding(v.getPaddingTop(), v.getPaddingLeft(), v.getPaddingBottom(),
362 v.getPaddingRight());
363 MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams();
364 params.setMargins(params.topMargin, params.leftMargin, params.bottomMargin,
365 params.rightMargin);
366 v.setLayoutParams(params);
367 }
368
Jason Monk16fbd9d2017-04-27 14:28:49 -0400369 @Override
370 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
371 super.onLayout(changed, left, top, right, bottom);
372 post(() -> updatePosition());
373 }
374
375 private void animateChild(int oldHeight, int newHeight) {
376 if (true) return;
377 if (mAnimating) {
378 mAnimation.cancel();
379 }
380 mAnimating = true;
381 mAnimation = new AnimatorSet();
382 mAnimation.addListener(new AnimatorListenerAdapter() {
383 @Override
384 public void onAnimationEnd(Animator animation) {
385 mAnimating = false;
386 }
387 });
Wesley.CW Wangdb357c72018-07-04 17:35:00 +0800388 int fromTop = mList.getTop();
389 int fromBottom = mList.getBottom();
Jason Monk16fbd9d2017-04-27 14:28:49 -0400390 int toTop = fromTop - ((newHeight - oldHeight) / 2);
391 int toBottom = fromBottom + ((newHeight - oldHeight) / 2);
Wesley.CW Wangdb357c72018-07-04 17:35:00 +0800392 ObjectAnimator top = ObjectAnimator.ofInt(mList, "top", fromTop, toTop);
393 top.addUpdateListener(animation -> mListBackground.invalidateSelf());
Jason Monk16fbd9d2017-04-27 14:28:49 -0400394 mAnimation.playTogether(top,
Wesley.CW Wangdb357c72018-07-04 17:35:00 +0800395 ObjectAnimator.ofInt(mList, "bottom", fromBottom, toBottom));
Jason Monk16fbd9d2017-04-27 14:28:49 -0400396 }
397
398 public void setDivisionView(View v) {
399 mDivision = v;
400 if (mDivision != null) {
401 mDivision.addOnLayoutChangeListener(
402 (v1, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
403 updatePosition());
404 }
405 updatePosition();
406 }
407
408 private void updatePosition() {
Wesley.CW Wangdb357c72018-07-04 17:35:00 +0800409 if (mList == null) return;
Wesley.CW Wang00e2fcf2018-06-15 16:24:57 +0800410 // If got separated button, setRotatedBackground to false,
411 // all items won't get white background.
Wesley.CW Wangdb357c72018-07-04 17:35:00 +0800412 mListBackground.setRotatedBackground(mHasSeparatedButton);
413 mSeparatedViewBackground.setRotatedBackground(mHasSeparatedButton);
Jason Monk16fbd9d2017-04-27 14:28:49 -0400414 if (mDivision != null && mDivision.getVisibility() == VISIBLE) {
415 int index = mRotatedBackground ? 0 : 1;
416 mDivision.getLocationOnScreen(mTmp2);
417 float trans = mRotatedBackground ? mDivision.getTranslationX()
418 : mDivision.getTranslationY();
419 int viewTop = (int) (mTmp2[index] + trans);
Wesley.CW Wangdb357c72018-07-04 17:35:00 +0800420 mList.getLocationOnScreen(mTmp2);
Jason Monk16fbd9d2017-04-27 14:28:49 -0400421 viewTop -= mTmp2[index];
422 setCutPoint(viewTop);
423 } else {
Wesley.CW Wangdb357c72018-07-04 17:35:00 +0800424 setCutPoint(mList.getMeasuredHeight());
Jason Monk16fbd9d2017-04-27 14:28:49 -0400425 }
426 }
427
428 private void setCutPoint(int point) {
Wesley.CW Wangdb357c72018-07-04 17:35:00 +0800429 int curPoint = mListBackground.getCutPoint();
Jason Monk16fbd9d2017-04-27 14:28:49 -0400430 if (curPoint == point) return;
431 if (getAlpha() == 0 || curPoint == 0) {
Wesley.CW Wangdb357c72018-07-04 17:35:00 +0800432 mListBackground.setCutPoint(point);
Jason Monk16fbd9d2017-04-27 14:28:49 -0400433 return;
434 }
435 if (mAnimator != null) {
436 if (mEndPoint == point) {
437 return;
438 }
439 mAnimator.cancel();
440 }
441 mEndPoint = point;
Wesley.CW Wangdb357c72018-07-04 17:35:00 +0800442 mAnimator = ObjectAnimator.ofInt(mListBackground, "cutPoint", curPoint, point);
Jason Monk16fbd9d2017-04-27 14:28:49 -0400443 if (mCollapse) {
444 mAnimator.setStartDelay(300);
445 mCollapse = false;
446 }
447 mAnimator.start();
448 }
449
450 @Override
451 public ViewOutlineProvider getOutlineProvider() {
452 return super.getOutlineProvider();
453 }
454
455 public void setOutsideTouchListener(OnClickListener onClickListener) {
456 mHasOutsideTouch = true;
457 requestLayout();
458 setOnClickListener(onClickListener);
459 setClickable(true);
460 setFocusable(true);
461 }
462
463 public void setCollapse() {
464 mCollapse = true;
465 }
466
Wesley.CW Wang00e2fcf2018-06-15 16:24:57 +0800467 public void setHasSeparatedButton(boolean hasSeparatedButton) {
468 mHasSeparatedButton = hasSeparatedButton;
469 }
470
Jason Monk16fbd9d2017-04-27 14:28:49 -0400471 public static HardwareUiLayout get(View v) {
472 if (v instanceof HardwareUiLayout) return (HardwareUiLayout) v;
473 if (v.getParent() instanceof View) {
474 return get((View) v.getParent());
475 }
476 return null;
477 }
478
479 private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsListener = inoutInfo -> {
Wesley.CW Wangdb357c72018-07-04 17:35:00 +0800480 if (mHasOutsideTouch || (mList == null)) {
Jason Monk16fbd9d2017-04-27 14:28:49 -0400481 inoutInfo.setTouchableInsets(
482 ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
483 return;
484 }
485 inoutInfo.setTouchableInsets(
486 ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT);
Wesley.CW Wangdb357c72018-07-04 17:35:00 +0800487 inoutInfo.contentInsets.set(mList.getLeft(), mList.getTop(),
488 0, getBottom() - mList.getBottom());
Jason Monk16fbd9d2017-04-27 14:28:49 -0400489 };
490}