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.settings.accessibility;
18 
19 import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_BUTTON_COMPONENT_NAME;
20 import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME;
21 import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_COMPONENT_NAME;
22 
23 import static com.google.common.truth.Truth.assertThat;
24 
25 import android.accessibilityservice.AccessibilityServiceInfo;
26 import android.app.Activity;
27 import android.app.admin.DevicePolicyManager;
28 import android.app.settings.SettingsEnums;
29 import android.content.ComponentName;
30 import android.content.Context;
31 import android.content.Intent;
32 import android.content.pm.ApplicationInfo;
33 import android.content.pm.ResolveInfo;
34 import android.content.pm.ServiceInfo;
35 import android.view.accessibility.AccessibilityManager;
36 
37 import androidx.test.core.app.ApplicationProvider;
38 
39 import com.android.settings.SettingsActivity;
40 import com.android.settings.testutils.shadow.ShadowDevicePolicyManager;
41 import com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal;
42 
43 import com.google.common.collect.ImmutableList;
44 
45 import org.junit.Before;
46 import org.junit.Test;
47 import org.junit.runner.RunWith;
48 import org.robolectric.RobolectricTestRunner;
49 import org.robolectric.Shadows;
50 import org.robolectric.annotation.Config;
51 import org.robolectric.shadow.api.Shadow;
52 import org.robolectric.shadows.ShadowAccessibilityManager;
53 import org.robolectric.shadows.androidx.fragment.FragmentController;
54 import org.xmlpull.v1.XmlPullParserException;
55 
56 import java.io.IOException;
57 import java.util.ArrayList;
58 import java.util.List;
59 
60 /** Tests for {@link AccessibilityDetailsSettingsFragment}. */
61 @Config(shadows = {
62         ShadowDevicePolicyManager.class,
63         ShadowRestrictedLockUtilsInternal.class
64 })
65 @RunWith(RobolectricTestRunner.class)
66 public class AccessibilityDetailsSettingsFragmentTest {
67     private static final String PACKAGE_NAME = "com.foo.bar";
68     private static final String CLASS_NAME = PACKAGE_NAME + ".fake_a11y_service";
69     private static final String COMPONENT_NAME = PACKAGE_NAME + "/" + CLASS_NAME;
70 
71     private Context mContext;
72 
73     private FragmentController<AccessibilityDetailsSettingsFragment> mFragmentController;
74 
75     @Before
setUp()76     public void setUp() {
77         mContext = ApplicationProvider.getApplicationContext();
78         ShadowAccessibilityManager shadowAccessibilityManager = Shadow.extract(
79                 AccessibilityManager.getInstance(mContext));
80         shadowAccessibilityManager.setInstalledAccessibilityServiceList(getMockServiceList());
81     }
82 
83     @Test
onCreate_afterSuccessfullyLaunch_shouldBeFinished()84     public void onCreate_afterSuccessfullyLaunch_shouldBeFinished() {
85         final Intent intent = new Intent();
86         intent.putExtra(Intent.EXTRA_COMPONENT_NAME, COMPONENT_NAME);
87 
88         AccessibilityDetailsSettingsFragment fragment = startFragment(intent);
89 
90         assertThat(fragment.getActivity().isFinishing()).isTrue();
91     }
92 
93     @Test
onCreate_hasValidExtraComponentName_launchExpectedFragment()94     public void onCreate_hasValidExtraComponentName_launchExpectedFragment() {
95         Intent intent = new Intent();
96         intent.putExtra(Intent.EXTRA_COMPONENT_NAME, COMPONENT_NAME);
97 
98         AccessibilityDetailsSettingsFragment fragment = startFragment(intent);
99 
100         assertStartActivityWithExpectedFragment(fragment.getActivity(),
101                 ToggleAccessibilityServicePreferenceFragment.class.getName());
102     }
103 
104     @Test
onCreate_hasInvalidExtraComponentName_launchAccessibilitySettings()105     public void onCreate_hasInvalidExtraComponentName_launchAccessibilitySettings() {
106         Intent intent = new Intent();
107         intent.putExtra(Intent.EXTRA_COMPONENT_NAME, PACKAGE_NAME + "/.service");
108 
109         AccessibilityDetailsSettingsFragment fragment = startFragment(intent);
110 
111         assertStartActivityWithExpectedFragment(fragment.getActivity(),
112                 AccessibilitySettings.class.getName());
113     }
114 
115     @Test
onCreate_hasNoExtraComponentName_launchAccessibilitySettings()116     public void onCreate_hasNoExtraComponentName_launchAccessibilitySettings() {
117         AccessibilityDetailsSettingsFragment fragment = startFragment(/* intent= */ null);
118 
119         assertStartActivityWithExpectedFragment(fragment.getActivity(),
120                 AccessibilitySettings.class.getName());
121     }
122 
123     @Test
onCreate_extraComponentNameIsDisallowed_launchAccessibilitySettings()124     public void onCreate_extraComponentNameIsDisallowed_launchAccessibilitySettings() {
125         Intent intent = new Intent();
126         intent.putExtra(Intent.EXTRA_COMPONENT_NAME, COMPONENT_NAME);
127         DevicePolicyManager dpm = mContext.getSystemService(
128                 DevicePolicyManager.class);
129         ((ShadowDevicePolicyManager) Shadows.shadowOf(dpm)).setPermittedAccessibilityServices(
130                 ImmutableList.of());
131 
132         AccessibilityDetailsSettingsFragment fragment = startFragment(intent);
133 
134         assertStartActivityWithExpectedFragment(fragment.getActivity(),
135                 AccessibilitySettings.class.getName());
136     }
137 
138     @Test
onCreate_magnificationComponentName_launchMagnificationFragment()139     public void onCreate_magnificationComponentName_launchMagnificationFragment() {
140         Intent intent = new Intent();
141         intent.putExtra(Intent.EXTRA_COMPONENT_NAME,
142                 MAGNIFICATION_COMPONENT_NAME.flattenToString());
143 
144         AccessibilityDetailsSettingsFragment fragment = startFragment(intent);
145 
146         assertStartActivityWithExpectedFragment(fragment.getActivity(),
147                 ToggleScreenMagnificationPreferenceFragment.class.getName());
148     }
149 
150     @Test
onCreate_accessibilityButton_launchAccessibilityButtonFragment()151     public void onCreate_accessibilityButton_launchAccessibilityButtonFragment() {
152         Intent intent = new Intent();
153         intent.putExtra(Intent.EXTRA_COMPONENT_NAME,
154                 ACCESSIBILITY_BUTTON_COMPONENT_NAME.flattenToString());
155 
156         AccessibilityDetailsSettingsFragment fragment = startFragment(intent);
157 
158         assertStartActivityWithExpectedFragment(fragment.getActivity(),
159                 AccessibilityButtonFragment.class.getName());
160     }
161 
162     @Test
onCreate_hearingAidsComponentName_launchAccessibilityHearingAidsFragment()163     public void onCreate_hearingAidsComponentName_launchAccessibilityHearingAidsFragment() {
164         Intent intent = new Intent();
165         intent.putExtra(Intent.EXTRA_COMPONENT_NAME,
166                 ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME.flattenToString());
167 
168         AccessibilityDetailsSettingsFragment fragment = startFragment(intent);
169 
170         assertStartActivityWithExpectedFragment(fragment.getActivity(),
171                 AccessibilityHearingAidsFragment.class.getName());
172     }
173 
174     @Test
getMetricsCategory_returnsCorrectCategory()175     public void getMetricsCategory_returnsCorrectCategory() {
176 
177         AccessibilityDetailsSettingsFragment fragment = startFragment(/* intent= */ null);
178 
179         assertThat(fragment.getMetricsCategory()).isEqualTo(
180                 SettingsEnums.ACCESSIBILITY_DETAILS_SETTINGS);
181     }
182 
startFragment(Intent intent)183     private AccessibilityDetailsSettingsFragment startFragment(Intent intent) {
184         mFragmentController = FragmentController.of(
185                 new AccessibilityDetailsSettingsFragment(), intent)
186                 .create()
187                 .visible();
188 
189         return mFragmentController.get();
190     }
191 
getMockAccessibilityServiceInfo()192     private AccessibilityServiceInfo getMockAccessibilityServiceInfo() {
193         final ApplicationInfo applicationInfo = new ApplicationInfo();
194         final ServiceInfo serviceInfo = new ServiceInfo();
195         applicationInfo.packageName = PACKAGE_NAME;
196         serviceInfo.packageName = PACKAGE_NAME;
197         serviceInfo.name = CLASS_NAME;
198         serviceInfo.applicationInfo = applicationInfo;
199 
200         final ResolveInfo resolveInfo = new ResolveInfo();
201         resolveInfo.serviceInfo = serviceInfo;
202 
203         try {
204             final AccessibilityServiceInfo info = new AccessibilityServiceInfo(resolveInfo,
205                     mContext);
206             ComponentName componentName = ComponentName.unflattenFromString(COMPONENT_NAME);
207             info.setComponentName(componentName);
208             return info;
209         } catch (XmlPullParserException | IOException e) {
210             // Do nothing
211         }
212 
213         return null;
214     }
215 
getMockServiceList()216     private List<AccessibilityServiceInfo> getMockServiceList() {
217         final List<AccessibilityServiceInfo> infoList = new ArrayList<>();
218         infoList.add(getMockAccessibilityServiceInfo());
219         return infoList;
220     }
221 
assertStartActivityWithExpectedFragment(Activity activity, String fragmentName)222     private void assertStartActivityWithExpectedFragment(Activity activity, String fragmentName) {
223         Intent intent = Shadows.shadowOf(activity).getNextStartedActivity();
224         assertThat(intent.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT)).isEqualTo(
225                 fragmentName);
226     }
227 }
228