1 /*
2  * Copyright (C) 2022 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.development;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.junit.Assert.assertFalse;
22 import static org.junit.Assert.assertTrue;
23 
24 import android.app.Instrumentation;
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.platform.test.annotations.RequiresFlagsDisabled;
33 import android.platform.test.annotations.RequiresFlagsEnabled;
34 import android.platform.test.flag.junit.CheckFlagsRule;
35 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
36 import android.provider.Settings;
37 
38 import androidx.preference.PreferenceManager;
39 import androidx.preference.PreferenceScreen;
40 import androidx.preference.SwitchPreference;
41 import androidx.test.ext.junit.runners.AndroidJUnit4;
42 import androidx.test.platform.app.InstrumentationRegistry;
43 
44 import com.android.window.flags.Flags;
45 
46 import org.junit.Assert;
47 import org.junit.Before;
48 import org.junit.Rule;
49 import org.junit.Test;
50 import org.junit.runner.RunWith;
51 import org.mockito.MockitoAnnotations;
52 
53 import java.util.concurrent.CountDownLatch;
54 import java.util.concurrent.TimeUnit;
55 
56 @RunWith(AndroidJUnit4.class)
57 public class BackAnimationPreferenceControllerTest {
58 
59     private static final int SETTING_VALUE_OFF = 0;
60     private static final int SETTING_VALUE_ON = 1;
61 
62     private SwitchPreference mPreference;
63 
64     private Context mContext;
65     private BackAnimationPreferenceController mController;
66     private Looper mLooper;
67 
68     @Rule
69     public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
70 
71     @Before
setUp()72     public void setUp() {
73         MockitoAnnotations.initMocks(this);
74         Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
75         mContext = instrumentation.getTargetContext();
76         mController = new BackAnimationPreferenceController(mContext);
77         mPreference = new SwitchPreference(mContext);
78         if (Looper.myLooper() == null) {
79             Looper.prepare();
80         }
81         mLooper = Looper.myLooper();
82 
83         Settings.Global.putInt(mContext.getContentResolver(),
84                 Settings.Global.ENABLE_BACK_ANIMATION, -1);
85 
86         final PreferenceManager preferenceManager = new PreferenceManager(mContext);
87         final PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
88         mPreference.setKey(mController.getPreferenceKey());
89         screen.addPreference(mPreference);
90         mController.displayPreference(screen);
91     }
92 
93     @Test
94     @RequiresFlagsEnabled(Flags.FLAG_PREDICTIVE_BACK_SYSTEM_ANIMS)
controllerNotAvailable_whenAconfigFlagEnabled()95     public void controllerNotAvailable_whenAconfigFlagEnabled() {
96         assertFalse(mController.isAvailable());
97     }
98 
99     @Test
100     @RequiresFlagsDisabled(Flags.FLAG_PREDICTIVE_BACK_SYSTEM_ANIMS)
controllerAvailable_whenAconfigFlagDisabled()101     public void controllerAvailable_whenAconfigFlagDisabled() {
102         assertTrue(mController.isAvailable());
103     }
104 
105     @Test
onPreferenceChange_switchEnabled_shouldEnableBackAnimations()106     public void onPreferenceChange_switchEnabled_shouldEnableBackAnimations() {
107         mController.onPreferenceChange(mPreference, true /* new value */);
108 
109         final int mode = Settings.Global.getInt(mContext.getContentResolver(),
110                 Settings.Global.ENABLE_BACK_ANIMATION, -1 /* default */);
111         assertThat(mode).isEqualTo(SETTING_VALUE_ON);
112     }
113 
114     @Test
onPreferenceChange_switchDisabled_shouldDisableBackAnimations()115     public void onPreferenceChange_switchDisabled_shouldDisableBackAnimations() {
116         mController.onPreferenceChange(mPreference, false /* new value */);
117 
118         final int mode = Settings.Global.getInt(mContext.getContentResolver(),
119                 Settings.Global.ENABLE_BACK_ANIMATION, -1 /* default */);
120         assertThat(mode).isEqualTo(SETTING_VALUE_OFF);
121     }
122 
123     @Test
updateState_settingEnabled_preferenceShouldBeChecked()124     public void updateState_settingEnabled_preferenceShouldBeChecked() {
125         Settings.Global.putInt(mContext.getContentResolver(),
126                 Settings.Global.ENABLE_BACK_ANIMATION, SETTING_VALUE_ON);
127         mController.updateState(mPreference);
128         assertTrue(mPreference.isChecked());
129     }
130 
131     @Test
updateState_settingDisabled_preferenceShouldNotBeChecked()132     public void updateState_settingDisabled_preferenceShouldNotBeChecked() {
133         Settings.Global.putInt(mContext.getContentResolver(),
134                 Settings.Global.ENABLE_BACK_ANIMATION, SETTING_VALUE_OFF);
135 
136         mController.updateState(mPreference);
137         assertFalse(mPreference.isChecked());
138     }
139 
140     @Test
onDeveloperOptionsSwitchDisabled_shouldDisablePreference()141     public void onDeveloperOptionsSwitchDisabled_shouldDisablePreference()
142             throws InterruptedException {
143         ContentResolver contentResolver = mContext.getContentResolver();
144         int mode = doAndWaitForSettingChange(() -> mController.onDeveloperOptionsSwitchDisabled(),
145                 contentResolver);
146         assertThat(mode).isEqualTo(SETTING_VALUE_OFF);
147         assertFalse(mPreference.isEnabled());
148         assertFalse(mPreference.isChecked());
149     }
150 
doAndWaitForSettingChange(Runnable runnable, ContentResolver contentResolver)151     private int doAndWaitForSettingChange(Runnable runnable, ContentResolver contentResolver) {
152         CountDownLatch countDownLatch = new CountDownLatch(1);
153         ContentObserver settingsObserver =
154                 new ContentObserver(new Handler(mLooper)) {
155                     @Override
156                     public void onChange(boolean selfChange, Uri uri) {
157                         countDownLatch.countDown();
158                     }
159                 };
160         contentResolver.registerContentObserver(
161                 Settings.Global.getUriFor(Settings.Global.ENABLE_BACK_ANIMATION),
162                 false, settingsObserver, UserHandle.USER_SYSTEM
163         );
164         runnable.run();
165         try {
166             countDownLatch.await(500, TimeUnit.MILLISECONDS);
167         } catch (InterruptedException e) {
168             Assert.fail(e.getMessage());
169         }
170         return Settings.Global.getInt(contentResolver,
171                 Settings.Global.ENABLE_BACK_ANIMATION, -1 /* default */);
172     }
173 }
174