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 android.settings.cts;
18 
19 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
20 import static android.provider.Settings.Secure;
21 import static com.google.common.truth.Truth.assertThat;
22 import static org.junit.Assume.assumeFalse;
23 
24 import android.app.slice.Slice;
25 import android.app.slice.SliceManager;
26 import android.content.ComponentName;
27 import android.content.Context;
28 import android.content.Intent;
29 import android.content.pm.PackageManager;
30 import android.content.pm.PackageManager.NameNotFoundException;
31 import android.content.pm.ResolveInfo;
32 import android.net.Uri;
33 import android.net.wifi.WifiManager;
34 import android.os.Process;
35 import android.text.TextUtils;
36 import android.util.Log;
37 
38 import androidx.slice.SliceConvert;
39 import androidx.slice.SliceMetadata;
40 import androidx.slice.core.SliceAction;
41 import androidx.test.InstrumentationRegistry;
42 import androidx.test.runner.AndroidJUnit4;
43 
44 import org.junit.After;
45 import org.junit.Before;
46 import org.junit.Test;
47 import org.junit.runner.RunWith;
48 
49 import java.util.Collections;
50 import java.util.List;
51 
52 @RunWith(AndroidJUnit4.class)
53 public class WifiSliceTest {
54   private static final String TAG = "WifiSliceTest";
55 
56   private static final Uri WIFI_SLICE_URI =
57           Uri.parse("content://android.settings.slices/action/wifi");
58 
59   private static final String ACTION_ASSIST = "android.intent.action.ASSIST";
60   private static final String ACTION_VOICE_ASSIST = "android.intent.action.VOICE_ASSIST";
61   private static final String CATEGORY_DEFAULT = "android.intent.category.DEFAULT";
62   private static final String FEATURE_VOICE_RECOGNIZERS = "android.software.voice_recognizers";
63   private static final String ASSISTANT = "assistant";
64 
65   private final Context mContext = InstrumentationRegistry.getContext();
66   private final SliceManager mSliceManager = mContext.getSystemService(SliceManager.class);
67   private final boolean mHasVoiceRecognizersFeature =
68           mContext.getPackageManager().hasSystemFeature(FEATURE_VOICE_RECOGNIZERS);
69 
70   private Slice mWifiSlice;
71   private String mAssistant;
72 
73   @Before
setUp()74   public void setUp() throws Exception {
75     assumeFalse("Skipping test: Auto does not support provider android.settings.slices", isCar());
76     assumeFalse("Skipping test: TV does not support provider android.settings.slices", isTv());
77     assumeFalse(
78         "Skipping test: Watch does not support provider android.settings.slices", isWatch());
79     mWifiSlice = mSliceManager.bindSlice(WIFI_SLICE_URI, Collections.emptySet());
80     mAssistant = Secure.getString(mContext.getContentResolver(), ASSISTANT);
81   }
82 
83   @After
tearDown()84   public void tearDown() {
85     final String assistant = Secure.getString(mContext.getContentResolver(), ASSISTANT);
86     if (!TextUtils.equals(mAssistant, assistant)) {
87       Secure.putString(mContext.getContentResolver(), ASSISTANT, mAssistant);
88     }
89   }
90 
91   @Test
wifiSliceToggle_changeWifiState()92   public void wifiSliceToggle_changeWifiState() {
93     SliceMetadata mWifiSliceMetadata =
94             SliceMetadata.from(mContext, SliceConvert.wrap(mWifiSlice, mContext));
95     List<SliceAction> wifiSliceActions = mWifiSliceMetadata.getToggles();
96     if (wifiSliceActions.size() != 0) {
97       SliceAction toggleAction = wifiSliceActions.get(0);
98 
99       toggleAction.setChecked(true);
100       assertThat(toggleAction.isChecked()).isEqualTo(isWifiEnabled());
101 
102       toggleAction.setChecked(false);
103       assertThat(toggleAction.isChecked()).isEqualTo(isWifiEnabled());
104     }
105   }
106 
107   @Test
wifiSlice_hasCorrectUri()108   public void wifiSlice_hasCorrectUri() {
109     assertThat(mWifiSlice.getUri()).isEqualTo(WIFI_SLICE_URI);
110   }
111 
112   @Test
wifiSlice_grantedPermissionToDefaultAssistant()113   public void wifiSlice_grantedPermissionToDefaultAssistant() throws NameNotFoundException {
114     if (!mHasVoiceRecognizersFeature) {
115       Log.i(TAG, "The device doesn't support feature: " + FEATURE_VOICE_RECOGNIZERS);
116       return;
117     }
118     final PackageManager pm = mContext.getPackageManager();
119     final Intent requestDefaultAssistant =
120             new Intent(ACTION_ASSIST).addCategory(CATEGORY_DEFAULT);
121 
122     final List<ResolveInfo> infos = pm.queryIntentActivities(requestDefaultAssistant, 0);
123 
124     if (!infos.isEmpty()) {
125       final String packageName;
126       if (!TextUtils.isEmpty(mAssistant)) {
127         packageName = ComponentName.unflattenFromString(mAssistant).getPackageName();
128         Log.i(TAG, "Default assistant: " + packageName);
129       } else {
130         packageName = infos.get(0).activityInfo.packageName;
131         Log.i(TAG, "Set assistant: " + packageName);
132         Secure.putString(mContext.getContentResolver(), ASSISTANT,
133                 new ComponentName(packageName, infos.get(0).activityInfo.name).flattenToString());
134       }
135       final int testPid = Process.myPid();
136       final int testUid = pm.getPackageUid(packageName, 0);
137 
138       assertThat(mSliceManager.checkSlicePermission(WIFI_SLICE_URI, testPid, testUid))
139               .isEqualTo(PERMISSION_GRANTED);
140     }
141   }
142 
143   @Test
wifiSlice_grantedPermissionToDefaultVoiceAssistant()144   public void wifiSlice_grantedPermissionToDefaultVoiceAssistant() throws NameNotFoundException {
145     if (!mHasVoiceRecognizersFeature) {
146       Log.i(TAG, "The device doesn't support feature: " + FEATURE_VOICE_RECOGNIZERS);
147       return;
148     }
149     final PackageManager pm = mContext.getPackageManager();
150     final Intent requestDefaultAssistant =
151             new Intent(ACTION_VOICE_ASSIST).addCategory(CATEGORY_DEFAULT);
152 
153     final ResolveInfo info = pm.resolveActivity(requestDefaultAssistant, 0);
154 
155     if (info != null) {
156       final int testPid = Process.myPid();
157       final int testUid = pm.getPackageUid(info.activityInfo.packageName, 0);
158 
159       assertThat(mSliceManager.checkSlicePermission(WIFI_SLICE_URI, testPid, testUid))
160               .isEqualTo(PERMISSION_GRANTED);
161     }
162   }
163 
isCar()164   private boolean isCar() {
165     PackageManager pm = mContext.getPackageManager();
166     return pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
167   }
168 
isTv()169   private boolean isTv() {
170     PackageManager pm = mContext.getPackageManager();
171     return pm.hasSystemFeature(PackageManager.FEATURE_TELEVISION)
172             && pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK);
173   }
174 
isWatch()175   private boolean isWatch() {
176     return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
177   }
178 
isWifiEnabled()179   private boolean isWifiEnabled() {
180     final WifiManager wifiManager = mContext.getSystemService(WifiManager.class);
181     return wifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLED
182             || wifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLING;
183   }
184 
185 }
186