1 /*
2  * Copyright (C) 2020 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.settings.accessibility;
18 
19 import static com.android.settings.accessibility.DisableAnimationsPreferenceController.ANIMATION_OFF_VALUE;
20 import static com.android.settings.accessibility.DisableAnimationsPreferenceController.ANIMATION_ON_VALUE;
21 import static com.android.settings.accessibility.DisableAnimationsPreferenceController.TOGGLE_ANIMATION_TARGETS;
22 
23 import static com.google.common.truth.Truth.assertThat;
24 
25 import android.content.ContentResolver;
26 import android.content.Context;
27 import android.database.ContentObserver;
28 import android.net.Uri;
29 import android.os.Handler;
30 import android.os.Looper;
31 import android.os.UserHandle;
32 import android.provider.Settings;
33 
34 import androidx.annotation.Nullable;
35 import androidx.preference.PreferenceManager;
36 import androidx.preference.PreferenceScreen;
37 import androidx.preference.SwitchPreference;
38 import androidx.test.core.app.ApplicationProvider;
39 import androidx.test.ext.junit.runners.AndroidJUnit4;
40 
41 import com.android.settings.core.BasePreferenceController;
42 
43 import org.junit.After;
44 import org.junit.Assert;
45 import org.junit.Before;
46 import org.junit.Test;
47 import org.junit.runner.RunWith;
48 
49 import java.util.concurrent.CountDownLatch;
50 import java.util.concurrent.TimeUnit;
51 
52 @RunWith(AndroidJUnit4.class)
53 public class DisableAnimationsPreferenceControllerTest {
54 
55     private static final String TEST_PREFERENCE_KEY = "disable_animation";
56     private final Context mContext = ApplicationProvider.getApplicationContext();
57     private Looper mLooper;
58 
59     private PreferenceScreen mScreen;
60     private SwitchPreference mPreference;
61     private DisableAnimationsPreferenceController mController;
62 
63     @Before
setUp()64     public void setUp() {
65         if (Looper.myLooper() == null) {
66             Looper.prepare();
67         }
68         mLooper = Looper.myLooper();
69         PreferenceManager preferenceManager = new PreferenceManager(mContext);
70         mScreen = preferenceManager.createPreferenceScreen(mContext);
71         final SwitchPreference preference = new SwitchPreference(mContext);
72         preference.setKey(TEST_PREFERENCE_KEY);
73         preference.setPersistent(false);
74         mScreen.addPreference(preference);
75 
76         mController = new DisableAnimationsPreferenceController(mContext, TEST_PREFERENCE_KEY);
77         mController.displayPreference(mScreen);
78         mPreference = mScreen.findPreference(TEST_PREFERENCE_KEY);
79     }
80 
81     @After
cleanUp()82     public void cleanUp() {
83         // calling Settings.Global.resetToDefaults doesn't work somehow
84         // one could check if it works by running the test ones, and see if the settings
85         // that were changed being restored to default
86         setAnimationScaleAndWaitForUpdate(ANIMATION_ON_VALUE);
87     }
88 
89     @Test
getAvailabilityStatus_shouldReturnAvailable()90     public void getAvailabilityStatus_shouldReturnAvailable() {
91         assertThat(mController.getAvailabilityStatus()).isEqualTo(
92                 BasePreferenceController.AVAILABLE);
93     }
94 
95     @Test
isChecked_enabledAnimation_shouldReturnFalse()96     public void isChecked_enabledAnimation_shouldReturnFalse() {
97         setAnimationScaleAndWaitForUpdate(ANIMATION_ON_VALUE);
98 
99         mController.updateState(mPreference);
100 
101         assertThat(mController.isChecked()).isFalse();
102         assertThat(mPreference.isChecked()).isFalse();
103     }
104 
105     @Test
isChecked_disabledAnimation_shouldReturnTrue()106     public void isChecked_disabledAnimation_shouldReturnTrue() {
107         setAnimationScaleAndWaitForUpdate(ANIMATION_OFF_VALUE);
108 
109         mController.updateState(mPreference);
110 
111         assertThat(mController.isChecked()).isTrue();
112         assertThat(mPreference.isChecked()).isTrue();
113     }
114 
115     @Test
setChecked_disabledAnimation_shouldDisableAnimationTargets()116     public void setChecked_disabledAnimation_shouldDisableAnimationTargets() {
117         mController.setChecked(true);
118 
119         for (String animationSetting : TOGGLE_ANIMATION_TARGETS) {
120             final float value = Settings.Global.getFloat(mContext.getContentResolver(),
121                     animationSetting, /* def= */ -1.0f);
122             assertThat(Float.compare(value, ANIMATION_OFF_VALUE)).isEqualTo(0);
123         }
124     }
125 
126     @Test
setChecked_enabledAnimation_shouldEnableAnimationTargets()127     public void setChecked_enabledAnimation_shouldEnableAnimationTargets() {
128         mController.setChecked(false);
129 
130         for (String animationSetting : TOGGLE_ANIMATION_TARGETS) {
131             final float value = Settings.Global.getFloat(mContext.getContentResolver(),
132                     animationSetting, /* def= */ -1.0f);
133             assertThat(Float.compare(value, ANIMATION_ON_VALUE)).isEqualTo(0);
134         }
135     }
136 
137     @Test
onStart_enabledAnimation_shouldReturnFalse()138     public void onStart_enabledAnimation_shouldReturnFalse() {
139         mController.onStart();
140 
141         setAnimationScaleAndWaitForUpdate(ANIMATION_ON_VALUE);
142 
143         assertThat(mController.isChecked()).isFalse();
144         assertThat(mPreference.isChecked()).isFalse();
145     }
146 
147     @Test
onStart_disabledAnimation_shouldReturnTrue()148     public void onStart_disabledAnimation_shouldReturnTrue() {
149         mController.onStart();
150 
151         setAnimationScaleAndWaitForUpdate(ANIMATION_OFF_VALUE);
152 
153         assertThat(mController.isChecked()).isTrue();
154         assertThat(mPreference.isChecked()).isTrue();
155     }
156 
157     @Test
onStop_shouldNotUpdateTargets()158     public void onStop_shouldNotUpdateTargets() {
159         mPreference.setChecked(true);
160         mController.onStart();
161         mController.onStop();
162 
163         setAnimationScaleAndWaitForUpdate(ANIMATION_ON_VALUE);
164 
165         assertThat(mPreference.isChecked()).isTrue();
166     }
167 
setAnimationScaleAndWaitForUpdate(float newValue)168     private void setAnimationScaleAndWaitForUpdate(float newValue) {
169         ContentResolver resolver = mContext.getContentResolver();
170         CountDownLatch countDownLatch = new CountDownLatch(TOGGLE_ANIMATION_TARGETS.size());
171         ContentObserver settingsObserver = new ContentObserver(new Handler(mLooper)) {
172             @Override
173             public void onChange(boolean selfChange, @Nullable Uri uri) {
174                 countDownLatch.countDown();
175 
176             }
177         };
178 
179         try {
180             for (String key : TOGGLE_ANIMATION_TARGETS) {
181                 resolver.registerContentObserver(Settings.Global.getUriFor(key),
182                         false, settingsObserver, UserHandle.USER_ALL);
183                 Settings.Global.putFloat(mContext.getContentResolver(), key,
184                         newValue);
185             }
186             countDownLatch.await(5, TimeUnit.SECONDS);
187         } catch (InterruptedException e) {
188             Assert.fail(e.getMessage());
189         } finally {
190             resolver.unregisterContentObserver(settingsObserver);
191         }
192     }
193 }