Loading packages/SystemUI/res/layout/global_actions_wrapped.xml +1 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <com.android.systemui.HardwareUiLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@id/global_actions_view" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="top|right" Loading packages/SystemUI/res/values/ids.xml +3 −0 Original line number Diff line number Diff line Loading @@ -114,5 +114,8 @@ <item type="id" name="aod_mask_transition_progress_tag" /> <item type="id" name="aod_mask_transition_progress_end_tag" /> <item type="id" name="aod_mask_transition_progress_start_tag" /> <!-- Global Actions Menu --> <item type="id" name="global_actions_view" /> </resources> packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java +44 −33 Original line number Diff line number Diff line Loading @@ -37,23 +37,25 @@ import com.android.systemui.tuner.TunerService; import com.android.systemui.tuner.TunerService.Tunable; import com.android.systemui.util.leak.RotationUtils; public class HardwareUiLayout extends LinearLayout implements Tunable { /** * 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 View mList; private View mSeparatedView; private ViewGroup mList; private ViewGroup mSeparatedView; private int mOldHeight; private boolean mAnimating; private AnimatorSet mAnimation; private View mDivision; private boolean mHasOutsideTouch; private HardwareBgDrawable mListBackground; private HardwareBgDrawable mSeparatedViewBackground; private Animator mAnimator; private boolean mCollapse; private boolean mHasSeparatedButton; private int mEndPoint; private boolean mEdgeBleed; private boolean mRoundedDivider; Loading @@ -66,6 +68,35 @@ public class HardwareUiLayout extends LinearLayout implements Tunable { 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 public void removeAllItems() { if (mList != null) { mList.removeAllViews(); } if (mSeparatedView != null) { mSeparatedView.removeAllViews(); } } @Override public ViewGroup getParentView(boolean separated, int index) { if (separated) { return getSeparatedView(); } else { return getListView(); } } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); Loading Loading @@ -137,9 +168,9 @@ public class HardwareUiLayout extends LinearLayout implements Tunable { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (mList == null) { if (getChildCount() != 0) { mList = getChildAt(0); mList = getListView(); mList.setBackground(mListBackground); mSeparatedView = getChildAt(1); mSeparatedView = getSeparatedView(); mSeparatedView.setBackground(mSeparatedViewBackground); updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding()); mOldHeight = mList.getMeasuredHeight(); Loading Loading @@ -187,7 +218,7 @@ public class HardwareUiLayout extends LinearLayout implements Tunable { } else { rotateLeft(); } if (mHasSeparatedButton) { if (mHasSeparatedView) { 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. Loading Loading @@ -408,8 +439,8 @@ public class HardwareUiLayout extends LinearLayout implements Tunable { if (mList == null) return; // If got separated button, setRotatedBackground to false, // all items won't get white background. mListBackground.setRotatedBackground(mHasSeparatedButton); mSeparatedViewBackground.setRotatedBackground(mHasSeparatedButton); mListBackground.setRotatedBackground(mHasSeparatedView); mSeparatedViewBackground.setRotatedBackground(mHasSeparatedView); if (mDivision != null && mDivision.getVisibility() == VISIBLE) { int index = mRotatedBackground ? 0 : 1; mDivision.getLocationOnScreen(mTmp2); Loading Loading @@ -460,21 +491,21 @@ public class HardwareUiLayout extends LinearLayout implements Tunable { case RotationUtils.ROTATION_LANDSCAPE: defaultTopPadding = getPaddingLeft(); viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth(); separatedViewTopMargin = mHasSeparatedButton ? params.leftMargin : 0; separatedViewTopMargin = mHasSeparatedView ? params.leftMargin : 0; screenHeight = getMeasuredWidth(); targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.TOP; break; case RotationUtils.ROTATION_SEASCAPE: defaultTopPadding = getPaddingRight(); viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth(); separatedViewTopMargin = mHasSeparatedButton ? params.leftMargin : 0; separatedViewTopMargin = mHasSeparatedView ? params.leftMargin : 0; screenHeight = getMeasuredWidth(); targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.BOTTOM; break; default: // Portrait defaultTopPadding = getPaddingTop(); viewsTotalHeight = mList.getMeasuredHeight() + mSeparatedView.getMeasuredHeight(); separatedViewTopMargin = mHasSeparatedButton ? params.topMargin : 0; separatedViewTopMargin = mHasSeparatedView ? params.topMargin : 0; screenHeight = getMeasuredHeight(); targetGravity = Gravity.CENTER_VERTICAL|Gravity.RIGHT; break; Loading @@ -491,30 +522,10 @@ public class HardwareUiLayout extends LinearLayout implements Tunable { return super.getOutlineProvider(); } public void setOutsideTouchListener(OnClickListener onClickListener) { mHasOutsideTouch = true; requestLayout(); setOnClickListener(onClickListener); setClickable(true); setFocusable(true); } public void setCollapse() { mCollapse = true; } public void setHasSeparatedButton(boolean hasSeparatedButton) { mHasSeparatedButton = hasSeparatedButton; } public static HardwareUiLayout get(View v) { if (v instanceof HardwareUiLayout) return (HardwareUiLayout) v; if (v.getParent() instanceof View) { return get((View) v.getParent()); } return null; } private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsListener = inoutInfo -> { if (mHasOutsideTouch || (mList == null)) { inoutInfo.setTouchableInsets( Loading packages/SystemUI/src/com/android/systemui/MultiListLayout.java 0 → 100644 +124 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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 android.content.Context; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; /** * Layout class representing the Global Actions menu which appears when the power button is held. */ public abstract class MultiListLayout extends LinearLayout { boolean mHasOutsideTouch; boolean mHasSeparatedView; int mExpectedSeparatedItemCount; int mExpectedListItemCount; public MultiListLayout(Context context, AttributeSet attrs) { super(context, attrs); } protected abstract ViewGroup getSeparatedView(); protected abstract ViewGroup getListView(); /** * Removes all child items from the separated and list views, if they exist. */ public abstract void removeAllItems(); /** * Get the parent view which will be used to contain the item at the specified index. * @param separated Whether or not this index refers to a position in the separated or list * container. * @param index The index of the item within the container. * @return The parent ViewGroup which will be used to contain the specified item * after it has been added to the layout. */ public abstract ViewGroup getParentView(boolean separated, int index); /** * Sets the divided view, which may have a differently-colored background. */ public abstract void setDivisionView(View v); /** * Set the view accessibility delegate for the list view container. */ public void setListViewAccessibilityDelegate(View.AccessibilityDelegate delegate) { getListView().setAccessibilityDelegate(delegate); } protected void setSeparatedViewVisibility(boolean visible) { getSeparatedView().setVisibility(visible ? View.VISIBLE : View.GONE); } /** * Sets the number of items expected to be rendered in the separated container. This allows the * layout to correctly determine which parent containers will be used for items before they have * beenadded to the layout. * @param count The number of items expected. */ public void setExpectedSeparatedItemCount(int count) { mExpectedSeparatedItemCount = count; } /** * Sets the number of items expected to be rendered in the list container. This allows the * layout to correctly determine which parent containers will be used for items before they have * beenadded to the layout. * @param count The number of items expected. */ public void setExpectedListItemCount(int count) { mExpectedListItemCount = count; } /** * Sets whether the separated view should be shown, and handles updating visibility on * that view. */ public void setHasSeparatedView(boolean hasSeparatedView) { mHasSeparatedView = hasSeparatedView; setSeparatedViewVisibility(hasSeparatedView); } /** * Sets this layout to respond to an outside touch listener. */ public void setOutsideTouchListener(OnClickListener onClickListener) { mHasOutsideTouch = true; requestLayout(); setOnClickListener(onClickListener); setClickable(true); setFocusable(true); } /** * Retrieve the MultiListLayout associated with the given view. */ public static MultiListLayout get(View v) { if (v instanceof MultiListLayout) return (MultiListLayout) v; if (v.getParent() instanceof View) { return get((View) v.getParent()); } return null; } } packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +70 −29 Original line number Diff line number Diff line Loading @@ -67,10 +67,8 @@ import android.view.WindowManagerGlobal; import android.view.accessibility.AccessibilityEvent; import android.widget.AdapterView.OnItemLongClickListener; import android.widget.BaseAdapter; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.ImageView.ScaleType; import android.widget.LinearLayout; import android.widget.TextView; import com.android.internal.R; Loading @@ -86,8 +84,8 @@ import com.android.internal.util.ScreenRecordHelper; import com.android.internal.util.ScreenshotHelper; import com.android.internal.widget.LockPatternUtils; import com.android.systemui.Dependency; import com.android.systemui.HardwareUiLayout; import com.android.systemui.Interpolators; import com.android.systemui.MultiListLayout; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.plugins.GlobalActions.GlobalActionsManager; import com.android.systemui.statusbar.phone.ScrimController; Loading Loading @@ -490,6 +488,11 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, public boolean showBeforeProvisioning() { return true; } @Override public boolean shouldBeSeparated() { return true; } } private final class RestartAction extends SinglePressAction implements LongPressAction { Loading Loading @@ -926,6 +929,34 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, return getItem(position).isEnabled(); } public ArrayList<Action> getSeparatedActions(boolean shouldUseSeparatedView) { ArrayList<Action> separatedActions = new ArrayList<Action>(); if (!shouldUseSeparatedView) { return separatedActions; } for (int i = 0; i < mItems.size(); i++) { final Action action = mItems.get(i); if (action.shouldBeSeparated()) { separatedActions.add(action); } } return separatedActions; } public ArrayList<Action> getListActions(boolean shouldUseSeparatedView) { if (!shouldUseSeparatedView) { return new ArrayList<Action>(mItems); } ArrayList<Action> listActions = new ArrayList<Action>(); for (int i = 0; i < mItems.size(); i++) { final Action action = mItems.get(i); if (!action.shouldBeSeparated()) { listActions.add(action); } } return listActions; } @Override public boolean areAllItemsEnabled() { return false; Loading Loading @@ -965,7 +996,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, View view = action.create(mContext, convertView, parent, LayoutInflater.from(mContext)); // Everything but screenshot, the last item, gets white background. if (position == getCount() - 1) { HardwareUiLayout.get(parent).setDivisionView(view); MultiListLayout.get(parent).setDivisionView(view); } return view; } Loading Loading @@ -1004,6 +1035,10 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, boolean showBeforeProvisioning(); boolean isEnabled(); default boolean shouldBeSeparated() { return false; } } /** Loading Loading @@ -1423,9 +1458,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, private final Context mContext; private final MyAdapter mAdapter; private final LinearLayout mListView; private final FrameLayout mSeparatedView; private final HardwareUiLayout mHardwareLayout; private final MultiListLayout mGlobalActionsLayout; private final OnClickListener mClickListener; private final OnItemLongClickListener mLongClickListener; private final GradientDrawable mGradientDrawable; Loading Loading @@ -1466,16 +1499,11 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY); setContentView(com.android.systemui.R.layout.global_actions_wrapped); mListView = findViewById(android.R.id.list); mSeparatedView = findViewById(com.android.systemui.R.id.separated_button); if (!mShouldDisplaySeparatedButton) { mSeparatedView.setVisibility(View.GONE); } mHardwareLayout = HardwareUiLayout.get(mListView); mHardwareLayout.setOutsideTouchListener(view -> dismiss()); mHardwareLayout.setHasSeparatedButton(mShouldDisplaySeparatedButton); setTitle(R.string.global_actions); mListView.setAccessibilityDelegate(new View.AccessibilityDelegate() { mGlobalActionsLayout = (MultiListLayout) findViewById(com.android.systemui.R.id.global_actions_view); mGlobalActionsLayout.setOutsideTouchListener(view -> dismiss()); mGlobalActionsLayout.setHasSeparatedView(mShouldDisplaySeparatedButton); mGlobalActionsLayout.setListViewAccessibilityDelegate(new View.AccessibilityDelegate() { @Override public boolean dispatchPopulateAccessibilityEvent( View host, AccessibilityEvent event) { Loading @@ -1484,20 +1512,33 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, return true; } }); setTitle(R.string.global_actions); } private void updateList() { mListView.removeAllViews(); mSeparatedView.removeAllViews(); mGlobalActionsLayout.removeAllItems(); ArrayList<Action> separatedActions = mAdapter.getSeparatedActions(mShouldDisplaySeparatedButton); ArrayList<Action> listActions = mAdapter.getListActions(mShouldDisplaySeparatedButton); mGlobalActionsLayout.setExpectedListItemCount(listActions.size()); mGlobalActionsLayout.setExpectedSeparatedItemCount(separatedActions.size()); for (int i = 0; i < mAdapter.getCount(); i++) { ViewGroup parentView = mShouldDisplaySeparatedButton && i == mAdapter.getCount() - 1 ? mSeparatedView : mListView; View v = mAdapter.getView(i, null, parentView); Action action = mAdapter.getItem(i); int separatedIndex = separatedActions.indexOf(action); ViewGroup parent; if (separatedIndex != -1) { parent = mGlobalActionsLayout.getParentView(true, separatedIndex); } else { int listIndex = listActions.indexOf(action); parent = mGlobalActionsLayout.getParentView(false, listIndex); } View v = mAdapter.getView(i, null, parent); final int pos = i; v.setOnClickListener(view -> mClickListener.onClick(this, pos)); v.setOnLongClickListener(view -> mLongClickListener.onItemLongClick(null, v, pos, 0)); parentView.addView(v); parent.addView(v); } } Loading Loading @@ -1543,9 +1584,9 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, super.show(); mShowing = true; mGradientDrawable.setAlpha(0); mHardwareLayout.setTranslationX(getAnimTranslation()); mHardwareLayout.setAlpha(0); mHardwareLayout.animate() mGlobalActionsLayout.setTranslationX(getAnimTranslation()); mGlobalActionsLayout.setAlpha(0); mGlobalActionsLayout.animate() .alpha(1) .translationX(0) .setDuration(300) Loading @@ -1564,9 +1605,9 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, return; } mShowing = false; mHardwareLayout.setTranslationX(0); mHardwareLayout.setAlpha(1); mHardwareLayout.animate() mGlobalActionsLayout.setTranslationX(0); mGlobalActionsLayout.setAlpha(1); mGlobalActionsLayout.animate() .alpha(0) .translationX(getAnimTranslation()) .setDuration(300) Loading Loading
packages/SystemUI/res/layout/global_actions_wrapped.xml +1 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <com.android.systemui.HardwareUiLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@id/global_actions_view" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="top|right" Loading
packages/SystemUI/res/values/ids.xml +3 −0 Original line number Diff line number Diff line Loading @@ -114,5 +114,8 @@ <item type="id" name="aod_mask_transition_progress_tag" /> <item type="id" name="aod_mask_transition_progress_end_tag" /> <item type="id" name="aod_mask_transition_progress_start_tag" /> <!-- Global Actions Menu --> <item type="id" name="global_actions_view" /> </resources>
packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java +44 −33 Original line number Diff line number Diff line Loading @@ -37,23 +37,25 @@ import com.android.systemui.tuner.TunerService; import com.android.systemui.tuner.TunerService.Tunable; import com.android.systemui.util.leak.RotationUtils; public class HardwareUiLayout extends LinearLayout implements Tunable { /** * 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 View mList; private View mSeparatedView; private ViewGroup mList; private ViewGroup mSeparatedView; private int mOldHeight; private boolean mAnimating; private AnimatorSet mAnimation; private View mDivision; private boolean mHasOutsideTouch; private HardwareBgDrawable mListBackground; private HardwareBgDrawable mSeparatedViewBackground; private Animator mAnimator; private boolean mCollapse; private boolean mHasSeparatedButton; private int mEndPoint; private boolean mEdgeBleed; private boolean mRoundedDivider; Loading @@ -66,6 +68,35 @@ public class HardwareUiLayout extends LinearLayout implements Tunable { 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 public void removeAllItems() { if (mList != null) { mList.removeAllViews(); } if (mSeparatedView != null) { mSeparatedView.removeAllViews(); } } @Override public ViewGroup getParentView(boolean separated, int index) { if (separated) { return getSeparatedView(); } else { return getListView(); } } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); Loading Loading @@ -137,9 +168,9 @@ public class HardwareUiLayout extends LinearLayout implements Tunable { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (mList == null) { if (getChildCount() != 0) { mList = getChildAt(0); mList = getListView(); mList.setBackground(mListBackground); mSeparatedView = getChildAt(1); mSeparatedView = getSeparatedView(); mSeparatedView.setBackground(mSeparatedViewBackground); updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding()); mOldHeight = mList.getMeasuredHeight(); Loading Loading @@ -187,7 +218,7 @@ public class HardwareUiLayout extends LinearLayout implements Tunable { } else { rotateLeft(); } if (mHasSeparatedButton) { if (mHasSeparatedView) { 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. Loading Loading @@ -408,8 +439,8 @@ public class HardwareUiLayout extends LinearLayout implements Tunable { if (mList == null) return; // If got separated button, setRotatedBackground to false, // all items won't get white background. mListBackground.setRotatedBackground(mHasSeparatedButton); mSeparatedViewBackground.setRotatedBackground(mHasSeparatedButton); mListBackground.setRotatedBackground(mHasSeparatedView); mSeparatedViewBackground.setRotatedBackground(mHasSeparatedView); if (mDivision != null && mDivision.getVisibility() == VISIBLE) { int index = mRotatedBackground ? 0 : 1; mDivision.getLocationOnScreen(mTmp2); Loading Loading @@ -460,21 +491,21 @@ public class HardwareUiLayout extends LinearLayout implements Tunable { case RotationUtils.ROTATION_LANDSCAPE: defaultTopPadding = getPaddingLeft(); viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth(); separatedViewTopMargin = mHasSeparatedButton ? params.leftMargin : 0; separatedViewTopMargin = mHasSeparatedView ? params.leftMargin : 0; screenHeight = getMeasuredWidth(); targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.TOP; break; case RotationUtils.ROTATION_SEASCAPE: defaultTopPadding = getPaddingRight(); viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth(); separatedViewTopMargin = mHasSeparatedButton ? params.leftMargin : 0; separatedViewTopMargin = mHasSeparatedView ? params.leftMargin : 0; screenHeight = getMeasuredWidth(); targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.BOTTOM; break; default: // Portrait defaultTopPadding = getPaddingTop(); viewsTotalHeight = mList.getMeasuredHeight() + mSeparatedView.getMeasuredHeight(); separatedViewTopMargin = mHasSeparatedButton ? params.topMargin : 0; separatedViewTopMargin = mHasSeparatedView ? params.topMargin : 0; screenHeight = getMeasuredHeight(); targetGravity = Gravity.CENTER_VERTICAL|Gravity.RIGHT; break; Loading @@ -491,30 +522,10 @@ public class HardwareUiLayout extends LinearLayout implements Tunable { return super.getOutlineProvider(); } public void setOutsideTouchListener(OnClickListener onClickListener) { mHasOutsideTouch = true; requestLayout(); setOnClickListener(onClickListener); setClickable(true); setFocusable(true); } public void setCollapse() { mCollapse = true; } public void setHasSeparatedButton(boolean hasSeparatedButton) { mHasSeparatedButton = hasSeparatedButton; } public static HardwareUiLayout get(View v) { if (v instanceof HardwareUiLayout) return (HardwareUiLayout) v; if (v.getParent() instanceof View) { return get((View) v.getParent()); } return null; } private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsListener = inoutInfo -> { if (mHasOutsideTouch || (mList == null)) { inoutInfo.setTouchableInsets( Loading
packages/SystemUI/src/com/android/systemui/MultiListLayout.java 0 → 100644 +124 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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 android.content.Context; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; /** * Layout class representing the Global Actions menu which appears when the power button is held. */ public abstract class MultiListLayout extends LinearLayout { boolean mHasOutsideTouch; boolean mHasSeparatedView; int mExpectedSeparatedItemCount; int mExpectedListItemCount; public MultiListLayout(Context context, AttributeSet attrs) { super(context, attrs); } protected abstract ViewGroup getSeparatedView(); protected abstract ViewGroup getListView(); /** * Removes all child items from the separated and list views, if they exist. */ public abstract void removeAllItems(); /** * Get the parent view which will be used to contain the item at the specified index. * @param separated Whether or not this index refers to a position in the separated or list * container. * @param index The index of the item within the container. * @return The parent ViewGroup which will be used to contain the specified item * after it has been added to the layout. */ public abstract ViewGroup getParentView(boolean separated, int index); /** * Sets the divided view, which may have a differently-colored background. */ public abstract void setDivisionView(View v); /** * Set the view accessibility delegate for the list view container. */ public void setListViewAccessibilityDelegate(View.AccessibilityDelegate delegate) { getListView().setAccessibilityDelegate(delegate); } protected void setSeparatedViewVisibility(boolean visible) { getSeparatedView().setVisibility(visible ? View.VISIBLE : View.GONE); } /** * Sets the number of items expected to be rendered in the separated container. This allows the * layout to correctly determine which parent containers will be used for items before they have * beenadded to the layout. * @param count The number of items expected. */ public void setExpectedSeparatedItemCount(int count) { mExpectedSeparatedItemCount = count; } /** * Sets the number of items expected to be rendered in the list container. This allows the * layout to correctly determine which parent containers will be used for items before they have * beenadded to the layout. * @param count The number of items expected. */ public void setExpectedListItemCount(int count) { mExpectedListItemCount = count; } /** * Sets whether the separated view should be shown, and handles updating visibility on * that view. */ public void setHasSeparatedView(boolean hasSeparatedView) { mHasSeparatedView = hasSeparatedView; setSeparatedViewVisibility(hasSeparatedView); } /** * Sets this layout to respond to an outside touch listener. */ public void setOutsideTouchListener(OnClickListener onClickListener) { mHasOutsideTouch = true; requestLayout(); setOnClickListener(onClickListener); setClickable(true); setFocusable(true); } /** * Retrieve the MultiListLayout associated with the given view. */ public static MultiListLayout get(View v) { if (v instanceof MultiListLayout) return (MultiListLayout) v; if (v.getParent() instanceof View) { return get((View) v.getParent()); } return null; } }
packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +70 −29 Original line number Diff line number Diff line Loading @@ -67,10 +67,8 @@ import android.view.WindowManagerGlobal; import android.view.accessibility.AccessibilityEvent; import android.widget.AdapterView.OnItemLongClickListener; import android.widget.BaseAdapter; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.ImageView.ScaleType; import android.widget.LinearLayout; import android.widget.TextView; import com.android.internal.R; Loading @@ -86,8 +84,8 @@ import com.android.internal.util.ScreenRecordHelper; import com.android.internal.util.ScreenshotHelper; import com.android.internal.widget.LockPatternUtils; import com.android.systemui.Dependency; import com.android.systemui.HardwareUiLayout; import com.android.systemui.Interpolators; import com.android.systemui.MultiListLayout; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.plugins.GlobalActions.GlobalActionsManager; import com.android.systemui.statusbar.phone.ScrimController; Loading Loading @@ -490,6 +488,11 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, public boolean showBeforeProvisioning() { return true; } @Override public boolean shouldBeSeparated() { return true; } } private final class RestartAction extends SinglePressAction implements LongPressAction { Loading Loading @@ -926,6 +929,34 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, return getItem(position).isEnabled(); } public ArrayList<Action> getSeparatedActions(boolean shouldUseSeparatedView) { ArrayList<Action> separatedActions = new ArrayList<Action>(); if (!shouldUseSeparatedView) { return separatedActions; } for (int i = 0; i < mItems.size(); i++) { final Action action = mItems.get(i); if (action.shouldBeSeparated()) { separatedActions.add(action); } } return separatedActions; } public ArrayList<Action> getListActions(boolean shouldUseSeparatedView) { if (!shouldUseSeparatedView) { return new ArrayList<Action>(mItems); } ArrayList<Action> listActions = new ArrayList<Action>(); for (int i = 0; i < mItems.size(); i++) { final Action action = mItems.get(i); if (!action.shouldBeSeparated()) { listActions.add(action); } } return listActions; } @Override public boolean areAllItemsEnabled() { return false; Loading Loading @@ -965,7 +996,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, View view = action.create(mContext, convertView, parent, LayoutInflater.from(mContext)); // Everything but screenshot, the last item, gets white background. if (position == getCount() - 1) { HardwareUiLayout.get(parent).setDivisionView(view); MultiListLayout.get(parent).setDivisionView(view); } return view; } Loading Loading @@ -1004,6 +1035,10 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, boolean showBeforeProvisioning(); boolean isEnabled(); default boolean shouldBeSeparated() { return false; } } /** Loading Loading @@ -1423,9 +1458,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, private final Context mContext; private final MyAdapter mAdapter; private final LinearLayout mListView; private final FrameLayout mSeparatedView; private final HardwareUiLayout mHardwareLayout; private final MultiListLayout mGlobalActionsLayout; private final OnClickListener mClickListener; private final OnItemLongClickListener mLongClickListener; private final GradientDrawable mGradientDrawable; Loading Loading @@ -1466,16 +1499,11 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY); setContentView(com.android.systemui.R.layout.global_actions_wrapped); mListView = findViewById(android.R.id.list); mSeparatedView = findViewById(com.android.systemui.R.id.separated_button); if (!mShouldDisplaySeparatedButton) { mSeparatedView.setVisibility(View.GONE); } mHardwareLayout = HardwareUiLayout.get(mListView); mHardwareLayout.setOutsideTouchListener(view -> dismiss()); mHardwareLayout.setHasSeparatedButton(mShouldDisplaySeparatedButton); setTitle(R.string.global_actions); mListView.setAccessibilityDelegate(new View.AccessibilityDelegate() { mGlobalActionsLayout = (MultiListLayout) findViewById(com.android.systemui.R.id.global_actions_view); mGlobalActionsLayout.setOutsideTouchListener(view -> dismiss()); mGlobalActionsLayout.setHasSeparatedView(mShouldDisplaySeparatedButton); mGlobalActionsLayout.setListViewAccessibilityDelegate(new View.AccessibilityDelegate() { @Override public boolean dispatchPopulateAccessibilityEvent( View host, AccessibilityEvent event) { Loading @@ -1484,20 +1512,33 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, return true; } }); setTitle(R.string.global_actions); } private void updateList() { mListView.removeAllViews(); mSeparatedView.removeAllViews(); mGlobalActionsLayout.removeAllItems(); ArrayList<Action> separatedActions = mAdapter.getSeparatedActions(mShouldDisplaySeparatedButton); ArrayList<Action> listActions = mAdapter.getListActions(mShouldDisplaySeparatedButton); mGlobalActionsLayout.setExpectedListItemCount(listActions.size()); mGlobalActionsLayout.setExpectedSeparatedItemCount(separatedActions.size()); for (int i = 0; i < mAdapter.getCount(); i++) { ViewGroup parentView = mShouldDisplaySeparatedButton && i == mAdapter.getCount() - 1 ? mSeparatedView : mListView; View v = mAdapter.getView(i, null, parentView); Action action = mAdapter.getItem(i); int separatedIndex = separatedActions.indexOf(action); ViewGroup parent; if (separatedIndex != -1) { parent = mGlobalActionsLayout.getParentView(true, separatedIndex); } else { int listIndex = listActions.indexOf(action); parent = mGlobalActionsLayout.getParentView(false, listIndex); } View v = mAdapter.getView(i, null, parent); final int pos = i; v.setOnClickListener(view -> mClickListener.onClick(this, pos)); v.setOnLongClickListener(view -> mLongClickListener.onItemLongClick(null, v, pos, 0)); parentView.addView(v); parent.addView(v); } } Loading Loading @@ -1543,9 +1584,9 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, super.show(); mShowing = true; mGradientDrawable.setAlpha(0); mHardwareLayout.setTranslationX(getAnimTranslation()); mHardwareLayout.setAlpha(0); mHardwareLayout.animate() mGlobalActionsLayout.setTranslationX(getAnimTranslation()); mGlobalActionsLayout.setAlpha(0); mGlobalActionsLayout.animate() .alpha(1) .translationX(0) .setDuration(300) Loading @@ -1564,9 +1605,9 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, return; } mShowing = false; mHardwareLayout.setTranslationX(0); mHardwareLayout.setAlpha(1); mHardwareLayout.animate() mGlobalActionsLayout.setTranslationX(0); mGlobalActionsLayout.setAlpha(1); mGlobalActionsLayout.animate() .alpha(0) .translationX(getAnimTranslation()) .setDuration(300) Loading