Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c12ed9c8 authored by Aaron Heuckroth's avatar Aaron Heuckroth Committed by Android (Google) Code Review
Browse files

Merge "Refactor MultiListLayout to improve encapsulation."

parents 5ec6a340 57d60d2c
Loading
Loading
Loading
Loading
+34 −15
Original line number Diff line number Diff line
@@ -32,10 +32,13 @@ import android.view.ViewOutlineProvider;
import android.view.ViewTreeObserver;
import android.widget.LinearLayout;

import com.android.systemui.globalactions.GlobalActionsDialog;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
import com.android.systemui.util.leak.RotationUtils;

import java.util.ArrayList;

/**
 * Layout for placing two containers at a specific physical position on the device, relative to the
 * device's hardware, regardless of screen rotation.
@@ -89,15 +92,6 @@ public class HardwareUiLayout extends MultiListLayout implements Tunable {
        }
    }

    @Override
    public ViewGroup getParentView(boolean separated, int index, int rotation) {
        if (separated) {
            return getSeparatedView();
        } else {
            return getListView();
        }
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
@@ -221,7 +215,7 @@ public class HardwareUiLayout extends MultiListLayout implements Tunable {
        } else {
            rotateLeft();
        }
        if (mHasSeparatedView) {
        if (mSeparated) {
            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.
@@ -261,6 +255,31 @@ public class HardwareUiLayout extends MultiListLayout implements Tunable {
        }
    }

    @Override
    public void onUpdateList() {
        removeAllItems();
        ArrayList<GlobalActionsDialog.Action> separatedActions =
                mAdapter.getSeparatedItems(mSeparated);
        ArrayList<GlobalActionsDialog.Action> listActions = mAdapter.getListItems(mSeparated);

        for (int i = 0; i < mAdapter.getCount(); i++) {
            Object action = mAdapter.getItem(i);
            int separatedIndex = separatedActions.indexOf(action);
            ViewGroup parent;
            if (separatedIndex != -1) {
                parent = getSeparatedView();
            } else {
                int listIndex = listActions.indexOf(action);
                parent = getListView();
            }
            View v = mAdapter.getView(i, null, parent);
            final int pos = i;
            v.setOnClickListener(view -> mAdapter.onClickItem(pos));
            v.setOnLongClickListener(view -> mAdapter.onLongClickItem(pos));
            parent.addView(v);
        }
    }

    private void rotateRight() {
        rotateRight(this);
        rotateRight(mList);
@@ -442,8 +461,8 @@ public class HardwareUiLayout extends MultiListLayout implements Tunable {
        if (mList == null) return;
        // If got separated button, setRotatedBackground to false,
        // all items won't get white background.
        mListBackground.setRotatedBackground(mHasSeparatedView);
        mSeparatedViewBackground.setRotatedBackground(mHasSeparatedView);
        mListBackground.setRotatedBackground(mSeparated);
        mSeparatedViewBackground.setRotatedBackground(mSeparated);
        if (mDivision != null && mDivision.getVisibility() == VISIBLE) {
            int index = mRotatedBackground ? 0 : 1;
            mDivision.getLocationOnScreen(mTmp2);
@@ -494,21 +513,21 @@ public class HardwareUiLayout extends MultiListLayout implements Tunable {
            case RotationUtils.ROTATION_LANDSCAPE:
                defaultTopPadding = getPaddingLeft();
                viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth();
                separatedViewTopMargin = mHasSeparatedView ? params.leftMargin : 0;
                separatedViewTopMargin = mSeparated ? params.leftMargin : 0;
                screenHeight = getMeasuredWidth();
                targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.TOP;
                break;
            case RotationUtils.ROTATION_SEASCAPE:
                defaultTopPadding = getPaddingRight();
                viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth();
                separatedViewTopMargin = mHasSeparatedView ? params.leftMargin : 0;
                separatedViewTopMargin = mSeparated ? params.leftMargin : 0;
                screenHeight = getMeasuredWidth();
                targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.BOTTOM;
                break;
            default: // Portrait
                defaultTopPadding = getPaddingTop();
                viewsTotalHeight = mList.getMeasuredHeight() + mSeparatedView.getMeasuredHeight();
                separatedViewTopMargin = mHasSeparatedView ? params.topMargin : 0;
                separatedViewTopMargin = mSeparated ? params.topMargin : 0;
                screenHeight = getMeasuredHeight();
                targetGravity = Gravity.CENTER_VERTICAL|Gravity.RIGHT;
                break;
+57 −37
Original line number Diff line number Diff line
@@ -21,19 +21,20 @@ import android.content.res.Configuration;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.LinearLayout;

import com.android.systemui.util.leak.RotationUtils;

import java.util.ArrayList;

/**
 * Layout class representing the Global Actions menu which appears when the power button is held.
 */
public abstract class MultiListLayout extends LinearLayout {
    protected boolean mHasOutsideTouch;
    protected boolean mHasSeparatedView;

    protected int mExpectedSeparatedItemCount;
    protected int mExpectedListItemCount;
    protected boolean mSeparated;
    protected MultiListAdapter mAdapter;

    protected int mRotation;
    protected RotationListener mRotationListener;
@@ -52,18 +53,6 @@ public abstract class MultiListLayout extends LinearLayout {
     */
    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.
     * @param rotation Specifies the rotation of the device, which is used in some cases to
     *                 determine child ordering.
     * @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, int rotation);

    /**
     * Sets the divided view, which may have a differently-colored background.
     */
@@ -81,32 +70,19 @@ public abstract class MultiListLayout extends LinearLayout {
    }

    /**
     * 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.
     * Sets whether the separated view should be shown, and handles updating visibility on
     * that view.
     */
    public void setExpectedListItemCount(int count) {
        mExpectedListItemCount = count;
    public void setSeparated(boolean separated) {
        mSeparated = separated;
        setSeparatedViewVisibility(separated);
    }

    /**
     * Sets whether the separated view should be shown, and handles updating visibility on
     * that view.
     * Sets the adapter used to inflate items.
     */
    public void setHasSeparatedView(boolean hasSeparatedView) {
        mHasSeparatedView = hasSeparatedView;
        setSeparatedViewVisibility(hasSeparatedView);
    public void setAdapter(MultiListAdapter adapter) {
        mAdapter = adapter;
    }

    /**
@@ -136,6 +112,19 @@ public abstract class MultiListLayout extends LinearLayout {
        }
    }

    /**
     * Update the list of items in both the separated and list views.
     * For this to work, mAdapter must already have been set.
     */
    public void updateList() {
        if (mAdapter == null) {
            throw new IllegalStateException("mAdapter must be set before calling updateList");
        }
        onUpdateList();
    }

    protected abstract void onUpdateList();

    public void setRotationListener(RotationListener listener) {
        mRotationListener = listener;
    }
@@ -157,4 +146,35 @@ public abstract class MultiListLayout extends LinearLayout {
    public interface RotationListener {
        void onRotate(int from, int to);
    }

    /**
     * Adapter class for converting items into child views for MultiListLayout and handling
     * callbacks for input events.
     */
    public abstract static class MultiListAdapter extends BaseAdapter {
        /**
         * Creates an ArrayList of items which should be rendered in the separated view.
         * @param useSeparatedView is true if the separated view will be used, false otherwise.
         */
        public abstract ArrayList getSeparatedItems(boolean useSeparatedView);

        /**
         * Creates an ArrayList of items which should be rendered in the list view.
         * @param useSeparatedView True if the separated view will be used, false otherwise.
         */
        public abstract ArrayList getListItems(boolean useSeparatedView);

        /**
         * Callback to run when an individual item is clicked or pressed.
         * @param position The index of the item which was clicked.
         */
        public abstract void onClickItem(int position);

        /**
         * Callback to run when an individual item is long-clicked or long-pressed.
         * @param position The index of the item which was long-clicked.
         * @return True if the long-click was handled, false otherwise.
         */
        public abstract boolean onLongClickItem(int position);
    }
}
+46 −92
Original line number Diff line number Diff line
@@ -65,8 +65,6 @@ import android.view.Window;
import android.view.WindowManager;
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;
@@ -87,6 +85,7 @@ import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.MultiListLayout;
import com.android.systemui.MultiListLayout.MultiListAdapter;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
import com.android.systemui.plugins.GlobalActionsPanelPlugin;
@@ -99,16 +98,14 @@ import com.android.systemui.volume.SystemUIInterpolators.LogAccelerateInterpolat

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

/**
 * Helper to show the global actions dialog.  Each item is an {@link Action} that
 * may show depending on whether the keyguard is showing, and whether the device
 * is provisioned.
 */
class GlobalActionsDialog implements DialogInterface.OnDismissListener,
        DialogInterface.OnClickListener, DialogInterface.OnShowListener,
        ConfigurationController.ConfigurationListener {
public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
        DialogInterface.OnShowListener, ConfigurationController.ConfigurationListener {

    static public final String SYSTEM_DIALOG_REASON_KEY = "reason";
    static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";
@@ -158,7 +155,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
    private boolean mHasVibrator;
    private boolean mHasLogoutButton;
    private boolean mHasLockdownButton;
    private boolean mSeparatedEmergencyButtonEnabled;
    private boolean mUseSeparatedList;
    private final boolean mShowSilentToggle;
    private final EmergencyAffordanceManager mEmergencyAffordanceManager;
    private final ScreenshotHelper mScreenshotHelper;
@@ -336,7 +333,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
        ArraySet<String> addedKeys = new ArraySet<String>();
        mHasLogoutButton = false;
        mHasLockdownButton = false;
        mSeparatedEmergencyButtonEnabled = true;
        mUseSeparatedList = true;
        for (int i = 0; i < defaultActions.length; i++) {
            String actionKey = defaultActions[i];
            if (addedKeys.contains(actionKey)) {
@@ -384,7 +381,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
                    mHasLogoutButton = true;
                }
            } else if (GLOBAL_ACTION_KEY_EMERGENCY.equals(actionKey)) {
                if (mSeparatedEmergencyButtonEnabled
                if (mUseSeparatedList
                        && !mEmergencyAffordanceManager.needsEmergencyAffordance()) {
                    mItems.add(new EmergencyDialerAction());
                }
@@ -401,14 +398,6 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,

        mAdapter = new MyAdapter();

        OnItemLongClickListener onItemLongClickListener = (parent, view, position, id) -> {
            final Action action = mAdapter.getItem(position);
            if (action instanceof LongPressAction) {
                mDialog.dismiss();
                return ((LongPressAction) action).onLongPress();
            }
            return false;
        };
        GlobalActionsPanelPlugin.PanelViewController panelViewController =
                mPanelExtension.get() != null
                        ? mPanelExtension.get().onPanelShown(() -> {
@@ -417,8 +406,8 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
                            }
                        })
                        : null;
        ActionsDialog dialog = new ActionsDialog(mContext, this, mAdapter, onItemLongClickListener,
                mSeparatedEmergencyButtonEnabled, panelViewController);
        ActionsDialog dialog = new ActionsDialog(mContext, mAdapter, mUseSeparatedList,
                panelViewController);
        dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.
        dialog.setKeyguardShowing(mKeyguardShowing);

@@ -548,7 +537,6 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
        }
    }


    private class ScreenshotAction extends SinglePressAction implements LongPressAction {
        public ScreenshotAction() {
            super(R.drawable.ic_screenshot, R.string.global_action_screenshot);
@@ -713,7 +701,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,

    private Action getEmergencyAction() {
        Drawable emergencyIcon = mContext.getDrawable(R.drawable.emergency_icon);
        if(!mSeparatedEmergencyButtonEnabled) {
        if (!mUseSeparatedList) {
            // use un-colored legacy treatment
            emergencyIcon.setTintList(null);
        }
@@ -906,15 +894,6 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
        }
    }

    /** {@inheritDoc} */
    public void onClick(DialogInterface dialog, int which) {
        Action item = mAdapter.getItem(which);
        if (!(item instanceof SilentModeTriStateAction)) {
            dialog.dismiss();
        }
        item.onPress();
    }

    /** {@inheritDoc} */
    public void onShow(DialogInterface dialog) {
        MetricsLogger.visible(mContext, MetricsEvent.POWER_MENU);
@@ -927,11 +906,10 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
     * the device is provisioned
     * via {@link com.android.systemui.globalactions.GlobalActionsDialog#mDeviceProvisioned}.
     */
    private class MyAdapter extends BaseAdapter {

    public class MyAdapter extends MultiListAdapter {
        @Override
        public int getCount() {
            int count = 0;

            for (int i = 0; i < mItems.size(); i++) {
                final Action action = mItems.get(i);

@@ -951,7 +929,8 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
            return getItem(position).isEnabled();
        }

        public ArrayList<Action> getSeparatedActions(boolean shouldUseSeparatedView) {
        @Override
        public ArrayList<Action> getSeparatedItems(boolean shouldUseSeparatedView) {
            ArrayList<Action> separatedActions = new ArrayList<Action>();
            if (!shouldUseSeparatedView) {
                return separatedActions;
@@ -965,7 +944,8 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
            return separatedActions;
        }

        public ArrayList<Action> getListActions(boolean shouldUseSeparatedView) {
        @Override
        public ArrayList<Action> getListItems(boolean shouldUseSeparatedView) {
            if (!shouldUseSeparatedView) {
                return new ArrayList<Action>(mItems);
            }
@@ -984,6 +964,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
            return false;
        }

        @Override
        public Action getItem(int position) {

            int filteredPos = 0;
@@ -1013,6 +994,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            Action action = getItem(position);
            View view = action.create(mContext, convertView, parent, LayoutInflater.from(mContext));
@@ -1022,6 +1004,25 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
            }
            return view;
        }

        @Override
        public boolean onLongClickItem(int position) {
            final Action action = mAdapter.getItem(position);
            if (action instanceof LongPressAction) {
                mDialog.dismiss();
                return ((LongPressAction) action).onLongPress();
            }
            return false;
        }

        @Override
        public void onClickItem(int position) {
            Action item = mAdapter.getItem(position);
            if (!(item instanceof SilentModeTriStateAction)) {
                mDialog.dismiss();
            }
            item.onPress();
        }
    }

    // note: the scheme below made more sense when we were planning on having
@@ -1033,7 +1034,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
    /**
     * What each item in the global actions dialog must be able to support.
     */
    private interface Action {
    public interface Action {
        /**
         * @return Text that will be announced when dialog is created.  null
         * for none.
@@ -1052,7 +1053,8 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,

        /**
         * @return whether this action should appear in the dialog before the
         * device is provisioned.
         * device is provisioned.onlongpress
         *
         */
        boolean showBeforeProvisioning();

@@ -1488,26 +1490,21 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
        private final Context mContext;
        private final MyAdapter mAdapter;
        private MultiListLayout mGlobalActionsLayout;
        private final OnClickListener mClickListener;
        private final OnItemLongClickListener mLongClickListener;
        private final Drawable mBackgroundDrawable;
        private final ColorExtractor mColorExtractor;
        private final GlobalActionsPanelPlugin.PanelViewController mPanelController;
        private boolean mKeyguardShowing;
        private boolean mShouldDisplaySeparatedButton;
        private boolean mUseSeparatedList;
        private boolean mShowing;
        private final float mScrimAlpha;

        public ActionsDialog(Context context, OnClickListener clickListener, MyAdapter adapter,
                OnItemLongClickListener longClickListener, boolean shouldDisplaySeparatedButton,
        ActionsDialog(Context context, MyAdapter adapter, boolean separated,
                GlobalActionsPanelPlugin.PanelViewController plugin) {
            super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions);
            mContext = context;
            mAdapter = adapter;
            mClickListener = clickListener;
            mLongClickListener = longClickListener;
            mColorExtractor = Dependency.get(SysuiColorExtractor.class);
            mShouldDisplaySeparatedButton = shouldDisplaySeparatedButton;
            mUseSeparatedList = separated;

            // Window initialization
            Window window = getWindow();
@@ -1573,7 +1570,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
            mGlobalActionsLayout = (MultiListLayout)
                    findViewById(com.android.systemui.R.id.global_actions_view);
            mGlobalActionsLayout.setOutsideTouchListener(view -> dismiss());
            mGlobalActionsLayout.setHasSeparatedView(mShouldDisplaySeparatedButton);
            mGlobalActionsLayout.setSeparated(mUseSeparatedList);
            mGlobalActionsLayout.setListViewAccessibilityDelegate(new View.AccessibilityDelegate() {
                @Override
                public boolean dispatchPopulateAccessibilityEvent(
@@ -1584,6 +1581,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
                }
            });
            mGlobalActionsLayout.setRotationListener(this::onRotate);
            mGlobalActionsLayout.setAdapter(mAdapter);
        }

        private boolean isPanelEnabled(Context context) {
@@ -1601,55 +1599,11 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
            return com.android.systemui.R.layout.global_actions_wrapped;
        }

        private void updateList() {
            mGlobalActionsLayout.removeAllItems();
            ArrayList<Action> separatedActions =
                    mAdapter.getSeparatedActions(mShouldDisplaySeparatedButton);
            ArrayList<Action> listActions = mAdapter.getListActions(mShouldDisplaySeparatedButton);
            mGlobalActionsLayout.setExpectedListItemCount(listActions.size());
            mGlobalActionsLayout.setExpectedSeparatedItemCount(separatedActions.size());
            int rotation = RotationUtils.getRotation(mContext);

            boolean reverse = false; // should we add items to parents in the reverse order?
            if (isGridEnabled(mContext)) {
                if (rotation == RotationUtils.ROTATION_NONE
                        || rotation == RotationUtils.ROTATION_SEASCAPE) {
                    reverse = !reverse; // if we're in portrait or seascape, reverse items
                }
                if (TextUtils.getLayoutDirectionFromLocale(Locale.getDefault())
                        == View.LAYOUT_DIRECTION_RTL) {
                    reverse = !reverse; // if we're in an RTL language, reverse items (again)
                }
            }

            for (int i = 0; i < mAdapter.getCount(); i++) {
                Action action = mAdapter.getItem(i);
                int separatedIndex = separatedActions.indexOf(action);
                ViewGroup parent;
                if (separatedIndex != -1) {
                    parent = mGlobalActionsLayout.getParentView(true, separatedIndex, rotation);
                } else {
                    int listIndex = listActions.indexOf(action);
                    parent = mGlobalActionsLayout.getParentView(false, listIndex, rotation);
                }
                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));
                if (reverse) {
                    parent.addView(v, 0); // reverse order of items
                } else {
                    parent.addView(v);
                }
            }
        }

        @Override
        protected void onStart() {
            super.setCanceledOnTouchOutside(true);
            super.onStart();
            updateList();
            mGlobalActionsLayout.updateList();

            if (mBackgroundDrawable instanceof GradientDrawable) {
                Point displaySize = new Point();
@@ -1767,7 +1721,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
        public void onRotate(int from, int to) {
            if (mShowing && isGridEnabled(mContext)) {
                initializeLayout();
                updateList();
                mGlobalActionsLayout.updateList();
            }
        }
    }
+51 −3

File changed.

Preview size limit exceeded, changes collapsed.

+1 −3
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@ package com.android.systemui.globalactions;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
@@ -39,6 +38,7 @@ import android.widget.LinearLayout;
 */

public class ListGridLayout extends LinearLayout {
    private static final String TAG = "ListGridLayout";
    private int mExpectedCount;
    private int mRows;
    private int mColumns;
@@ -103,12 +103,10 @@ public class ListGridLayout extends LinearLayout {
                setSublistVisibility(i, false);
            }
        }

    }

    private void setSublistVisibility(int index, boolean visible) {
        View subList = getChildAt(index);
        Log.d("ListGrid", "index: " + index  + ", visibility: "  + visible);
        if (subList != null) {
            subList.setVisibility(visible ? View.VISIBLE : View.GONE);
        }