diff --git a/packages/SystemUI/res/layout/global_actions_grid_v2.xml b/packages/SystemUI/res/layout/global_actions_grid_v2.xml
index ff0c6a756ca26..92ae1b95264f6 100644
--- a/packages/SystemUI/res/layout/global_actions_grid_v2.xml
+++ b/packages/SystemUI/res/layout/global_actions_grid_v2.xml
@@ -1,71 +1,75 @@
-
-
-
+
-
-
+
+
+
+
+
+ >
-
-
-
-
-
-
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ >
+
+
-
-
-
+
+
+
+
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/global_actions_wrapped.xml b/packages/SystemUI/res/layout/global_actions_wrapped.xml
deleted file mode 100644
index d4410702a7d19..0000000000000
--- a/packages/SystemUI/res/layout/global_actions_wrapped.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
deleted file mode 100644
index ad2e0024065f7..0000000000000
--- a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
+++ /dev/null
@@ -1,570 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.systemui;
-
-import static com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE;
-import static com.android.systemui.util.leak.RotationUtils.ROTATION_NONE;
-import static com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.provider.Settings;
-import android.util.AttributeSet;
-import android.view.Gravity;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewOutlineProvider;
-import android.view.ViewTreeObserver;
-import android.widget.LinearLayout;
-
-import com.android.systemui.tuner.TunerService;
-import com.android.systemui.tuner.TunerService.Tunable;
-import com.android.systemui.util.leak.RotationUtils;
-
-/**
- * Layout for placing two containers at a specific physical position on the device, relative to the
- * device's hardware, regardless of screen rotation.
- */
-public class HardwareUiLayout extends MultiListLayout implements Tunable {
-
- private static final String EDGE_BLEED = "sysui_hwui_edge_bleed";
- private static final String ROUNDED_DIVIDER = "sysui_hwui_rounded_divider";
- private final int[] mTmp2 = new int[2];
- private ViewGroup mList;
- private ViewGroup mSeparatedView;
- private int mOldHeight;
- private boolean mAnimating;
- private AnimatorSet mAnimation;
- private View mDivision;
- private HardwareBgDrawable mListBackground;
- private HardwareBgDrawable mSeparatedViewBackground;
- private Animator mAnimator;
- private boolean mCollapse;
- private int mEndPoint;
- private boolean mEdgeBleed;
- private boolean mRoundedDivider;
- private boolean mRotatedBackground;
- private boolean mSwapOrientation = true;
-
- public HardwareUiLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- // Manually re-initialize mRotation to portrait-mode, since this view must always
- // be constructed in portrait mode and rotated into the correct initial position.
- mRotation = ROTATION_NONE;
- updateSettings();
- }
-
- @Override
- protected ViewGroup getSeparatedView() {
- return findViewById(com.android.systemui.R.id.separated_button);
- }
-
- @Override
- protected ViewGroup getListView() {
- return findViewById(android.R.id.list);
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- updateSettings();
- Dependency.get(TunerService.class).addTunable(this, EDGE_BLEED, ROUNDED_DIVIDER);
- getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsListener);
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- getViewTreeObserver().removeOnComputeInternalInsetsListener(mInsetsListener);
- Dependency.get(TunerService.class).removeTunable(this);
- }
-
- @Override
- public void onTuningChanged(String key, String newValue) {
- updateSettings();
- }
-
- private void updateSettings() {
- mEdgeBleed = Settings.Secure.getInt(getContext().getContentResolver(),
- EDGE_BLEED, 0) != 0;
- mRoundedDivider = Settings.Secure.getInt(getContext().getContentResolver(),
- ROUNDED_DIVIDER, 0) != 0;
- updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding());
- mListBackground = new HardwareBgDrawable(mRoundedDivider, !mEdgeBleed, getContext());
- mSeparatedViewBackground = new HardwareBgDrawable(mRoundedDivider, !mEdgeBleed,
- getContext());
- if (mList != null) {
- mList.setBackground(mListBackground);
- mSeparatedView.setBackground(mSeparatedViewBackground);
- requestLayout();
- }
- }
-
- private void updateEdgeMargin(int edge) {
- if (mList != null) {
- MarginLayoutParams params = (MarginLayoutParams) mList.getLayoutParams();
- if (mRotation == ROTATION_LANDSCAPE) {
- params.topMargin = edge;
- } else if (mRotation == ROTATION_SEASCAPE) {
- params.bottomMargin = edge;
- } else {
- params.rightMargin = edge;
- }
- mList.setLayoutParams(params);
- }
-
- if (mSeparatedView != null) {
- MarginLayoutParams params = (MarginLayoutParams) mSeparatedView.getLayoutParams();
- if (mRotation == ROTATION_LANDSCAPE) {
- params.topMargin = edge;
- } else if (mRotation == ROTATION_SEASCAPE) {
- params.bottomMargin = edge;
- } else {
- params.rightMargin = edge;
- }
- mSeparatedView.setLayoutParams(params);
- }
- }
-
- private int getEdgePadding() {
- return getContext().getResources().getDimensionPixelSize(R.dimen.edge_margin);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- if (mList == null) {
- if (getChildCount() != 0) {
- mList = getListView();
- mList.setBackground(mListBackground);
- mSeparatedView = getSeparatedView();
- mSeparatedView.setBackground(mSeparatedViewBackground);
- updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding());
- mOldHeight = mList.getMeasuredHeight();
-
- // Must be called to initialize view rotation correctly.
- // Requires LayoutParams, hence why this isn't called during the constructor.
- updateRotation();
- } else {
- return;
- }
- }
- int newHeight = mList.getMeasuredHeight();
- if (newHeight != mOldHeight) {
- animateChild(mOldHeight, newHeight);
- }
-
- post(() -> updatePaddingAndGravityIfTooTall());
- post(() -> updatePosition());
- }
-
- public void setSwapOrientation(boolean swapOrientation) {
- mSwapOrientation = swapOrientation;
- }
-
- private void updateRotation() {
- int rotation = RotationUtils.getRotation(getContext());
- if (rotation != mRotation) {
- rotate(mRotation, rotation);
- mRotation = rotation;
- }
- }
-
- /**
- * Requires LayoutParams to be set to work correctly, and therefore must be run after after
- * the HardwareUILayout has been added to the view hierarchy.
- */
- protected void rotate(int from, int to) {
- super.rotate(from, to);
- if (from != ROTATION_NONE && to != ROTATION_NONE) {
- // Rather than handling this confusing case, just do 2 rotations.
- rotate(from, ROTATION_NONE);
- rotate(ROTATION_NONE, to);
- return;
- }
- if (from == ROTATION_LANDSCAPE || to == ROTATION_SEASCAPE) {
- rotateRight();
- } else {
- rotateLeft();
- }
- if (mAdapter.hasSeparatedItems()) {
- if (from == ROTATION_SEASCAPE || to == ROTATION_SEASCAPE) {
- // Separated view has top margin, so seascape separated view need special rotation,
- // not a full left or right rotation.
- swapLeftAndTop(mSeparatedView);
- } else if (from == ROTATION_LANDSCAPE) {
- rotateRight(mSeparatedView);
- } else {
- rotateLeft(mSeparatedView);
- }
- }
- if (to != ROTATION_NONE) {
- if (mList instanceof LinearLayout) {
- mRotatedBackground = true;
- mListBackground.setRotatedBackground(true);
- mSeparatedViewBackground.setRotatedBackground(true);
- LinearLayout linearLayout = (LinearLayout) mList;
- if (mSwapOrientation) {
- linearLayout.setOrientation(LinearLayout.HORIZONTAL);
- setOrientation(LinearLayout.HORIZONTAL);
- }
- swapDimens(mList);
- swapDimens(mSeparatedView);
- }
- } else {
- if (mList instanceof LinearLayout) {
- mRotatedBackground = false;
- mListBackground.setRotatedBackground(false);
- mSeparatedViewBackground.setRotatedBackground(false);
- LinearLayout linearLayout = (LinearLayout) mList;
- if (mSwapOrientation) {
- linearLayout.setOrientation(LinearLayout.VERTICAL);
- setOrientation(LinearLayout.VERTICAL);
- }
- swapDimens(mList);
- swapDimens(mSeparatedView);
- }
- }
- }
-
- @Override
- public void onUpdateList() {
- super.onUpdateList();
-
- for (int i = 0; i < mAdapter.getCount(); i++) {
- ViewGroup parent;
- boolean separated = mAdapter.shouldBeSeparated(i);
- if (separated) {
- parent = getSeparatedView();
- } else {
- parent = getListView();
- }
- View v = mAdapter.getView(i, null, parent);
- parent.addView(v);
- }
- }
-
- private void rotateRight() {
- rotateRight(this);
- rotateRight(mList);
- swapDimens(this);
-
- LayoutParams p = (LayoutParams) mList.getLayoutParams();
- p.gravity = rotateGravityRight(p.gravity);
- mList.setLayoutParams(p);
-
- LayoutParams separatedViewLayoutParams = (LayoutParams) mSeparatedView.getLayoutParams();
- separatedViewLayoutParams.gravity = rotateGravityRight(separatedViewLayoutParams.gravity);
- mSeparatedView.setLayoutParams(separatedViewLayoutParams);
-
- setGravity(rotateGravityRight(getGravity()));
- }
-
- private void swapDimens(View v) {
- ViewGroup.LayoutParams params = v.getLayoutParams();
- int h = params.width;
- params.width = params.height;
- params.height = h;
- v.setLayoutParams(params);
- }
-
- private int rotateGravityRight(int gravity) {
- int retGravity = 0;
- int layoutDirection = getLayoutDirection();
- final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
- final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
-
- switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
- case Gravity.CENTER_HORIZONTAL:
- retGravity |= Gravity.CENTER_VERTICAL;
- break;
- case Gravity.RIGHT:
- retGravity |= Gravity.BOTTOM;
- break;
- case Gravity.LEFT:
- default:
- retGravity |= Gravity.TOP;
- break;
- }
-
- switch (verticalGravity) {
- case Gravity.CENTER_VERTICAL:
- retGravity |= Gravity.CENTER_HORIZONTAL;
- break;
- case Gravity.BOTTOM:
- retGravity |= Gravity.LEFT;
- break;
- case Gravity.TOP:
- default:
- retGravity |= Gravity.RIGHT;
- break;
- }
- return retGravity;
- }
-
- private void rotateLeft() {
- rotateLeft(this);
- rotateLeft(mList);
- swapDimens(this);
-
- LayoutParams p = (LayoutParams) mList.getLayoutParams();
- p.gravity = rotateGravityLeft(p.gravity);
- mList.setLayoutParams(p);
-
- LayoutParams separatedViewLayoutParams = (LayoutParams) mSeparatedView.getLayoutParams();
- separatedViewLayoutParams.gravity = rotateGravityLeft(separatedViewLayoutParams.gravity);
- mSeparatedView.setLayoutParams(separatedViewLayoutParams);
-
- setGravity(rotateGravityLeft(getGravity()));
- }
-
- private int rotateGravityLeft(int gravity) {
- if (gravity == -1) {
- gravity = Gravity.TOP | Gravity.START;
- }
- int retGravity = 0;
- int layoutDirection = getLayoutDirection();
- final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
- final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
-
- switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
- case Gravity.CENTER_HORIZONTAL:
- retGravity |= Gravity.CENTER_VERTICAL;
- break;
- case Gravity.RIGHT:
- retGravity |= Gravity.TOP;
- break;
- case Gravity.LEFT:
- default:
- retGravity |= Gravity.BOTTOM;
- break;
- }
-
- switch (verticalGravity) {
- case Gravity.CENTER_VERTICAL:
- retGravity |= Gravity.CENTER_HORIZONTAL;
- break;
- case Gravity.BOTTOM:
- retGravity |= Gravity.RIGHT;
- break;
- case Gravity.TOP:
- default:
- retGravity |= Gravity.LEFT;
- break;
- }
- return retGravity;
- }
-
- private void rotateLeft(View v) {
- v.setPadding(v.getPaddingTop(), v.getPaddingRight(), v.getPaddingBottom(),
- v.getPaddingLeft());
- MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams();
- params.setMargins(params.topMargin, params.rightMargin, params.bottomMargin,
- params.leftMargin);
- v.setLayoutParams(params);
- }
-
- private void rotateRight(View v) {
- v.setPadding(v.getPaddingBottom(), v.getPaddingLeft(), v.getPaddingTop(),
- v.getPaddingRight());
- MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams();
- params.setMargins(params.bottomMargin, params.leftMargin, params.topMargin,
- params.rightMargin);
- v.setLayoutParams(params);
- }
-
- private void swapLeftAndTop(View v) {
- v.setPadding(v.getPaddingTop(), v.getPaddingLeft(), v.getPaddingBottom(),
- v.getPaddingRight());
- MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams();
- params.setMargins(params.topMargin, params.leftMargin, params.bottomMargin,
- params.rightMargin);
- v.setLayoutParams(params);
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
-
- post(() -> updatePosition());
-
- }
-
- private void animateChild(int oldHeight, int newHeight) {
- if (true) return;
- if (mAnimating) {
- mAnimation.cancel();
- }
- mAnimating = true;
- mAnimation = new AnimatorSet();
- mAnimation.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mAnimating = false;
- }
- });
- int fromTop = mList.getTop();
- int fromBottom = mList.getBottom();
- int toTop = fromTop - ((newHeight - oldHeight) / 2);
- int toBottom = fromBottom + ((newHeight - oldHeight) / 2);
- ObjectAnimator top = ObjectAnimator.ofInt(mList, "top", fromTop, toTop);
- top.addUpdateListener(animation -> mListBackground.invalidateSelf());
- mAnimation.playTogether(top,
- ObjectAnimator.ofInt(mList, "bottom", fromBottom, toBottom));
- }
-
- public void setDivisionView(View v) {
- mDivision = v;
- if (mDivision != null) {
- mDivision.addOnLayoutChangeListener(
- (v1, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
- updatePosition());
- }
- updatePosition();
- }
-
- private void updatePosition() {
- if (mList == null) return;
- // If got separated button, setRotatedBackground to false,
- // all items won't get white background.
- boolean separated = mAdapter.hasSeparatedItems();
- mListBackground.setRotatedBackground(separated);
- mSeparatedViewBackground.setRotatedBackground(separated);
- if (mDivision != null && mDivision.getVisibility() == VISIBLE) {
- int index = mRotatedBackground ? 0 : 1;
- mDivision.getLocationOnScreen(mTmp2);
- float trans = mRotatedBackground ? mDivision.getTranslationX()
- : mDivision.getTranslationY();
- int viewTop = (int) (mTmp2[index] + trans);
- mList.getLocationOnScreen(mTmp2);
- viewTop -= mTmp2[index];
- setCutPoint(viewTop);
- } else {
- setCutPoint(mList.getMeasuredHeight());
- }
- }
-
- private void setCutPoint(int point) {
- int curPoint = mListBackground.getCutPoint();
- if (curPoint == point) return;
- if (getAlpha() == 0 || curPoint == 0) {
- mListBackground.setCutPoint(point);
- return;
- }
- if (mAnimator != null) {
- if (mEndPoint == point) {
- return;
- }
- mAnimator.cancel();
- }
- mEndPoint = point;
- mAnimator = ObjectAnimator.ofInt(mListBackground, "cutPoint", curPoint, point);
- if (mCollapse) {
- mAnimator.setStartDelay(300);
- mCollapse = false;
- }
- mAnimator.start();
- }
-
- // If current power menu height larger then screen height, remove padding to break power menu
- // alignment and set menu center vertical within the screen.
- private void updatePaddingAndGravityIfTooTall() {
- int defaultTopPadding;
- int viewsTotalHeight;
- int separatedViewTopMargin;
- int screenHeight;
- int totalHeight;
- int targetGravity;
- boolean separated = mAdapter.hasSeparatedItems();
- MarginLayoutParams params = (MarginLayoutParams) mSeparatedView.getLayoutParams();
- switch (RotationUtils.getRotation(getContext())) {
- case RotationUtils.ROTATION_LANDSCAPE:
- defaultTopPadding = getPaddingLeft();
- viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth();
- separatedViewTopMargin = separated ? params.leftMargin : 0;
- screenHeight = getMeasuredWidth();
- targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.TOP;
- break;
- case RotationUtils.ROTATION_SEASCAPE:
- defaultTopPadding = getPaddingRight();
- viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth();
- separatedViewTopMargin = separated ? params.leftMargin : 0;
- screenHeight = getMeasuredWidth();
- targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.BOTTOM;
- break;
- default: // Portrait
- defaultTopPadding = getPaddingTop();
- viewsTotalHeight = mList.getMeasuredHeight() + mSeparatedView.getMeasuredHeight();
- separatedViewTopMargin = separated ? params.topMargin : 0;
- screenHeight = getMeasuredHeight();
- targetGravity = Gravity.CENTER_VERTICAL|Gravity.RIGHT;
- break;
- }
- totalHeight = defaultTopPadding + viewsTotalHeight + separatedViewTopMargin;
- if (totalHeight >= screenHeight) {
- setPadding(0, 0, 0, 0);
- setGravity(targetGravity);
- }
- }
-
- @Override
- public ViewOutlineProvider getOutlineProvider() {
- return super.getOutlineProvider();
- }
-
- public void setCollapse() {
- mCollapse = true;
- }
-
- private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsListener = inoutInfo -> {
- if (mHasOutsideTouch || (mList == null)) {
- inoutInfo.setTouchableInsets(
- ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
- return;
- }
- inoutInfo.setTouchableInsets(
- ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT);
- inoutInfo.contentInsets.set(mList.getLeft(), mList.getTop(),
- 0, getBottom() - mList.getBottom());
- };
-
- private float getAnimationDistance() {
- return getContext().getResources().getDimension(
- com.android.systemui.R.dimen.global_actions_panel_width) / 2;
- }
-
- @Override
- public float getAnimationOffsetX() {
- if (RotationUtils.getRotation(mContext) == ROTATION_NONE) {
- return getAnimationDistance();
- }
- return 0;
- }
-
- @Override
- public float getAnimationOffsetY() {
- switch (RotationUtils.getRotation(getContext())) {
- case RotationUtils.ROTATION_LANDSCAPE:
- return -getAnimationDistance();
- case RotationUtils.ROTATION_SEASCAPE:
- return getAnimationDistance();
- default: // Portrait
- return 0;
- }
- }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 24f505d5a395f..786ad2c7d82ac 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -1574,7 +1574,6 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
private ControlsUiController mControlsUiController;
private ViewGroup mControlsView;
- private ViewGroup mContainerView;
ActionsDialog(Context context, MyAdapter adapter,
GlobalActionsPanelPlugin.PanelViewController plugin, BlurUtils blurUtils,
@@ -1671,7 +1670,6 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
mControlsView = findViewById(com.android.systemui.R.id.global_actions_controls);
mGlobalActionsLayout = findViewById(com.android.systemui.R.id.global_actions_view);
mGlobalActionsLayout.setOutsideTouchListener(view -> dismiss());
- ((View) mGlobalActionsLayout.getParent()).setOnClickListener(view -> dismiss());
mGlobalActionsLayout.setListViewAccessibilityDelegate(new View.AccessibilityDelegate() {
@Override
public boolean dispatchPopulateAccessibilityEvent(
@@ -1684,6 +1682,15 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
mGlobalActionsLayout.setRotationListener(this::onRotate);
mGlobalActionsLayout.setAdapter(mAdapter);
+ View globalActionsParent = (View) mGlobalActionsLayout.getParent();
+ globalActionsParent.setOnClickListener(v -> dismiss());
+
+ // add fall-through dismiss handling to root view
+ View rootView = findViewById(com.android.systemui.R.id.global_actions_grid_root);
+ if (rootView != null) {
+ rootView.setOnClickListener(v -> dismiss());
+ }
+
if (shouldUsePanel()) {
initializePanel();
}
@@ -1692,14 +1699,6 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
mScrimAlpha = ScrimController.BUSY_SCRIM_ALPHA;
}
getWindow().setBackgroundDrawable(mBackgroundDrawable);
-
- if (mControlsView != null) {
- mContainerView = findViewById(com.android.systemui.R.id.global_actions_container);
- mContainerView.setOnTouchListener((v, e) -> {
- dismiss();
- return true;
- });
- }
}
private void fixNavBarClipping() {
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/MinHeightScrollView.java b/packages/SystemUI/src/com/android/systemui/globalactions/MinHeightScrollView.java
new file mode 100644
index 0000000000000..622fa658f1b0e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/MinHeightScrollView.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.globalactions;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ScrollView;
+
+/**
+ * When measured, this view sets the minimum height of its first child to be equal to its own
+ * target height.
+ *
+ * This ensures fall-through click handlers can be placed on this view's child component.
+ */
+public class MinHeightScrollView extends ScrollView {
+ public MinHeightScrollView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ View firstChild = getChildAt(0);
+ if (firstChild != null) {
+ firstChild.setMinimumHeight(MeasureSpec.getSize(heightMeasureSpec));
+ }
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+}