• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui;
18 
19 import android.content.Context;
20 import android.content.res.Configuration;
21 import android.util.AttributeSet;
22 import android.view.View;
23 import android.view.ViewGroup;
24 import android.widget.BaseAdapter;
25 import android.widget.LinearLayout;
26 
27 import com.android.systemui.util.leak.RotationUtils;
28 
29 /**
30  * Layout class representing the Global Actions menu which appears when the power button is held.
31  */
32 public abstract class MultiListLayout extends LinearLayout {
33     protected boolean mHasOutsideTouch;
34     protected MultiListAdapter mAdapter;
35     protected int mRotation;
36     protected RotationListener mRotationListener;
37 
MultiListLayout(Context context, AttributeSet attrs)38     public MultiListLayout(Context context, AttributeSet attrs) {
39         super(context, attrs);
40         mRotation = RotationUtils.getRotation(context);
41     }
42 
getSeparatedView()43     protected abstract ViewGroup getSeparatedView();
44 
getListView()45     protected abstract ViewGroup getListView();
46 
47     /**
48      * Sets the divided view, which may have a differently-colored background.
49      */
setDivisionView(View v)50     public abstract void setDivisionView(View v);
51 
52     /**
53      * Set the view accessibility delegate for the list view container.
54      */
setListViewAccessibilityDelegate(View.AccessibilityDelegate delegate)55     public void setListViewAccessibilityDelegate(View.AccessibilityDelegate delegate) {
56         getListView().setAccessibilityDelegate(delegate);
57     }
58 
setSeparatedViewVisibility(boolean visible)59     protected void setSeparatedViewVisibility(boolean visible) {
60         ViewGroup separatedView = getSeparatedView();
61         if (separatedView != null) {
62             separatedView.setVisibility(visible ? View.VISIBLE : View.GONE);
63         }
64     }
65 
66     /**
67      * Sets the adapter used to inflate items.
68      */
setAdapter(MultiListAdapter adapter)69     public void setAdapter(MultiListAdapter adapter) {
70         mAdapter = adapter;
71     }
72 
73     /**
74      * Sets this layout to respond to an outside touch listener.
75      */
setOutsideTouchListener(OnClickListener onClickListener)76     public void setOutsideTouchListener(OnClickListener onClickListener) {
77         mHasOutsideTouch = true;
78         requestLayout();
79         setOnClickListener(onClickListener);
80         setClickable(true);
81         setFocusable(true);
82     }
83 
84     @Override
onConfigurationChanged(Configuration newConfig)85     protected void onConfigurationChanged(Configuration newConfig) {
86         super.onConfigurationChanged(newConfig);
87         int newRotation = RotationUtils.getRotation(mContext);
88         if (newRotation != mRotation) {
89             rotate(mRotation, newRotation);
90             mRotation = newRotation;
91         }
92     }
93 
rotate(int from, int to)94     protected void rotate(int from, int to) {
95         if (mRotationListener != null) {
96             mRotationListener.onRotate(from, to);
97         }
98     }
99 
100     /**
101      * Update the list of items in both the separated and list views.
102      * For this to work, mAdapter must already have been set.
103      */
updateList()104     public void updateList() {
105         if (mAdapter == null) {
106             throw new IllegalStateException("mAdapter must be set before calling updateList");
107         }
108         onUpdateList();
109     }
110 
removeAllSeparatedViews()111     protected void removeAllSeparatedViews() {
112         ViewGroup separated = getSeparatedView();
113         if (separated != null) {
114             separated.removeAllViews();
115         }
116     }
117 
removeAllListViews()118     protected void removeAllListViews() {
119         ViewGroup list = getListView();
120         if (list != null) {
121             list.removeAllViews();
122         }
123     }
124 
removeAllItems()125     protected void removeAllItems() {
126         removeAllListViews();
127         removeAllSeparatedViews();
128     }
129 
onUpdateList()130     protected void onUpdateList() {
131         removeAllItems();
132         setSeparatedViewVisibility(mAdapter.hasSeparatedItems());
133     }
134 
setRotationListener(RotationListener listener)135     public void setRotationListener(RotationListener listener) {
136         mRotationListener = listener;
137     }
138 
139     /**
140      * Retrieve the MultiListLayout associated with the given view.
141      */
get(View v)142     public static MultiListLayout get(View v) {
143         if (v instanceof MultiListLayout) return (MultiListLayout) v;
144         if (v.getParent() instanceof View) {
145             return get((View) v.getParent());
146         }
147         return null;
148     }
149 
150     /**
151      * Interface to provide callbacks which trigger when this list detects a rotation.
152      */
153     public interface RotationListener {
onRotate(int from, int to)154         void onRotate(int from, int to);
155     }
156 
157     /**
158      * Get the X offset in pixels for use when animating the view onto or off of the screen.
159      */
getAnimationOffsetX()160     public abstract float getAnimationOffsetX();
161 
162     /**
163      * Get the Y offset in pixels for use when animating the view onto or off of the screen.
164      */
getAnimationOffsetY()165     public abstract float getAnimationOffsetY();
166 
167     /**
168      * Adapter class for converting items into child views for MultiListLayout and handling
169      * callbacks for input events.
170      */
171     public abstract static class MultiListAdapter extends BaseAdapter {
172         /**
173          * Counts the number of items to be rendered in the separated view.
174          */
countSeparatedItems()175         public abstract int countSeparatedItems();
176 
177         /**
178          * Counts the number of items be rendered in the list view.
179          */
countListItems()180         public abstract int countListItems();
181 
182         /**
183          * Callback to run when an individual item is clicked or pressed.
184          * @param position The index of the item which was clicked.
185          */
onClickItem(int position)186         public abstract void onClickItem(int position);
187 
188         /**
189          * Callback to run when an individual item is long-clicked or long-pressed.
190          * @param position The index of the item which was long-clicked.
191          * @return True if the long-click was handled, false otherwise.
192          */
onLongClickItem(int position)193         public abstract boolean onLongClickItem(int position);
194 
195         /**
196          * Determines whether the mAdapter contains any separated items, used to determine whether
197          * or not to hide the separated list from view.
198          */
hasSeparatedItems()199         public boolean hasSeparatedItems() {
200             return countSeparatedItems() > 0;
201         }
202 
203         /**
204          * Determines whether the item at the given index should be rendered in the separarted view.
205          * @param position The index of the item.
206          */
shouldBeSeparated(int position)207         public abstract boolean shouldBeSeparated(int position);
208     }
209 }
210