OSDN Git Service

6d18449e5f89d6b3a516f57becb9f7eff4c4eade
[android-x86/packages-apps-Settings.git] / tests / robotests / src / com / android / settings / slices / SliceBroadcastReceiverTest.java
1 /*
2  * Copyright (C) 2018 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
18 package com.android.settings.slices;
19
20 import static com.google.common.truth.Truth.assertThat;
21
22 import static org.mockito.ArgumentMatchers.any;
23 import static org.mockito.ArgumentMatchers.eq;
24 import static org.mockito.Mockito.doReturn;
25 import static org.mockito.Mockito.mock;
26 import static org.mockito.Mockito.never;
27 import static org.mockito.Mockito.spy;
28 import static org.mockito.Mockito.verify;
29
30 import android.app.slice.Slice;
31 import android.content.ContentResolver;
32 import android.content.ContentValues;
33 import android.content.Context;
34 import android.content.Intent;
35 import android.database.sqlite.SQLiteDatabase;
36 import android.net.Uri;
37 import android.provider.Settings;
38 import android.provider.SettingsSlicesContract;
39 import android.util.Pair;
40
41 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
42 import com.android.settings.core.BasePreferenceController;
43 import com.android.settings.testutils.FakeIndexProvider;
44 import com.android.settings.search.SearchFeatureProvider;
45 import com.android.settings.search.SearchFeatureProviderImpl;
46 import com.android.settings.testutils.DatabaseTestUtils;
47 import com.android.settings.testutils.FakeFeatureFactory;
48 import com.android.settings.testutils.FakeSliderController;
49 import com.android.settings.testutils.FakeToggleController;
50 import com.android.settings.testutils.SettingsRobolectricTestRunner;
51
52 import org.junit.After;
53 import org.junit.Before;
54 import org.junit.Test;
55 import org.junit.runner.RunWith;
56 import org.mockito.ArgumentCaptor;
57 import org.robolectric.RuntimeEnvironment;
58
59 @RunWith(SettingsRobolectricTestRunner.class)
60 public class SliceBroadcastReceiverTest {
61
62     private final String fakeTitle = "title";
63     private final String fakeSummary = "summary";
64     private final String fakeScreenTitle = "screen_title";
65     private final int fakeIcon = 1234;
66     private final String fakeFragmentClassName = FakeIndexProvider.class.getName();
67     private final Class fakeControllerName = FakeToggleController.class;
68
69     private Context mContext;
70     private SQLiteDatabase mDb;
71     private SliceBroadcastReceiver mReceiver;
72     private SearchFeatureProvider mSearchFeatureProvider;
73     private FakeFeatureFactory mFakeFeatureFactory;
74     private ArgumentCaptor<Pair<Integer, Object>> mLoggingNameArgumentCatpor;
75     private ArgumentCaptor<Pair<Integer, Object>> mLoggingValueArgumentCatpor;
76
77     @Before
78     public void setUp() {
79         mContext = spy(RuntimeEnvironment.application);
80         mDb = SlicesDatabaseHelper.getInstance(mContext).getWritableDatabase();
81         mReceiver = new SliceBroadcastReceiver();
82         SlicesDatabaseHelper helper = SlicesDatabaseHelper.getInstance(mContext);
83         helper.setIndexedState();
84         mSearchFeatureProvider = new SearchFeatureProviderImpl();
85         mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
86         mFakeFeatureFactory.searchFeatureProvider = mSearchFeatureProvider;
87         mLoggingNameArgumentCatpor = ArgumentCaptor.forClass(Pair.class);
88         mLoggingValueArgumentCatpor = ArgumentCaptor.forClass(Pair.class);
89     }
90
91     @After
92     public void cleanUp() {
93         DatabaseTestUtils.clearDb(mContext);
94     }
95
96     @Test
97     public void onReceive_toggleChanged() {
98         final String key = "key";
99         final Uri uri = new Uri.Builder()
100                 .scheme(ContentResolver.SCHEME_CONTENT)
101                 .authority(SettingsSliceProvider.SLICE_AUTHORITY)
102                 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
103                 .appendPath(key)
104                 .build();
105         mSearchFeatureProvider.getSearchIndexableResources().getProviderValues().clear();
106         insertSpecialCase(key);
107         final ContentResolver resolver = mock(ContentResolver.class);
108         doReturn(resolver).when(mContext).getContentResolver();
109         // Turn on toggle setting
110         FakeToggleController fakeToggleController = new FakeToggleController(mContext, key);
111         fakeToggleController.setChecked(true);
112         Intent intent = new Intent(SettingsSliceProvider.ACTION_TOGGLE_CHANGED);
113         intent.putExtra(SettingsSliceProvider.EXTRA_SLICE_KEY, key);
114
115         assertThat(fakeToggleController.isChecked()).isTrue();
116
117         // Toggle setting
118         mReceiver.onReceive(mContext, intent);
119
120         assertThat(fakeToggleController.isChecked()).isFalse();
121         verify(mFakeFeatureFactory.metricsFeatureProvider)
122                 .action(eq(mContext),
123                         eq(MetricsEvent.ACTION_SETTINGS_SLICE_CHANGED),
124                         mLoggingNameArgumentCatpor.capture(),
125                         mLoggingValueArgumentCatpor.capture());
126
127         final Pair<Integer, Object> namePair = mLoggingNameArgumentCatpor.getValue();
128         final Pair<Integer, Object> valuePair = mLoggingValueArgumentCatpor.getValue();
129         assertThat(namePair.first).isEqualTo(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_NAME);
130         assertThat(namePair.second).isEqualTo(fakeToggleController.getPreferenceKey());
131
132         verify(resolver).notifyChange(uri, null);
133         assertThat(valuePair.first)
134                 .isEqualTo(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE);
135         assertThat(valuePair.second).isEqualTo(0);
136     }
137
138     @Test
139     public void toggleUpdate_synchronously_notifyChange_should_be_called() {
140         // Monitor the ContentResolver
141         final ContentResolver resolver = spy(mContext.getContentResolver());
142         doReturn(resolver).when(mContext).getContentResolver();
143
144         final String key = "key";
145         mSearchFeatureProvider.getSearchIndexableResources().getProviderValues().clear();
146         insertSpecialCase(key);
147
148         FakeToggleController fakeToggleController = new FakeToggleController(mContext, key);
149         fakeToggleController.setChecked(true);
150         // Set the toggle setting update synchronously.
151         fakeToggleController.setAsyncUpdate(false);
152         Intent intent = new Intent(SettingsSliceProvider.ACTION_TOGGLE_CHANGED);
153         intent.putExtra(SettingsSliceProvider.EXTRA_SLICE_KEY, key);
154
155         assertThat(fakeToggleController.isChecked()).isTrue();
156
157         // Toggle setting
158         mReceiver.onReceive(mContext, intent);
159
160         assertThat(fakeToggleController.isChecked()).isFalse();
161
162         final Uri expectedUri = new Uri.Builder()
163                 .scheme(ContentResolver.SCHEME_CONTENT)
164                 .authority(SettingsSliceProvider.SLICE_AUTHORITY)
165                 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
166                 .appendPath(key)
167                 .build();
168         verify(resolver).notifyChange(expectedUri, null);
169     }
170
171     @Test
172     public void toggleUpdate_asynchronously_notifyChange_should_not_be_called() {
173         // Monitor the ContentResolver
174         final ContentResolver resolver = spy(mContext.getContentResolver());
175         doReturn(resolver).when(mContext).getContentResolver();
176
177         final String key = "key";
178         mSearchFeatureProvider.getSearchIndexableResources().getProviderValues().clear();
179         insertSpecialCase(key);
180
181         FakeToggleController fakeToggleController = new FakeToggleController(mContext, key);
182         fakeToggleController.setChecked(true);
183         // Set the toggle setting update asynchronously.
184         fakeToggleController.setAsyncUpdate(true);
185         Intent intent = new Intent(SettingsSliceProvider.ACTION_TOGGLE_CHANGED);
186         intent.putExtra(SettingsSliceProvider.EXTRA_SLICE_KEY, key);
187
188         assertThat(fakeToggleController.isChecked()).isTrue();
189
190         // Toggle setting
191         mReceiver.onReceive(mContext, intent);
192
193         verify(resolver, never()).notifyChange(null, null);
194     }
195
196     @Test
197     public void onReceive_sliderChanged() {
198         final String key = "key";
199         final Uri uri = new Uri.Builder()
200                 .scheme(ContentResolver.SCHEME_CONTENT)
201                 .authority(SettingsSliceProvider.SLICE_AUTHORITY)
202                 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
203                 .appendPath(key)
204                 .build();
205         final ContentResolver resolver = mock(ContentResolver.class);
206         doReturn(resolver).when(mContext).getContentResolver();
207         final int position = FakeSliderController.MAX_STEPS - 1;
208         final int oldPosition = FakeSliderController.MAX_STEPS;
209         mSearchFeatureProvider.getSearchIndexableResources().getProviderValues().clear();
210         insertSpecialCase(FakeSliderController.class, key);
211
212         // Set slider setting
213         FakeSliderController fakeSliderController = new FakeSliderController(mContext, key);
214         fakeSliderController.setSliderPosition(oldPosition);
215         // Build action
216         Intent intent = new Intent(SettingsSliceProvider.ACTION_SLIDER_CHANGED);
217         intent.putExtra(Slice.EXTRA_RANGE_VALUE, position);
218         intent.putExtra(SettingsSliceProvider.EXTRA_SLICE_KEY, key);
219
220         assertThat(fakeSliderController.getSliderPosition()).isEqualTo(oldPosition);
221
222         // Update the setting.
223         mReceiver.onReceive(mContext, intent);
224
225         assertThat(fakeSliderController.getSliderPosition()).isEqualTo(position);
226         verify(mFakeFeatureFactory.metricsFeatureProvider)
227                 .action(eq(mContext),
228                         eq(MetricsEvent.ACTION_SETTINGS_SLICE_CHANGED),
229                         mLoggingNameArgumentCatpor.capture(),
230                         mLoggingValueArgumentCatpor.capture());
231
232         final Pair<Integer, Object> namePair = mLoggingNameArgumentCatpor.getValue();
233         final Pair<Integer, Object> valuePair = mLoggingValueArgumentCatpor.getValue();
234         assertThat(namePair.first).isEqualTo(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_NAME);
235         assertThat(namePair.second).isEqualTo(key);
236
237         verify(resolver).notifyChange(uri, null);
238         assertThat(valuePair.first)
239                 .isEqualTo(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE);
240         assertThat(valuePair.second).isEqualTo(position);
241     }
242
243     @Test(expected = IllegalArgumentException.class)
244     public void onReceive_invalidController_throwsException() {
245         final String key = "key";
246         final int position = 0;
247         mSearchFeatureProvider.getSearchIndexableResources().getProviderValues().clear();
248         insertSpecialCase(FakeToggleController.class, key);
249
250         // Build action
251         Intent intent = new Intent(SettingsSliceProvider.ACTION_SLIDER_CHANGED);
252         intent.putExtra(Slice.EXTRA_RANGE_VALUE, position);
253         intent.putExtra(SettingsSliceProvider.EXTRA_SLICE_KEY, key);
254
255         // Trigger the exception.
256         mReceiver.onReceive(mContext, intent);
257     }
258
259     @Test(expected = IllegalArgumentException.class)
260     public void sliderOnReceive_noKey_throwsException() {
261         // Build action
262         final Intent intent = new Intent(SettingsSliceProvider.ACTION_SLIDER_CHANGED)
263                 .putExtra(Slice.EXTRA_RANGE_VALUE, 0);
264
265         // Trigger the exception.
266         mReceiver.onReceive(mContext, intent);
267     }
268
269     @Test(expected = IllegalStateException.class)
270     public void toggleOnReceive_noExtra_illegalStateException() {
271         final Intent intent = new Intent(SettingsSliceProvider.ACTION_TOGGLE_CHANGED);
272         mReceiver.onReceive(mContext, intent);
273     }
274
275     @Test(expected = IllegalStateException.class)
276     public void toggleOnReceive_emptyKey_throwsIllegalStateException() {
277         final Intent intent = new Intent(SettingsSliceProvider.ACTION_TOGGLE_CHANGED)
278                 .putExtra(SettingsSliceProvider.EXTRA_SLICE_KEY, (String) null);
279         mReceiver.onReceive(mContext, intent);
280     }
281
282     @Test
283     public void toggleUpdate_unavailableUriNotified() {
284         // Monitor the ContentResolver
285         final ContentResolver resolver = spy(mContext.getContentResolver());
286         doReturn(resolver).when(mContext).getContentResolver();
287
288         // Disable Setting
289         Settings.Global.putInt(mContext.getContentResolver(),
290                 FakeToggleController.AVAILABILITY_KEY,
291                 BasePreferenceController.UNSUPPORTED_ON_DEVICE);
292
293         // Insert Fake Toggle into Database
294         final String key = "key";
295         mSearchFeatureProvider.getSearchIndexableResources().getProviderValues().clear();
296         insertSpecialCase(FakeToggleController.class, key);
297
298         // Turn on toggle setting
299         final FakeToggleController fakeToggleController = new FakeToggleController(mContext, key);
300         fakeToggleController.setChecked(true);
301
302         // Build Action
303         final Intent intent = new Intent(SettingsSliceProvider.ACTION_TOGGLE_CHANGED);
304         intent.putExtra(SettingsSliceProvider.EXTRA_SLICE_KEY, key);
305
306         // Trigger Slice change
307         mReceiver.onReceive(mContext, intent);
308
309         // Check the value is the same and the Uri has been notified.
310         assertThat(fakeToggleController.isChecked()).isTrue();
311         final Uri expectedUri = new Uri.Builder()
312                 .scheme(ContentResolver.SCHEME_CONTENT)
313                 .authority(SettingsSliceProvider.SLICE_AUTHORITY)
314                 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
315                 .appendPath(key)
316                 .build();
317         verify(resolver).notifyChange(eq(expectedUri), eq(null));
318     }
319
320     @Test
321     public void sliderUpdate_unavailableUriNotified() {
322         // Monitor the ContentResolver
323         final ContentResolver resolver = spy(mContext.getContentResolver());
324         doReturn(resolver).when(mContext).getContentResolver();
325
326         // Disable Setting
327         Settings.Global.putInt(mContext.getContentResolver(),
328                 FakeSliderController.AVAILABILITY_KEY,
329                 BasePreferenceController.UNSUPPORTED_ON_DEVICE);
330
331         // Insert Fake Slider into Database
332         final String key = "key";
333         final int position = FakeSliderController.MAX_STEPS - 1;
334         final int oldPosition = FakeSliderController.MAX_STEPS;
335         mSearchFeatureProvider.getSearchIndexableResources().getProviderValues().clear();
336         insertSpecialCase(FakeSliderController.class, key);
337
338         // Set slider setting
339         final FakeSliderController fakeSliderController = new FakeSliderController(mContext, key);
340         fakeSliderController.setSliderPosition(oldPosition);
341
342         // Build action
343         final Intent intent = new Intent(SettingsSliceProvider.ACTION_SLIDER_CHANGED);
344         intent.putExtra(Slice.EXTRA_RANGE_VALUE, position);
345         intent.putExtra(SettingsSliceProvider.EXTRA_SLICE_KEY, key);
346
347         // Trigger Slice change
348         mReceiver.onReceive(mContext, intent);
349
350         // Check position is the same and the Uri has been notified.
351         assertThat(fakeSliderController.getSliderPosition()).isEqualTo(oldPosition);
352         final Uri expectedUri = new Uri.Builder()
353                 .scheme(ContentResolver.SCHEME_CONTENT)
354                 .authority(SettingsSliceProvider.SLICE_AUTHORITY)
355                 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
356                 .appendPath(key)
357                 .build();
358         verify(resolver).notifyChange(eq(expectedUri), eq(null));
359     }
360
361     private void insertSpecialCase(String key) {
362         insertSpecialCase(fakeControllerName, key);
363     }
364
365     private void insertSpecialCase(Class controllerClass, String key) {
366         ContentValues values = new ContentValues();
367         values.put(SlicesDatabaseHelper.IndexColumns.KEY, key);
368         values.put(SlicesDatabaseHelper.IndexColumns.TITLE, fakeTitle);
369         values.put(SlicesDatabaseHelper.IndexColumns.SUMMARY, fakeSummary);
370         values.put(SlicesDatabaseHelper.IndexColumns.SCREENTITLE, fakeScreenTitle);
371         values.put(SlicesDatabaseHelper.IndexColumns.ICON_RESOURCE, fakeIcon);
372         values.put(SlicesDatabaseHelper.IndexColumns.FRAGMENT, fakeFragmentClassName);
373         values.put(SlicesDatabaseHelper.IndexColumns.CONTROLLER, controllerClass.getName());
374         mDb.replaceOrThrow(SlicesDatabaseHelper.Tables.TABLE_SLICES_INDEX, null, values);
375     }
376 }