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.bluetooth;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.mockito.Mockito.when;
22 
23 import android.accessibilityservice.AccessibilityServiceInfo;
24 import android.content.ComponentName;
25 import android.content.pm.ApplicationInfo;
26 import android.content.pm.ResolveInfo;
27 import android.content.pm.ServiceInfo;
28 import android.view.accessibility.AccessibilityManager;
29 
30 import androidx.preference.Preference;
31 import androidx.preference.PreferenceCategory;
32 
33 import com.android.settings.testutils.FakeFeatureFactory;
34 
35 import org.junit.Rule;
36 import org.junit.Test;
37 import org.junit.runner.RunWith;
38 import org.mockito.junit.MockitoJUnit;
39 import org.mockito.junit.MockitoRule;
40 import org.robolectric.RobolectricTestRunner;
41 import org.robolectric.shadow.api.Shadow;
42 import org.robolectric.shadows.ShadowAccessibilityManager;
43 import org.xmlpull.v1.XmlPullParserException;
44 
45 import java.io.IOException;
46 import java.util.List;
47 
48 /** Tests for {@link BluetoothDetailsRelatedToolsController}. */
49 @RunWith(RobolectricTestRunner.class)
50 public class BluetoothDetailsRelatedToolsControllerTest extends BluetoothDetailsControllerTestBase {
51     @Rule
52     public final MockitoRule mockito = MockitoJUnit.rule();
53 
54     private static final String PACKAGE_NAME = "com.android.test";
55     private static final String PACKAGE_NAME2 = "com.android.test2";
56     private static final String CLASS_NAME = PACKAGE_NAME + ".test_a11y_service";
57     private static final String KEY_RELATED_TOOLS_GROUP = "bluetooth_related_tools";
58     private static final String KEY_LIVE_CAPTION = "live_caption";
59 
60 
61     private BluetoothDetailsRelatedToolsController mController;
62     private BluetoothFeatureProvider mFeatureProvider;
63     private ShadowAccessibilityManager mShadowAccessibilityManager;
64     private PreferenceCategory mPreferenceCategory;
65 
66     @Override
setUp()67     public void setUp() {
68         super.setUp();
69         final FakeFeatureFactory fakeFeatureFactory = FakeFeatureFactory.setupForTest();
70         mFeatureProvider = fakeFeatureFactory.getBluetoothFeatureProvider();
71         mShadowAccessibilityManager = Shadow.extract(AccessibilityManager.getInstance(mContext));
72         final Preference preference = new Preference(mContext);
73         preference.setKey(KEY_LIVE_CAPTION);
74         mPreferenceCategory = new PreferenceCategory(mContext);
75         mPreferenceCategory.setKey(KEY_RELATED_TOOLS_GROUP);
76         mScreen.addPreference(mPreferenceCategory);
77         mScreen.addPreference(preference);
78 
79         mController = new BluetoothDetailsRelatedToolsController(mContext, mFragment, mCachedDevice,
80                 mLifecycle);
81         mController.init(mScreen);
82     }
83 
84     @Test
isAvailable_isHearingAidDevice_available()85     public void isAvailable_isHearingAidDevice_available() {
86         when(mCachedDevice.isHearingAidDevice()).thenReturn(true);
87 
88         assertThat(mController.isAvailable()).isTrue();
89     }
90 
91     @Test
isAvailable_isNotHearingAidDevice_notAvailable()92     public void isAvailable_isNotHearingAidDevice_notAvailable() {
93         when(mCachedDevice.isHearingAidDevice()).thenReturn(false);
94 
95         assertThat(mController.isAvailable()).isFalse();
96     }
97 
98     @Test
displayPreference_oneRelatedToolsMatchA11yService_showOnePreference()99     public void displayPreference_oneRelatedToolsMatchA11yService_showOnePreference() {
100         when(mCachedDevice.isHearingAidDevice()).thenReturn(true);
101         mShadowAccessibilityManager.setInstalledAccessibilityServiceList(
102                 List.of(getMockAccessibilityServiceInfo(PACKAGE_NAME, CLASS_NAME)));
103         when(mFeatureProvider.getRelatedTools()).thenReturn(
104                 List.of(new ComponentName(PACKAGE_NAME, CLASS_NAME)));
105 
106         mController.displayPreference(mScreen);
107 
108         assertThat(mPreferenceCategory.getPreferenceCount()).isEqualTo(1);
109     }
110 
111     @Test
displayPreference_oneRelatedToolsNotMatchA11yService_showNoPreference()112     public void displayPreference_oneRelatedToolsNotMatchA11yService_showNoPreference() {
113         when(mCachedDevice.isHearingAidDevice()).thenReturn(true);
114         mShadowAccessibilityManager.setInstalledAccessibilityServiceList(
115                 List.of(getMockAccessibilityServiceInfo(PACKAGE_NAME, CLASS_NAME)));
116         when(mFeatureProvider.getRelatedTools()).thenReturn(
117                 List.of(new ComponentName(PACKAGE_NAME2, CLASS_NAME)));
118 
119         mController.displayPreference(mScreen);
120 
121         assertThat(mPreferenceCategory.getPreferenceCount()).isEqualTo(0);
122     }
123 
124     @Test
displayPreference_noRelatedTools_showNoPreference()125     public void displayPreference_noRelatedTools_showNoPreference() {
126         when(mCachedDevice.isHearingAidDevice()).thenReturn(true);
127         mShadowAccessibilityManager.setInstalledAccessibilityServiceList(
128                 List.of(getMockAccessibilityServiceInfo(PACKAGE_NAME, CLASS_NAME)));
129         when(mFeatureProvider.getRelatedTools()).thenReturn(null);
130 
131         mController.displayPreference(mScreen);
132 
133         assertThat(mPreferenceCategory.getPreferenceCount()).isEqualTo(0);
134     }
135 
getMockAccessibilityServiceInfo(String packageName, String className)136     private AccessibilityServiceInfo getMockAccessibilityServiceInfo(String packageName,
137             String className) {
138         final ApplicationInfo applicationInfo = new ApplicationInfo();
139         final ServiceInfo serviceInfo = new ServiceInfo();
140         applicationInfo.packageName = packageName;
141         serviceInfo.packageName = packageName;
142         serviceInfo.name = className;
143         serviceInfo.applicationInfo = applicationInfo;
144 
145         final ResolveInfo resolveInfo = new ResolveInfo();
146         resolveInfo.serviceInfo = serviceInfo;
147 
148         try {
149             final AccessibilityServiceInfo info = new AccessibilityServiceInfo(resolveInfo,
150                     mContext);
151             ComponentName componentName = ComponentName.unflattenFromString(
152                     packageName + "/" + className);
153             info.setComponentName(componentName);
154             return info;
155         } catch (XmlPullParserException | IOException e) {
156             // Do nothing
157         }
158 
159         return null;
160     }
161 }
162