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.globalactions;
18 
19 import android.content.Context;
20 import android.text.TextUtils;
21 import android.util.AttributeSet;
22 import android.view.View;
23 import android.view.ViewGroup;
24 
25 import com.android.internal.annotations.VisibleForTesting;
26 import com.android.systemui.HardwareBgDrawable;
27 import com.android.systemui.MultiListLayout;
28 import com.android.systemui.R;
29 import com.android.systemui.util.leak.RotationUtils;
30 
31 import java.util.Locale;
32 
33 /**
34  * Grid-based implementation of the button layout created by the global actions dialog.
35  */
36 public abstract class GlobalActionsLayout extends MultiListLayout {
37 
38     boolean mBackgroundsSet;
39 
GlobalActionsLayout(Context context, AttributeSet attrs)40     public GlobalActionsLayout(Context context, AttributeSet attrs) {
41         super(context, attrs);
42     }
43 
setBackgrounds()44     private void setBackgrounds() {
45         ViewGroup listView = getListView();
46         int listBgColor = getResources().getColor(
47                 R.color.global_actions_grid_background, null);
48         HardwareBgDrawable listBackground = getBackgroundDrawable(listBgColor);
49         if (listBackground != null) {
50             listView.setBackground(listBackground);
51         }
52 
53         ViewGroup separatedView = getSeparatedView();
54 
55         if (separatedView != null) {
56             int separatedBgColor = getResources().getColor(
57                     R.color.global_actions_separated_background, null);
58             HardwareBgDrawable separatedBackground = getBackgroundDrawable(separatedBgColor);
59             if (separatedBackground != null) {
60                 getSeparatedView().setBackground(separatedBackground);
61             }
62         }
63     }
64 
getBackgroundDrawable(int backgroundColor)65     protected HardwareBgDrawable getBackgroundDrawable(int backgroundColor) {
66         HardwareBgDrawable background = new HardwareBgDrawable(true, true, getContext());
67         background.setTint(backgroundColor);
68         return background;
69     }
70 
71     @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)72     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
73         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
74 
75         // backgrounds set only once, the first time onMeasure is called after inflation
76         if (getListView() != null && !mBackgroundsSet) {
77             setBackgrounds();
78             mBackgroundsSet = true;
79         }
80     }
81 
addToListView(View v, boolean reverse)82     protected void addToListView(View v, boolean reverse) {
83         if (reverse) {
84             getListView().addView(v, 0);
85         } else {
86             getListView().addView(v);
87         }
88     }
89 
addToSeparatedView(View v, boolean reverse)90     protected void addToSeparatedView(View v, boolean reverse) {
91         ViewGroup separated = getSeparatedView();
92         if (separated != null) {
93             if (reverse) {
94                 separated.addView(v, 0);
95             } else {
96                 separated.addView(v);
97             }
98         } else {
99             // if no separated view exists, just use the list view
100             addToListView(v, reverse);
101         }
102     }
103 
104     @VisibleForTesting
getCurrentLayoutDirection()105     protected int getCurrentLayoutDirection() {
106         return TextUtils.getLayoutDirectionFromLocale(Locale.getDefault());
107     }
108 
109     @VisibleForTesting
getCurrentRotation()110     protected int getCurrentRotation() {
111         return RotationUtils.getRotation(mContext);
112     }
113 
114     /**
115      * Determines whether the ListGridLayout should reverse the ordering of items within sublists.
116      * Used for RTL languages to ensure that items appear in the same positions, without having to
117      * override layoutDirection, which breaks Talkback ordering.
118      */
shouldReverseListItems()119     protected abstract boolean shouldReverseListItems();
120 
121     @Override
onUpdateList()122     public void onUpdateList() {
123         super.onUpdateList();
124 
125         ViewGroup separatedView = getSeparatedView();
126         ViewGroup listView = getListView();
127 
128         for (int i = 0; i < mAdapter.getCount(); i++) {
129             // generate the view item
130             View v;
131             boolean separated = mAdapter.shouldBeSeparated(i);
132             if (separated) {
133                 v = mAdapter.getView(i, null, separatedView);
134             } else {
135                 v = mAdapter.getView(i, null, listView);
136             }
137             if (separated) {
138                 addToSeparatedView(v, false);
139             } else {
140                 addToListView(v, shouldReverseListItems());
141             }
142         }
143     }
144 
145     @Override
getSeparatedView()146     protected ViewGroup getSeparatedView() {
147         return findViewById(R.id.separated_button);
148     }
149 
150     @Override
getListView()151     protected ViewGroup getListView() {
152         return findViewById(android.R.id.list);
153     }
154 
getWrapper()155     protected View getWrapper() {
156         return getChildAt(0);
157     }
158 
159     /**
160      * Not used in this implementation of the Global Actions Menu, but necessary for some others.
161      */
162     @Override
setDivisionView(View v)163     public void setDivisionView(View v) {
164         // do nothing
165     }
166 }
167