1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5  * except in compliance with the License. You may obtain a copy of the License at
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the
10  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11  * KIND, either express or implied. See the License for the specific language governing
12  * permissions and limitations under the License.
13  */
14 
15 package com.android.systemui.qs;
16 
17 import static com.android.systemui.statusbar.phone.AutoTileManager.SAVER;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertTrue;
22 import static org.mockito.ArgumentMatchers.eq;
23 import static org.mockito.Mockito.any;
24 import static org.mockito.Mockito.anyInt;
25 import static org.mockito.Mockito.never;
26 import static org.mockito.Mockito.verify;
27 
28 import android.content.BroadcastReceiver;
29 import android.content.Intent;
30 import android.content.IntentFilter;
31 import android.os.UserHandle;
32 import android.provider.Settings.Secure;
33 import android.testing.AndroidTestingRunner;
34 import android.testing.TestableLooper.RunWithLooper;
35 
36 import androidx.test.filters.SmallTest;
37 
38 import com.android.systemui.SysuiTestCase;
39 import com.android.systemui.broadcast.BroadcastDispatcher;
40 import com.android.systemui.dump.DumpManager;
41 import com.android.systemui.util.settings.FakeSettings;
42 import com.android.systemui.util.settings.SecureSettings;
43 
44 import org.junit.Before;
45 import org.junit.Test;
46 import org.junit.runner.RunWith;
47 import org.mockito.ArgumentCaptor;
48 import org.mockito.Captor;
49 import org.mockito.InOrder;
50 import org.mockito.Mock;
51 import org.mockito.Mockito;
52 import org.mockito.MockitoAnnotations;
53 
54 import java.util.List;
55 import java.util.concurrent.Executor;
56 
57 @RunWith(AndroidTestingRunner.class)
58 @RunWithLooper
59 @SmallTest
60 public class AutoAddTrackerTest extends SysuiTestCase {
61 
62     private static final int END_POSITION = -1;
63     private static final int USER = 0;
64 
65     @Mock
66     private BroadcastDispatcher mBroadcastDispatcher;
67     @Mock
68     private QSHost mQSHost;
69     @Mock
70     private DumpManager mDumpManager;
71     @Captor
72     private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverArgumentCaptor;
73     @Captor
74     private ArgumentCaptor<IntentFilter> mIntentFilterArgumentCaptor;
75 
76     private Executor mBackgroundExecutor = Runnable::run; // Direct executor
77     private AutoAddTracker mAutoTracker;
78     private SecureSettings mSecureSettings;
79 
80     @Before
setUp()81     public void setUp() {
82         MockitoAnnotations.initMocks(this);
83 
84         mSecureSettings = new FakeSettings();
85 
86         mSecureSettings.putStringForUser(Secure.QS_AUTO_ADDED_TILES, null, USER);
87 
88         mAutoTracker = createAutoAddTracker(USER);
89         mAutoTracker.initialize();
90     }
91 
92     @Test
testChangeFromBackup()93     public void testChangeFromBackup() {
94         assertFalse(mAutoTracker.isAdded(SAVER));
95 
96         mSecureSettings.putStringForUser(Secure.QS_AUTO_ADDED_TILES, SAVER, USER);
97 
98         assertTrue(mAutoTracker.isAdded(SAVER));
99 
100         mAutoTracker.destroy();
101     }
102 
103     @Test
testSetAdded()104     public void testSetAdded() {
105         assertFalse(mAutoTracker.isAdded(SAVER));
106         mAutoTracker.setTileAdded(SAVER);
107 
108         assertTrue(mAutoTracker.isAdded(SAVER));
109 
110         mAutoTracker.destroy();
111     }
112 
113     @Test
testPersist()114     public void testPersist() {
115         assertFalse(mAutoTracker.isAdded(SAVER));
116         mAutoTracker.setTileAdded(SAVER);
117 
118         mAutoTracker.destroy();
119         mAutoTracker = createAutoAddTracker(USER);
120         mAutoTracker.initialize();
121 
122         assertTrue(mAutoTracker.isAdded(SAVER));
123 
124         mAutoTracker.destroy();
125     }
126 
127     @Test
testIndependentUsers()128     public void testIndependentUsers() {
129         mAutoTracker.setTileAdded(SAVER);
130 
131         mAutoTracker = createAutoAddTracker(USER + 1);
132         mAutoTracker.initialize();
133         assertFalse(mAutoTracker.isAdded(SAVER));
134     }
135 
136     @Test
testChangeUser()137     public void testChangeUser() {
138         mAutoTracker.setTileAdded(SAVER);
139 
140         mAutoTracker = createAutoAddTracker(USER + 1);
141         mAutoTracker.changeUser(UserHandle.of(USER));
142         assertTrue(mAutoTracker.isAdded(SAVER));
143     }
144 
145     @Test
testRestoredTilePositionPreserved()146     public void testRestoredTilePositionPreserved() {
147         verify(mBroadcastDispatcher).registerReceiver(
148                 mBroadcastReceiverArgumentCaptor.capture(), any(), any(), any(), anyInt(), any());
149         String restoredTiles = "saver,internet,work,cast";
150         Intent restoreTilesIntent = makeRestoreIntent(Secure.QS_TILES, null, restoredTiles);
151 
152         mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreTilesIntent);
153 
154         assertEquals(2, mAutoTracker.getRestoredTilePosition("work"));
155     }
156 
157     @Test
testNoRestoredTileReturnsEndPosition()158     public void testNoRestoredTileReturnsEndPosition() {
159         verify(mBroadcastDispatcher).registerReceiver(
160                 mBroadcastReceiverArgumentCaptor.capture(), any(), any(), any(), anyInt(), any());
161         Intent restoreTilesIntent = makeRestoreIntent(Secure.QS_TILES, null, null);
162 
163         mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreTilesIntent);
164 
165         assertEquals(END_POSITION, mAutoTracker.getRestoredTilePosition("work"));
166     }
167 
168     @Test
testBroadcastReceiverRegistered()169     public void testBroadcastReceiverRegistered() {
170         verify(mBroadcastDispatcher).registerReceiver(
171                 any(), mIntentFilterArgumentCaptor.capture(), any(), eq(UserHandle.of(USER)),
172                 anyInt(), any());
173 
174         assertTrue(
175                 mIntentFilterArgumentCaptor.getValue().hasAction(Intent.ACTION_SETTING_RESTORED));
176     }
177 
178     @Test
testBroadcastReceiverChangesWithUser()179     public void testBroadcastReceiverChangesWithUser() {
180         mAutoTracker.changeUser(UserHandle.of(USER + 1));
181 
182         InOrder inOrder = Mockito.inOrder(mBroadcastDispatcher);
183         inOrder.verify(mBroadcastDispatcher).unregisterReceiver(any());
184         inOrder.verify(mBroadcastDispatcher)
185                 .registerReceiver(any(), any(), any(), eq(UserHandle.of(USER + 1)), anyInt(),
186                         any());
187     }
188 
189     @Test
testSettingRestoredWithTilesNotRemovedInSource_noAutoAddedInTarget()190     public void testSettingRestoredWithTilesNotRemovedInSource_noAutoAddedInTarget() {
191         verify(mBroadcastDispatcher).registerReceiver(
192                 mBroadcastReceiverArgumentCaptor.capture(), any(), any(), any(), anyInt(), any());
193 
194         // These tiles were present in the original device
195         String restoredTiles = "saver,work,internet,cast";
196         Intent restoreTilesIntent = makeRestoreIntent(Secure.QS_TILES, null, restoredTiles);
197         mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreTilesIntent);
198 
199         // And these tiles have been auto-added in the original device
200         // (no auto-added before restore)
201         String restoredAutoAddTiles = "work";
202         Intent restoreAutoAddTilesIntent =
203                 makeRestoreIntent(Secure.QS_AUTO_ADDED_TILES, null, restoredAutoAddTiles);
204         mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreAutoAddTilesIntent);
205 
206         // Then, don't remove any current tiles
207         verify(mQSHost, never()).removeTiles(any());
208         assertEquals(restoredAutoAddTiles,
209                 mSecureSettings.getStringForUser(Secure.QS_AUTO_ADDED_TILES, USER));
210     }
211 
212     @Test
testSettingRestoredWithTilesRemovedInSource_noAutoAddedInTarget()213     public void testSettingRestoredWithTilesRemovedInSource_noAutoAddedInTarget() {
214         verify(mBroadcastDispatcher)
215                 .registerReceiver(mBroadcastReceiverArgumentCaptor.capture(), any(), any(), any(),
216                         anyInt(), any());
217 
218         // These tiles were present in the original device
219         String restoredTiles = "saver,internet,cast";
220         Intent restoreTilesIntent = makeRestoreIntent(Secure.QS_TILES, null, restoredTiles);
221         mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreTilesIntent);
222 
223         // And these tiles have been auto-added in the original device
224         // (no auto-added before restore)
225         String restoredAutoAddTiles = "work";
226         Intent restoreAutoAddTilesIntent =
227                 makeRestoreIntent(Secure.QS_AUTO_ADDED_TILES, null, restoredAutoAddTiles);
228         mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreAutoAddTilesIntent);
229 
230         // Then, remove work tile
231         verify(mQSHost).removeTiles(List.of("work"));
232         assertEquals(restoredAutoAddTiles,
233                 mSecureSettings.getStringForUser(Secure.QS_AUTO_ADDED_TILES, USER));
234     }
235 
236     @Test
testSettingRestoredWithTilesRemovedInSource_sameAutoAddedinTarget()237     public void testSettingRestoredWithTilesRemovedInSource_sameAutoAddedinTarget() {
238         verify(mBroadcastDispatcher)
239                 .registerReceiver(mBroadcastReceiverArgumentCaptor.capture(), any(), any(), any(),
240                         anyInt(), any());
241 
242         // These tiles were present in the original device
243         String restoredTiles = "saver,internet,cast";
244         Intent restoreTilesIntent =
245                 makeRestoreIntent(Secure.QS_TILES, "saver, internet, cast, work", restoredTiles);
246         mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreTilesIntent);
247 
248         // And these tiles have been auto-added in the original device
249         // (no auto-added before restore)
250         String restoredAutoAddTiles = "work";
251         Intent restoreAutoAddTilesIntent =
252                 makeRestoreIntent(Secure.QS_AUTO_ADDED_TILES, "work", restoredAutoAddTiles);
253         mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreAutoAddTilesIntent);
254 
255         // Then, remove work tile
256         verify(mQSHost).removeTiles(List.of("work"));
257         assertEquals(restoredAutoAddTiles,
258                 mSecureSettings.getStringForUser(Secure.QS_AUTO_ADDED_TILES, USER));
259     }
260 
261     @Test
testSettingRestoredWithTilesRemovedInSource_othersAutoAddedinTarget()262     public void testSettingRestoredWithTilesRemovedInSource_othersAutoAddedinTarget() {
263         verify(mBroadcastDispatcher)
264                 .registerReceiver(mBroadcastReceiverArgumentCaptor.capture(), any(), any(), any(),
265                         anyInt(), any());
266 
267         // These tiles were present in the original device
268         String restoredTiles = "saver,internet,cast";
269         Intent restoreTilesIntent =
270                 makeRestoreIntent(Secure.QS_TILES, "saver, internet, cast, work", restoredTiles);
271         mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreTilesIntent);
272 
273         // And these tiles have been auto-added in the original device
274         // (no auto-added before restore)
275         String restoredAutoAddTiles = "work";
276         Intent restoreAutoAddTilesIntent =
277                 makeRestoreIntent(Secure.QS_AUTO_ADDED_TILES, "inversion", restoredAutoAddTiles);
278         mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreAutoAddTilesIntent);
279 
280         // Then, remove work tile
281         verify(mQSHost).removeTiles(List.of("work"));
282 
283         String setting = mSecureSettings.getStringForUser(Secure.QS_AUTO_ADDED_TILES, USER);
284         assertEquals(2, setting.split(",").length);
285         assertTrue(setting.contains("work"));
286         assertTrue(setting.contains("inversion"));
287     }
288 
289 
makeRestoreIntent( String settingName, String previousValue, String restoredValue)290     private Intent makeRestoreIntent(
291             String settingName, String previousValue, String restoredValue) {
292         Intent intent = new Intent(Intent.ACTION_SETTING_RESTORED);
293         intent.putExtra(Intent.EXTRA_SETTING_NAME, settingName);
294         intent.putExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE, previousValue);
295         intent.putExtra(Intent.EXTRA_SETTING_NEW_VALUE, restoredValue);
296         return intent;
297     }
298 
createAutoAddTracker(int user)299     private AutoAddTracker createAutoAddTracker(int user) {
300         // Null handler wil dispatch sync.
301         return new AutoAddTracker(
302                 mSecureSettings,
303                 mBroadcastDispatcher,
304                 mQSHost,
305                 mDumpManager,
306                 null,
307                 mBackgroundExecutor,
308                 user
309         );
310     }
311 }