OSDN Git Service

Merge "Add dynamic summaries to Slices"
[android-x86/packages-apps-Settings.git] / tests / unit / src / com / android / settings / wifi / tether / TetherServiceTest.java
1 /*
2  * Copyright (C) 2016 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.wifi.tether;
18
19 import static org.junit.Assert.*;
20 import static org.mockito.Matchers.*;
21 import static org.mockito.Mockito.verify;
22 import static org.mockito.Mockito.when;
23 import static android.net.ConnectivityManager.EXTRA_ADD_TETHER_TYPE;
24 import static android.net.ConnectivityManager.EXTRA_PROVISION_CALLBACK;
25 import static android.net.ConnectivityManager.EXTRA_REM_TETHER_TYPE;
26 import static android.net.ConnectivityManager.EXTRA_RUN_PROVISION;
27 import static android.net.ConnectivityManager.EXTRA_SET_ALARM;
28 import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
29 import static android.net.ConnectivityManager.TETHERING_INVALID;
30 import static android.net.ConnectivityManager.TETHERING_USB;
31 import static android.net.ConnectivityManager.TETHERING_WIFI;
32 import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
33 import static android.net.ConnectivityManager.TETHER_ERROR_PROVISION_FAILED;
34
35 import android.app.Activity;
36 import android.app.AlarmManager;
37 import android.app.PendingIntent;
38 import android.app.usage.UsageStatsManager;
39 import android.content.BroadcastReceiver;
40 import android.content.Context;
41 import android.content.ContextWrapper;
42 import android.content.Intent;
43 import android.content.IntentFilter;
44 import android.content.pm.ActivityInfo;
45 import android.content.pm.ApplicationInfo;
46 import android.content.pm.ResolveInfo;
47 import android.content.pm.PackageManager;
48 import android.content.SharedPreferences;
49 import android.content.SharedPreferences.Editor;
50 import android.content.res.Resources;
51 import android.net.ConnectivityManager;
52 import android.net.wifi.WifiManager;
53 import android.os.Bundle;
54 import android.os.ResultReceiver;
55 import android.os.SystemClock;
56 import android.test.ServiceTestCase;
57 import android.util.Log;
58
59 import org.mockito.ArgumentCaptor;
60 import org.mockito.Captor;
61 import org.mockito.Mock;
62 import org.mockito.MockitoAnnotations;
63
64 import java.lang.ref.WeakReference;
65 import java.util.ArrayList;
66 import java.util.HashSet;
67 import java.util.List;
68 import java.util.Set;
69
70 public class TetherServiceTest extends ServiceTestCase<TetherService> {
71
72     private static final String TAG = "TetherServiceTest";
73     private static final String FAKE_PACKAGE_NAME = "com.some.package.name";
74     private static final String ENTITLEMENT_PACKAGE_NAME = "com.some.entitlement.name";
75     private static final String TEST_RESPONSE_ACTION = "testProvisioningResponseAction";
76     private static final String TEST_NO_UI_ACTION = "testNoUiProvisioningRequestAction";
77     private static final int BOGUS_RECEIVER_RESULT = -5;
78     private static final int TEST_CHECK_PERIOD = 100;
79     private static final int MS_PER_HOUR = 60 * 60 * 1000;
80     private static final int SHORT_TIMEOUT = 100;
81     private static final int PROVISION_TIMEOUT = 1000;
82
83     private TetherService mService;
84     private MockResources mResources;
85     private FakeUsageStatsManagerWrapper mUsageStatsManagerWrapper;
86     int mLastReceiverResultCode = BOGUS_RECEIVER_RESULT;
87     private int mLastTetherRequestType = TETHERING_INVALID;
88     private int mProvisionResponse = BOGUS_RECEIVER_RESULT;
89     private ProvisionReceiver mProvisionReceiver;
90     private Receiver mResultReceiver;
91
92     @Mock private AlarmManager mAlarmManager;
93     @Mock private ConnectivityManager mConnectivityManager;
94     @Mock private PackageManager mPackageManager;
95     @Mock private WifiManager mWifiManager;
96     @Mock private SharedPreferences mPrefs;
97     @Mock private Editor mPrefEditor;
98     @Captor private ArgumentCaptor<PendingIntent> mPiCaptor;
99     @Captor private ArgumentCaptor<String> mStoredTypes;
100
101     public TetherServiceTest() {
102         super(TetherService.class);
103     }
104
105     @Override
106     protected void setUp() throws Exception {
107         super.setUp();
108         MockitoAnnotations.initMocks(this);
109
110         mResources = new MockResources();
111         mContext = new TestContextWrapper(getContext());
112         setContext(mContext);
113
114         mResultReceiver = new Receiver(this);
115         mLastReceiverResultCode = BOGUS_RECEIVER_RESULT;
116         mProvisionResponse = Activity.RESULT_OK;
117         mProvisionReceiver = new ProvisionReceiver();
118         IntentFilter filter = new IntentFilter(TEST_NO_UI_ACTION);
119         filter.addCategory(Intent.CATEGORY_DEFAULT);
120         mContext.registerReceiver(mProvisionReceiver, filter);
121
122         final String CURRENT_TYPES = "currentTethers";
123         when(mPrefs.getString(CURRENT_TYPES, "")).thenReturn("");
124         when(mPrefs.edit()).thenReturn(mPrefEditor);
125         when(mPrefEditor.putString(eq(CURRENT_TYPES), mStoredTypes.capture())).thenReturn(
126                 mPrefEditor);
127         mUsageStatsManagerWrapper = new FakeUsageStatsManagerWrapper(mContext);
128
129         ResolveInfo systemAppResolveInfo = new ResolveInfo();
130         ActivityInfo systemActivityInfo = new ActivityInfo();
131         systemActivityInfo.packageName = ENTITLEMENT_PACKAGE_NAME;
132         ApplicationInfo systemAppInfo = new ApplicationInfo();
133         systemAppInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
134         systemActivityInfo.applicationInfo = systemAppInfo;
135         systemAppResolveInfo.activityInfo = systemActivityInfo;
136
137         ResolveInfo nonSystemResolveInfo = new ResolveInfo();
138         ActivityInfo nonSystemActivityInfo = new ActivityInfo();
139         nonSystemActivityInfo.packageName = FAKE_PACKAGE_NAME;
140         nonSystemActivityInfo.applicationInfo = new ApplicationInfo();
141         nonSystemResolveInfo.activityInfo = nonSystemActivityInfo;
142
143         List<ResolveInfo> resolvers = new ArrayList();
144         resolvers.add(nonSystemResolveInfo);
145         resolvers.add(systemAppResolveInfo);
146         when(mPackageManager.queryBroadcastReceivers(
147                 any(Intent.class), eq(PackageManager.MATCH_ALL))).thenReturn(resolvers);
148     }
149
150     @Override
151     protected void tearDown() throws Exception {
152         mContext.unregisterReceiver(mProvisionReceiver);
153         super.tearDown();
154     }
155
156     private void cancelAllProvisioning() {
157         int[] types = new int[]{TETHERING_BLUETOOTH, TETHERING_WIFI, TETHERING_USB};
158         for (int type : types) {
159             Intent intent = new Intent();
160             intent.putExtra(EXTRA_REM_TETHER_TYPE, type);
161             startService(intent);
162         }
163     }
164
165     public void testStartForProvision() {
166         runProvisioningForType(TETHERING_WIFI);
167
168         assertTrue(waitForProvisionRequest(TETHERING_WIFI));
169         assertTrue(waitForProvisionResponse(TETHER_ERROR_NO_ERROR));
170     }
171
172     public void testStartKeepsProvisionAppActive() {
173         setupService();
174         getService().setUsageStatsManagerWrapper(mUsageStatsManagerWrapper);
175
176         runProvisioningForType(TETHERING_WIFI);
177
178         assertTrue(waitForProvisionRequest(TETHERING_WIFI));
179         assertTrue(waitForProvisionResponse(TETHER_ERROR_NO_ERROR));
180         assertFalse(mUsageStatsManagerWrapper.isAppInactive(ENTITLEMENT_PACKAGE_NAME));
181         // Non-system handler of the intent action should stay idle.
182         assertTrue(mUsageStatsManagerWrapper.isAppInactive(FAKE_PACKAGE_NAME));
183     }
184
185     public void testScheduleRechecks() {
186         Intent intent = new Intent();
187         intent.putExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_WIFI);
188         intent.putExtra(EXTRA_SET_ALARM, true);
189         startService(intent);
190
191         long period = TEST_CHECK_PERIOD * MS_PER_HOUR;
192         verify(mAlarmManager).setRepeating(eq(AlarmManager.ELAPSED_REALTIME), anyLong(),
193                 eq(period), mPiCaptor.capture());
194         PendingIntent pi = mPiCaptor.getValue();
195         assertEquals(TetherService.class.getName(), pi.getIntent().getComponent().getClassName());
196     }
197
198     public void testStartMultiple() {
199         runProvisioningForType(TETHERING_WIFI);
200
201         assertTrue(waitForProvisionRequest(TETHERING_WIFI));
202         assertTrue(waitForProvisionResponse(TETHER_ERROR_NO_ERROR));
203
204         runProvisioningForType(TETHERING_USB);
205
206         assertTrue(waitForProvisionRequest(TETHERING_USB));
207         assertTrue(waitForProvisionResponse(TETHER_ERROR_NO_ERROR));
208
209         runProvisioningForType(TETHERING_BLUETOOTH);
210
211         assertTrue(waitForProvisionRequest(TETHERING_BLUETOOTH));
212         assertTrue(waitForProvisionResponse(TETHER_ERROR_NO_ERROR));
213     }
214
215     public void testPersistTypes() {
216         runProvisioningForType(TETHERING_WIFI);
217
218         waitForProvisionRequest(TETHERING_WIFI);
219         waitForProvisionResponse(TETHER_ERROR_NO_ERROR);
220
221         runProvisioningForType(TETHERING_BLUETOOTH);
222
223         waitForProvisionRequest(TETHERING_BLUETOOTH);
224         waitForProvisionResponse(TETHER_ERROR_NO_ERROR);
225
226         shutdownService();
227         assertEquals(TETHERING_WIFI + "," + TETHERING_BLUETOOTH, mStoredTypes.getValue());
228     }
229
230     public void testFailureStopsTethering_Wifi() {
231         mProvisionResponse = Activity.RESULT_CANCELED;
232
233         runProvisioningForType(TETHERING_WIFI);
234
235         assertTrue(waitForProvisionRequest(TETHERING_WIFI));
236         assertTrue(waitForProvisionResponse(TETHER_ERROR_PROVISION_FAILED));
237
238         verify(mConnectivityManager).stopTethering(ConnectivityManager.TETHERING_WIFI);
239     }
240
241     public void testFailureStopsTethering_Usb() {
242         mProvisionResponse = Activity.RESULT_CANCELED;
243
244         runProvisioningForType(TETHERING_USB);
245
246         assertTrue(waitForProvisionRequest(TETHERING_USB));
247         assertTrue(waitForProvisionResponse(TETHER_ERROR_PROVISION_FAILED));
248
249         verify(mConnectivityManager).setUsbTethering(eq(false));
250     }
251
252     public void testCancelAlarm() {
253         runProvisioningForType(TETHERING_WIFI);
254
255         assertTrue(waitForProvisionRequest(TETHERING_WIFI));
256         assertTrue(waitForProvisionResponse(TETHER_ERROR_NO_ERROR));
257
258         Intent intent = new Intent();
259         intent.putExtra(EXTRA_REM_TETHER_TYPE, TETHERING_WIFI);
260         startService(intent);
261
262         verify(mAlarmManager).cancel(mPiCaptor.capture());
263         PendingIntent pi = mPiCaptor.getValue();
264         assertEquals(TetherService.class.getName(), pi.getIntent().getComponent().getClassName());
265     }
266
267     private void runProvisioningForType(int type) {
268         Intent intent = new Intent();
269         intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
270         intent.putExtra(EXTRA_RUN_PROVISION, true);
271         intent.putExtra(EXTRA_PROVISION_CALLBACK, mResultReceiver);
272         startService(intent);
273     }
274
275     private boolean waitForAppInactive(UsageStatsManager usageStatsManager, String packageName) {
276         long startTime = SystemClock.uptimeMillis();
277         while (true) {
278             if (usageStatsManager.isAppInactive(packageName)) {
279                 return true;
280             }
281             if ((SystemClock.uptimeMillis() - startTime) > PROVISION_TIMEOUT) {
282                 return false;
283             }
284             SystemClock.sleep(SHORT_TIMEOUT);
285         }
286     }
287
288     private boolean waitForProvisionRequest(int expectedType) {
289         long startTime = SystemClock.uptimeMillis();
290         while (true) {
291             if (mLastTetherRequestType == expectedType) {
292                 mLastTetherRequestType = -1;
293                 return true;
294             }
295             if ((SystemClock.uptimeMillis() - startTime) > PROVISION_TIMEOUT) {
296                 Log.v(TAG, String.format(
297                         "waitForProvisionRequest timeout: expected=%d, actual=%d",
298                         expectedType, mLastTetherRequestType));
299                 return false;
300             }
301             SystemClock.sleep(SHORT_TIMEOUT);
302         }
303     }
304
305     private boolean waitForProvisionResponse(int expectedValue) {
306         long startTime = SystemClock.uptimeMillis();
307         while (true) {
308             if (mLastReceiverResultCode == expectedValue) {
309                 mLastReceiverResultCode = BOGUS_RECEIVER_RESULT;
310                 return true;
311             }
312             if ((SystemClock.uptimeMillis() - startTime) > PROVISION_TIMEOUT) {
313                 Log.v(TAG, String.format(
314                         "waitForProvisionResponse timeout: expected=%d, actual=%d",
315                         expectedValue, mLastReceiverResultCode));
316                 return false;
317             }
318             SystemClock.sleep(SHORT_TIMEOUT);
319         }
320     }
321
322     private static class MockResources extends android.test.mock.MockResources {
323         @Override
324         public int getInteger(int id) {
325             switch(id) {
326                 case com.android.internal.R.integer.config_mobile_hotspot_provision_check_period:
327                     return TEST_CHECK_PERIOD;
328                 default:
329                     return 0;
330             }
331         }
332
333         @Override
334         public String getString(int id) {
335             switch(id) {
336                 case com.android.internal.R.string.config_mobile_hotspot_provision_response:
337                     return TEST_RESPONSE_ACTION;
338                 case com.android.internal.R.string.config_mobile_hotspot_provision_app_no_ui:
339                     return TEST_NO_UI_ACTION;
340                 default:
341                     return null;
342             }
343         }
344     }
345
346     private class TestContextWrapper extends ContextWrapper {
347
348         public TestContextWrapper(Context base) {
349             super(base);
350         }
351
352         @Override
353         public Resources getResources() {
354             return mResources;
355         }
356
357         @Override
358         public SharedPreferences getSharedPreferences(String name, int mode) {
359             // Stub out prefs to control the persisted tether type list.
360             if (name == "tetherPrefs") {
361                 return mPrefs;
362             }
363             return super.getSharedPreferences(name, mode);
364         }
365
366         @Override
367         public PackageManager getPackageManager() {
368             return mPackageManager;
369         }
370
371         @Override
372         public Object getSystemService(String name) {
373             if (ALARM_SERVICE.equals(name)) {
374                 return mAlarmManager;
375             } else if (CONNECTIVITY_SERVICE.equals(name)) {
376                 return mConnectivityManager;
377             } else if (WIFI_SERVICE.equals(name)) {
378                 return mWifiManager;
379             }
380
381             return super.getSystemService(name);
382         }
383     }
384
385     private static final class Receiver extends ResultReceiver {
386         final WeakReference<TetherServiceTest> mTest;
387
388         Receiver(TetherServiceTest test) {
389             super(null);
390             mTest = new WeakReference<TetherServiceTest>(test);
391         }
392
393         @Override
394         protected void onReceiveResult(int resultCode, Bundle resultData) {
395             TetherServiceTest test = mTest.get();
396             if (test != null) {
397                 test.mLastReceiverResultCode = resultCode;
398             }
399         }
400     };
401
402     /**
403      * Stubs out the provisioning app receiver.
404      */
405     private class ProvisionReceiver extends BroadcastReceiver {
406         @Override
407         public void onReceive(Context context, Intent intent) {
408             mLastTetherRequestType = intent.getIntExtra("TETHER_TYPE", TETHERING_INVALID);
409             sendResponse(mProvisionResponse, context);
410         }
411
412         private void sendResponse(int response, Context context) {
413             Intent responseIntent = new Intent(TEST_RESPONSE_ACTION);
414             responseIntent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
415             responseIntent.putExtra(TetherService.EXTRA_RESULT, response);
416             context.sendBroadcast(
417                     responseIntent, android.Manifest.permission.CONNECTIVITY_INTERNAL);
418         }
419     }
420
421     private static class FakeUsageStatsManagerWrapper
422             extends TetherService.UsageStatsManagerWrapper {
423         private final Set<String> mActivePackages;
424
425         FakeUsageStatsManagerWrapper(Context context) {
426             super(context);
427             mActivePackages = new HashSet<>();
428         }
429
430         @Override
431         void setAppInactive(String packageName, boolean isInactive) {
432             if (!isInactive) {
433                 mActivePackages.add(packageName);
434             } else {
435                 mActivePackages.remove(packageName);
436             }
437         }
438
439         boolean isAppInactive(String packageName) {
440             return !mActivePackages.contains(packageName);
441         }
442     }
443 }