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 static junit.framework.Assert.assertEquals;
20 
21 import static org.mockito.ArgumentMatchers.any;
22 import static org.mockito.ArgumentMatchers.eq;
23 import static org.mockito.Mockito.doReturn;
24 import static org.mockito.Mockito.spy;
25 
26 import android.content.Context;
27 import android.testing.AndroidTestingRunner;
28 import android.util.AttributeSet;
29 import android.view.View;
30 import android.view.ViewGroup;
31 
32 import androidx.test.filters.SmallTest;
33 
34 import com.android.systemui.MultiListLayout;
35 import com.android.systemui.SysuiTestCase;
36 
37 import org.junit.Before;
38 import org.junit.Test;
39 import org.junit.runner.RunWith;
40 
41 import java.util.ArrayList;
42 
43 /**
44  * Tests for {@link ListGridLayout}.
45  */
46 @SmallTest
47 @RunWith(AndroidTestingRunner.class)
48 public class GlobalActionsLayoutTest extends SysuiTestCase {
49 
50     private TestLayout mLayout;
51     private TestAdapter mAdapter;
52 
53     private class TestAdapter extends MultiListLayout.MultiListAdapter {
54         @Override
onClickItem(int index)55         public void onClickItem(int index) { }
56 
57         @Override
onLongClickItem(int index)58         public boolean onLongClickItem(int index) {
59             return true;
60         }
61 
62         @Override
countSeparatedItems()63         public int countSeparatedItems() {
64             return -1;
65         }
66 
67         @Override
countListItems()68         public int countListItems() {
69             return -1;
70         }
71 
72         @Override
shouldBeSeparated(int position)73         public boolean shouldBeSeparated(int position) {
74             return false;
75         }
76 
77         @Override
getCount()78         public int getCount() {
79             return countSeparatedItems() + countListItems();
80         }
81 
82         @Override
getItem(int position)83         public Object getItem(int position) {
84             return null;
85         }
86 
87         @Override
getItemId(int position)88         public long getItemId(int position) {
89             return -1;
90         }
91 
92         @Override
getView(int position, View convertView, ViewGroup parent)93         public View getView(int position, View convertView, ViewGroup parent) {
94             return null;
95         }
96     }
97 
98     private class TestLayout extends GlobalActionsLayout {
99         ArrayList<View> mSeparatedViews = new ArrayList<>();
100         ArrayList<View> mListViews = new ArrayList<>();
101         boolean mSeparatedViewVisible = false;
102 
TestLayout(Context context, AttributeSet attrs)103         TestLayout(Context context, AttributeSet attrs) {
104             super(context, attrs);
105         }
106 
107         @Override
shouldReverseListItems()108         protected boolean shouldReverseListItems() {
109             return false;
110         }
111 
112         @Override
getAnimationOffsetX()113         public float getAnimationOffsetX() {
114             return 0;
115         }
116 
117         @Override
getAnimationOffsetY()118         public float getAnimationOffsetY() {
119             return 0;
120         }
121 
122         @Override
addToListView(View v, boolean reverse)123         protected void addToListView(View v, boolean reverse) {
124             if (reverse) {
125                 mListViews.add(0, v);
126             } else {
127                 mListViews.add(v);
128             }
129         }
130 
131         @Override
addToSeparatedView(View v, boolean reverse)132         protected void addToSeparatedView(View v, boolean reverse) {
133             if (reverse) {
134                 mSeparatedViews.add(0, v);
135             } else {
136                 mSeparatedViews.add(v);
137             }
138         }
139 
140         @Override
setSeparatedViewVisibility(boolean visible)141         protected void setSeparatedViewVisibility(boolean visible) {
142             mSeparatedViewVisible = visible;
143         }
144     }
145 
146     @Before
setUp()147     public void setUp() throws Exception {
148         mLayout = spy(new TestLayout(mContext, null));
149         mAdapter = spy(new TestAdapter());
150         mLayout.setAdapter(mAdapter);
151     }
152 
153     @Test(expected = IllegalStateException.class)
testOnUpdateList_noAdapter()154     public void testOnUpdateList_noAdapter() {
155         mLayout.setAdapter(null);
156         mLayout.updateList();
157     }
158 
159     @Test
testOnUpdateList_noItems()160     public void testOnUpdateList_noItems() {
161         doReturn(0).when(mAdapter).countSeparatedItems();
162         doReturn(0).when(mAdapter).countListItems();
163         mLayout.updateList();
164 
165         assertEquals(0, mLayout.mSeparatedViews.size());
166         assertEquals(0, mLayout.mListViews.size());
167 
168         assertEquals(false, mLayout.mSeparatedViewVisible);
169     }
170 
171     @Test
testOnUpdateList_oneSeparatedOneList()172     public void testOnUpdateList_oneSeparatedOneList() {
173         doReturn(1).when(mAdapter).countSeparatedItems();
174         doReturn(1).when(mAdapter).countListItems();
175         View view1 = new View(mContext, null);
176         View view2 = new View(mContext, null);
177 
178         doReturn(view1).when(mAdapter).getView(eq(0), any(), any());
179         doReturn(true).when(mAdapter).shouldBeSeparated(0);
180 
181         doReturn(view2).when(mAdapter).getView(eq(1), any(), any());
182         doReturn(false).when(mAdapter).shouldBeSeparated(1);
183 
184         mLayout.updateList();
185 
186         assertEquals(1, mLayout.mSeparatedViews.size());
187         assertEquals(1, mLayout.mListViews.size());
188         assertEquals(view1, mLayout.mSeparatedViews.get(0));
189         assertEquals(view2, mLayout.mListViews.get(0));
190     }
191 
192 
193     @Test
testOnUpdateList_twoSeparatedItems()194     public void testOnUpdateList_twoSeparatedItems() {
195         doReturn(2).when(mAdapter).countSeparatedItems();
196         doReturn(0).when(mAdapter).countListItems();
197         View view1 = new View(mContext, null);
198         View view2 = new View(mContext, null);
199 
200         doReturn(view1).when(mAdapter).getView(eq(0), any(), any());
201         doReturn(true).when(mAdapter).shouldBeSeparated(0);
202         doReturn(view2).when(mAdapter).getView(eq(1), any(), any());
203         doReturn(true).when(mAdapter).shouldBeSeparated(1);
204 
205         mLayout.updateList();
206 
207         assertEquals(2, mLayout.mSeparatedViews.size());
208         assertEquals(0, mLayout.mListViews.size());
209 
210         assertEquals(view1, mLayout.mSeparatedViews.get(0));
211         assertEquals(view2, mLayout.mSeparatedViews.get(1));
212 
213         // if separated view has items in it, should be made visible
214         assertEquals(true, mLayout.mSeparatedViewVisible);
215     }
216 
217     @Test
testOnUpdateList_twoSeparatedItems_reverse()218     public void testOnUpdateList_twoSeparatedItems_reverse() {
219         doReturn(2).when(mAdapter).countSeparatedItems();
220         doReturn(0).when(mAdapter).countListItems();
221         doReturn(true).when(mLayout).shouldReverseListItems();
222         View view1 = new View(mContext, null);
223         View view2 = new View(mContext, null);
224 
225         doReturn(view1).when(mAdapter).getView(eq(0), any(), any());
226         doReturn(true).when(mAdapter).shouldBeSeparated(0);
227 
228         doReturn(view2).when(mAdapter).getView(eq(1), any(), any());
229         doReturn(true).when(mAdapter).shouldBeSeparated(1);
230 
231         mLayout.updateList();
232 
233         assertEquals(2, mLayout.mSeparatedViews.size());
234         assertEquals(0, mLayout.mListViews.size());
235 
236         // separated view items are not reversed in current implementation, and this is intentional!
237         assertEquals(view1, mLayout.mSeparatedViews.get(0));
238         assertEquals(view2, mLayout.mSeparatedViews.get(1));
239     }
240 
241     @Test
testOnUpdateList_fourInList()242     public void testOnUpdateList_fourInList() {
243         doReturn(0).when(mAdapter).countSeparatedItems();
244         doReturn(4).when(mAdapter).countListItems();
245         View view1 = new View(mContext, null);
246         View view2 = new View(mContext, null);
247         View view3 = new View(mContext, null);
248         View view4 = new View(mContext, null);
249 
250         doReturn(view1).when(mAdapter).getView(eq(0), any(), any());
251         doReturn(false).when(mAdapter).shouldBeSeparated(0);
252 
253         doReturn(view2).when(mAdapter).getView(eq(1), any(), any());
254         doReturn(false).when(mAdapter).shouldBeSeparated(1);
255 
256         doReturn(view3).when(mAdapter).getView(eq(2), any(), any());
257         doReturn(false).when(mAdapter).shouldBeSeparated(2);
258 
259         doReturn(view4).when(mAdapter).getView(eq(3), any(), any());
260         doReturn(false).when(mAdapter).shouldBeSeparated(3);
261 
262         mLayout.updateList();
263 
264         assertEquals(0, mLayout.mSeparatedViews.size());
265         assertEquals(4, mLayout.mListViews.size());
266         assertEquals(view1, mLayout.mListViews.get(0));
267         assertEquals(view2, mLayout.mListViews.get(1));
268         assertEquals(view3, mLayout.mListViews.get(2));
269         assertEquals(view4, mLayout.mListViews.get(3));
270     }
271 
272     @Test
testOnUpdateList_fourInList_reverse()273     public void testOnUpdateList_fourInList_reverse() {
274         doReturn(0).when(mAdapter).countSeparatedItems();
275         doReturn(4).when(mAdapter).countListItems();
276         doReturn(true).when(mLayout).shouldReverseListItems();
277         View view1 = new View(mContext, null);
278         View view2 = new View(mContext, null);
279         View view3 = new View(mContext, null);
280         View view4 = new View(mContext, null);
281 
282         doReturn(view1).when(mAdapter).getView(eq(0), any(), any());
283         doReturn(false).when(mAdapter).shouldBeSeparated(0);
284 
285         doReturn(view2).when(mAdapter).getView(eq(1), any(), any());
286         doReturn(false).when(mAdapter).shouldBeSeparated(1);
287 
288         doReturn(view3).when(mAdapter).getView(eq(2), any(), any());
289         doReturn(false).when(mAdapter).shouldBeSeparated(2);
290 
291         doReturn(view4).when(mAdapter).getView(eq(3), any(), any());
292         doReturn(false).when(mAdapter).shouldBeSeparated(3);
293 
294         mLayout.updateList();
295 
296         assertEquals(0, mLayout.mSeparatedViews.size());
297         assertEquals(4, mLayout.mListViews.size());
298         assertEquals(view1, mLayout.mListViews.get(3));
299         assertEquals(view2, mLayout.mListViews.get(2));
300         assertEquals(view3, mLayout.mListViews.get(1));
301         assertEquals(view4, mLayout.mListViews.get(0));
302     }
303 }
304