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 android.appsecurity.cts;
18 
19 import static org.junit.Assert.assertNotNull;
20 import static org.junit.Assert.fail;
21 import static org.junit.Assume.assumeFalse;
22 
23 import android.platform.test.annotations.AppModeFull;
24 import android.platform.test.annotations.AsbSecurityTest;
25 
26 import com.android.tradefed.log.LogUtil.CLog;
27 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
28 
29 import org.junit.After;
30 import org.junit.Before;
31 import org.junit.Test;
32 import org.junit.runner.RunWith;
33 
34 import java.util.ArrayList;
35 import java.util.HashMap;
36 import java.util.List;
37 import java.util.Map;
38 
39 /**
40  * Tests for ephemeral packages.
41  */
42 @RunWith(DeviceJUnit4ClassRunner.class)
43 @AppModeFull(reason = "Already handles instant installs when needed")
44 public class EphemeralTest extends BaseAppSecurityTest {
45 
46     // a normally installed application
47     private static final String NORMAL_APK = "CtsEphemeralTestsNormalApp.apk";
48     private static final String NORMAL_PKG = "com.android.cts.normalapp";
49 
50     // the first ephemerally installed application
51     private static final String EPHEMERAL_1_APK = "CtsEphemeralTestsEphemeralApp1.apk";
52     private static final String EPHEMERAL_1_PKG = "com.android.cts.ephemeralapp1";
53 
54     // the second ephemerally installed application
55     private static final String EPHEMERAL_2_APK = "CtsEphemeralTestsEphemeralApp2.apk";
56     private static final String EPHEMERAL_2_PKG = "com.android.cts.ephemeralapp2";
57 
58     // a normally installed application with implicitly exposed components
59     private static final String IMPLICIT_APK = "CtsEphemeralTestsImplicitApp.apk";
60     private static final String IMPLICIT_PKG = "com.android.cts.implicitapp";
61 
62     // a normally installed application with no exposed components
63     private static final String UNEXPOSED_APK = "CtsEphemeralTestsUnexposedApp.apk";
64     private static final String UNEXPOSED_PKG = "com.android.cts.unexposedapp";
65 
66     // an application that gets upgraded from 'instant' to 'full'
67     private static final String UPGRADED_APK = "CtsInstantUpgradeApp.apk";
68     private static final String UPGRADED_PKG = "com.android.cts.instantupgradeapp";
69 
70     private static final String TEST_CLASS = ".ClientTest";
71     private static final String WEBVIEW_TEST_CLASS = ".WebViewTest";
72 
73     private static final List<Map<String, String>> EXPECTED_EXPOSED_INTENTS =
74             new ArrayList<>();
75     static {
76         // Framework intents we expect the system to expose to instant applications
77         EXPECTED_EXPOSED_INTENTS.add(makeArgs(
78                 "android.intent.action.CHOOSER",
79                 null, null));
80         // Contact intents we expect the system to expose to instant applications
81         EXPECTED_EXPOSED_INTENTS.add(makeArgs(
82                 "android.intent.action.PICK", null, "vnd.android.cursor.dir/contact"));
83         EXPECTED_EXPOSED_INTENTS.add(makeArgs(
84                 "android.intent.action.PICK", null, "vnd.android.cursor.dir/phone_v2"));
85         EXPECTED_EXPOSED_INTENTS.add(makeArgs(
86                 "android.intent.action.PICK", null, "vnd.android.cursor.dir/email_v2"));
87         EXPECTED_EXPOSED_INTENTS.add(makeArgs(
88                 "android.intent.action.PICK", null, "vnd.android.cursor.dir/postal-address_v2"));
89         // Storage intents we expect the system to expose to instant applications
90         EXPECTED_EXPOSED_INTENTS.add(makeArgs(
91                 "android.intent.action.OPEN_DOCUMENT",
92                 "android.intent.category.OPENABLE", "\\*/\\*"));
93         EXPECTED_EXPOSED_INTENTS.add(makeArgs(
94                 "android.intent.action.OPEN_DOCUMENT", null, "\\*/\\*"));
95         EXPECTED_EXPOSED_INTENTS.add(makeArgs(
96                 "android.intent.action.GET_CONTENT",
97                 "android.intent.category.OPENABLE", "\\*/\\*"));
98         EXPECTED_EXPOSED_INTENTS.add(makeArgs(
99                 "android.intent.action.GET_CONTENT", null, "\\*/\\*"));
100         EXPECTED_EXPOSED_INTENTS.add(makeArgs(
101                 "android.intent.action.OPEN_DOCUMENT_TREE", null, null));
102         EXPECTED_EXPOSED_INTENTS.add(makeArgs(
103                 "android.intent.action.CREATE_DOCUMENT",
104                 "android.intent.category.OPENABLE", "text/plain"));
105         EXPECTED_EXPOSED_INTENTS.add(makeArgs(
106                 "android.intent.action.CREATE_DOCUMENT", null, "text/plain"));
107         /** Camera intents we expect the system to expose to instant applications */
108         EXPECTED_EXPOSED_INTENTS.add(makeArgs(
109                 "android.media.action.IMAGE_CAPTURE", null, null));
110         EXPECTED_EXPOSED_INTENTS.add(makeArgs(
111                 "android.media.action.VIDEO_CAPTURE", null, null));
112     }
113 
114     private String mOldVerifierValue;
115     private Boolean mIsUnsupportedDevice;
116 
117     @Before
setUp()118     public void setUp() throws Exception {
119         mIsUnsupportedDevice = isDeviceUnsupported();
120         if (mIsUnsupportedDevice) {
121             return;
122         }
123 
124         Utils.prepareSingleUser(getDevice());
125         assertNotNull(getAbi());
126         assertNotNull(getBuild());
127 
128         uninstallTestPackages();
129         installTestPackages();
130     }
131 
132     @After
tearDown()133     public void tearDown() throws Exception {
134         if (mIsUnsupportedDevice) {
135             return;
136         }
137         uninstallTestPackages();
138     }
139 
140     @Test
testNormalQuery()141     public void testNormalQuery() throws Exception {
142         if (mIsUnsupportedDevice) {
143             return;
144         }
145         Utils.runDeviceTestsAsCurrentUser(getDevice(), NORMAL_PKG, TEST_CLASS, "testQuery");
146     }
147 
148     @Test
testNormalStartNormal()149     public void testNormalStartNormal() throws Exception {
150         if (mIsUnsupportedDevice) {
151             return;
152         }
153         Utils.runDeviceTestsAsCurrentUser(getDevice(), NORMAL_PKG, TEST_CLASS, "testStartNormal");
154     }
155 
156     @Test
testNormalStartEphemeral()157     public void testNormalStartEphemeral() throws Exception {
158         if (mIsUnsupportedDevice) {
159             return;
160         }
161         Utils.runDeviceTestsAsCurrentUser(getDevice(), NORMAL_PKG, TEST_CLASS,
162                 "testStartEphemeral");
163     }
164 
165     @Test
testEphemeralQuery()166     public void testEphemeralQuery() throws Exception {
167         if (mIsUnsupportedDevice) {
168             return;
169         }
170         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS, "testQuery");
171     }
172 
173     @Test
testEphemeralStartNormal()174     public void testEphemeralStartNormal() throws Exception {
175         if (mIsUnsupportedDevice) {
176             return;
177         }
178         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
179                 "testStartNormal");
180     }
181 
182     // each connection to an exposed component needs to run in its own test to
183     // avoid sharing state. once an instant app is exposed to a component, it's
184     // exposed until the device restarts or the instant app is removed.
185     @Test
testEphemeralStartExposed01()186     public void testEphemeralStartExposed01() throws Exception {
187         if (mIsUnsupportedDevice) {
188             return;
189         }
190         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
191                 "testStartExposed01");
192     }
193     @Test
testEphemeralStartExposed02()194     public void testEphemeralStartExposed02() throws Exception {
195         if (mIsUnsupportedDevice) {
196             return;
197         }
198         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
199                 "testStartExposed02");
200     }
201     @Test
testEphemeralStartExposed03()202     public void testEphemeralStartExposed03() throws Exception {
203         if (mIsUnsupportedDevice) {
204             return;
205         }
206         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
207                 "testStartExposed03");
208     }
209     @Test
testEphemeralStartExposed04()210     public void testEphemeralStartExposed04() throws Exception {
211         if (mIsUnsupportedDevice) {
212             return;
213         }
214         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
215                 "testStartExposed04");
216     }
217     @Test
testEphemeralStartExposed05()218     public void testEphemeralStartExposed05() throws Exception {
219         if (mIsUnsupportedDevice) {
220             return;
221         }
222         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
223                 "testStartExposed05");
224     }
225     @Test
testEphemeralStartExposed06()226     public void testEphemeralStartExposed06() throws Exception {
227         if (mIsUnsupportedDevice) {
228             return;
229         }
230         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
231                 "testStartExposed06");
232     }
233     @Test
testEphemeralStartExposed07()234     public void testEphemeralStartExposed07() throws Exception {
235         if (mIsUnsupportedDevice) {
236             return;
237         }
238         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
239                 "testStartExposed07");
240     }
241     @Test
testEphemeralStartExposed08()242     public void testEphemeralStartExposed08() throws Exception {
243         if (mIsUnsupportedDevice) {
244             return;
245         }
246         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
247                 "testStartExposed08");
248     }
249     @Test
testEphemeralStartExposed09()250     public void testEphemeralStartExposed09() throws Exception {
251         if (mIsUnsupportedDevice) {
252             return;
253         }
254         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
255                 "testStartExposed09");
256     }
257     @Test
testEphemeralStartExposed10()258     public void testEphemeralStartExposed10() throws Exception {
259         if (mIsUnsupportedDevice) {
260             return;
261         }
262         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
263                 "testStartExposed10");
264     }
265     @Test
testEphemeralStartExposed11()266     public void testEphemeralStartExposed11() throws Exception {
267         if (mIsUnsupportedDevice) {
268             return;
269         }
270         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
271                 "testStartExposed11");
272     }
273 
274     @Test
testEphemeralStartEphemeral()275     public void testEphemeralStartEphemeral() throws Exception {
276         if (mIsUnsupportedDevice) {
277             return;
278         }
279         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
280                 "testStartEphemeral");
281     }
282 
283     @Test
testEphemeralGetInstaller01()284     public void testEphemeralGetInstaller01() throws Exception {
285         if (mIsUnsupportedDevice) {
286             return;
287         }
288         installEphemeralApp(EPHEMERAL_1_APK, "com.android.cts.normalapp");
289         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
290                 "testGetInstaller01");
291     }
292     @Test
testEphemeralGetInstaller02()293     public void testEphemeralGetInstaller02() throws Exception {
294         if (mIsUnsupportedDevice) {
295             return;
296         }
297         installApp(NORMAL_APK, "com.android.cts.normalapp");
298         installEphemeralApp(EPHEMERAL_1_APK, "com.android.cts.normalapp");
299         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
300                 "testGetInstaller02");
301     }
302     @Test
testEphemeralGetInstaller03()303     public void testEphemeralGetInstaller03() throws Exception {
304         if (mIsUnsupportedDevice) {
305             return;
306         }
307         installApp(NORMAL_APK, "com.android.cts.normalapp");
308         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
309                 "testGetInstaller03");
310     }
311 
312     @Test
testExposedSystemActivities()313     public void testExposedSystemActivities() throws Exception {
314         if (mIsUnsupportedDevice) {
315             return;
316         }
317         for (Map<String, String> testArgs : EXPECTED_EXPOSED_INTENTS) {
318             final boolean exposed = isIntentExposed(testArgs);
319             if (exposed) {
320                 Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
321                         "testExposedActivity", testArgs);
322             } else {
323                 CLog.w("Skip intent; " + dumpArgs(testArgs));
324             }
325         }
326     }
327 
328     @Test
testBuildSerialUnknown()329     public void testBuildSerialUnknown() throws Exception {
330         if (mIsUnsupportedDevice) {
331             return;
332         }
333         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
334                 "testBuildSerialUnknown");
335     }
336 
337     @Test
testPackageInfo()338     public void testPackageInfo() throws Exception {
339         if (mIsUnsupportedDevice) {
340             return;
341         }
342         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
343                 "testPackageInfo");
344     }
345 
346     @Test
testActivityInfo()347     public void testActivityInfo() throws Exception {
348         if (mIsUnsupportedDevice) {
349             return;
350         }
351         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
352                 "testActivityInfo");
353     }
354 
355     @Test
testWebViewLoads()356     public void testWebViewLoads() throws Exception {
357         if (mIsUnsupportedDevice) {
358             return;
359         }
360         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, WEBVIEW_TEST_CLASS,
361                 "testWebViewLoads");
362     }
363 
364     @Test
testInstallPermissionNotGranted()365     public void testInstallPermissionNotGranted() throws Exception {
366         if (mIsUnsupportedDevice) {
367             return;
368         }
369         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
370                 "testInstallPermissionNotGranted");
371     }
372 
373     @Test
testInstallPermissionGranted()374     public void testInstallPermissionGranted() throws Exception {
375         if (mIsUnsupportedDevice) {
376             return;
377         }
378         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
379                 "testInstallPermissionGranted");
380     }
381 
382     @Test
383     @AsbSecurityTest(cveBugId = 140256621)
testInstallPermissionNotGrantedInPackageInfo()384     public void testInstallPermissionNotGrantedInPackageInfo() throws Exception {
385         if (mIsUnsupportedDevice) {
386             return;
387         }
388         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
389                 "testInstallPermissionNotGrantedInPackageInfo");
390     }
391 
392     @Test
393     @AsbSecurityTest(cveBugId = 140256621)
testInstallPermissionGrantedInPackageInfo()394     public void testInstallPermissionGrantedInPackageInfo() throws Exception {
395         if (mIsUnsupportedDevice) {
396             return;
397         }
398         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
399                 "testInstallPermissionGrantedInPackageInfo");
400     }
401 
402     /** Test for android.permission.INSTANT_APP_FOREGROUND_SERVICE */
403     @Test
testStartForegroundService()404     public void testStartForegroundService() throws Exception {
405         if (mIsUnsupportedDevice) {
406             return;
407         }
408         // Make sure the test package does not have INSTANT_APP_FOREGROUND_SERVICE
409         getDevice().executeShellCommand("cmd package revoke --user cur " + EPHEMERAL_1_PKG
410                 + " android.permission.INSTANT_APP_FOREGROUND_SERVICE");
411         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
412                 "testStartForegroundService");
413     }
414 
415     /** Test for android.permission.RECORD_AUDIO */
416     @Test
testRecordAudioPermission()417     public void testRecordAudioPermission() throws Exception {
418         if (mIsUnsupportedDevice) {
419             return;
420         }
421         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
422                 "testRecordAudioPermission");
423     }
424 
425     /** Test for android.permission.CAMERA */
426     @Test
testCameraPermission()427     public void testCameraPermission() throws Exception {
428         if (mIsUnsupportedDevice) {
429             return;
430         }
431         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
432                 "testCameraPermission");
433     }
434 
435     /** Test for android.permission.READ_PHONE_NUMBERS */
436     @Test
testReadPhoneNumbersPermission()437     public void testReadPhoneNumbersPermission() throws Exception {
438         if (mIsUnsupportedDevice) {
439             return;
440         }
441         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
442                 "testReadPhoneNumbersPermission");
443     }
444 
445     /** Test for android.permission.ACCESS_COARSE_LOCATION */
446     @Test
testAccessCoarseLocationPermission()447     public void testAccessCoarseLocationPermission() throws Throwable {
448         if (mIsUnsupportedDevice) {
449             return;
450         }
451         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
452                 "testAccessCoarseLocationPermission");
453     }
454 
455     /** Test for android.permission.NETWORK */
456     @Test
testInternetPermission()457     public void testInternetPermission() throws Throwable {
458         if (mIsUnsupportedDevice) {
459             return;
460         }
461         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
462                 "testInternetPermission");
463     }
464 
465     /** Test for android.permission.VIBRATE */
466     @Test
testVibratePermission()467     public void testVibratePermission() throws Throwable {
468         if (mIsUnsupportedDevice) {
469             return;
470         }
471         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
472                 "testVibratePermission");
473     }
474 
475     /** Test for android.permission.WAKE_LOCK */
476     @Test
testWakeLockPermission()477     public void testWakeLockPermission() throws Throwable {
478         if (mIsUnsupportedDevice) {
479             return;
480         }
481         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
482                 "testWakeLockPermission");
483     }
484 
485     /** Test for search manager */
486     @Test
testGetSearchableInfo()487     public void testGetSearchableInfo() throws Throwable {
488         if (mIsUnsupportedDevice) {
489             return;
490         }
491         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
492                 "testGetSearchableInfo");
493     }
494 
495     /** Test for upgrade from instant --> full */
496     @Test
testInstantAppUpgrade()497     public void testInstantAppUpgrade() throws Throwable {
498         if (mIsUnsupportedDevice) {
499             return;
500         }
501         installEphemeralApp(UPGRADED_APK);
502         Utils.runDeviceTestsAsCurrentUser(getDevice(), UPGRADED_PKG, TEST_CLASS,
503                 "testInstantApplicationWritePreferences");
504         Utils.runDeviceTestsAsCurrentUser(getDevice(), UPGRADED_PKG, TEST_CLASS,
505                 "testInstantApplicationWriteFile");
506         installFullApp(UPGRADED_APK);
507         Utils.runDeviceTestsAsCurrentUser(getDevice(), UPGRADED_PKG, TEST_CLASS,
508                 "testFullApplicationReadPreferences");
509         Utils.runDeviceTestsAsCurrentUser(getDevice(), UPGRADED_PKG, TEST_CLASS,
510                 "testFullApplicationReadFile");
511     }
512 
513     @Test
testGetChangedPackages()514     public void testGetChangedPackages() throws Throwable {
515         if (mIsUnsupportedDevice) {
516             return;
517         }
518         Utils.runDeviceTestsAsCurrentUser(getDevice(), NORMAL_PKG, TEST_CLASS,
519                 "testGetChangedPackages");
520         Utils.runDeviceTestsAsCurrentUser(getDevice(), EPHEMERAL_1_PKG, TEST_CLASS,
521                 "testGetChangedPackages");
522     }
523 
524     @Test
uninstall_userInstalledApp_shouldBeUserInitiated()525     public void uninstall_userInstalledApp_shouldBeUserInitiated() throws Throwable {
526         assumeFalse("Device does not support instant app", mIsUnsupportedDevice);
527         installEphemeralApp(EPHEMERAL_1_APK, NORMAL_PKG);
528 
529         Utils.runDeviceTestsAsCurrentUser(getDevice(), NORMAL_PKG, TEST_CLASS,
530                 "uninstall_userInstalledApp_shouldBeUserInitiated");
531     }
532 
533     @Test
uninstall_pruneInstantApp_shouldNotBeUserInitiated()534     public void uninstall_pruneInstantApp_shouldNotBeUserInitiated()
535             throws Throwable {
536         assumeFalse("Device does not support instant app", mIsUnsupportedDevice);
537 
538         Utils.runDeviceTestsAsCurrentUser(getDevice(), NORMAL_PKG, TEST_CLASS,
539                 "uninstall_pruneInstantApp_shouldNotBeUserInitiated");
540     }
541 
makeArgs( String action, String category, String mimeType)542     private static final HashMap<String, String> makeArgs(
543             String action, String category, String mimeType) {
544         if (action == null || action.length() == 0) {
545             fail("action not specified");
546         }
547         final HashMap<String, String> testArgs = new HashMap<>();
548         testArgs.put("action", action);
549         if (category != null && category.length() > 0) {
550             testArgs.put("category", category);
551         }
552         if (mimeType != null && mimeType.length() > 0) {
553             testArgs.put("mime_type", mimeType);
554         }
555         return testArgs;
556     }
557 
558     private static final String[] sUnsupportedFeatures = {
559             "feature:android.hardware.type.watch",
560             "android.hardware.type.embedded",
561     };
isDeviceUnsupported()562     private boolean isDeviceUnsupported() throws Exception {
563         for (String unsupportedFeature : sUnsupportedFeatures) {
564             if (getDevice().hasFeature(unsupportedFeature)) {
565                 return true;
566             }
567         }
568         return false;
569     }
570 
isIntentExposed(Map<String, String> testArgs)571     private boolean isIntentExposed(Map<String, String> testArgs)
572             throws Exception {
573         final StringBuffer command = new StringBuffer();
574         command.append("cmd package query-activities");
575         command.append(" -a ").append(testArgs.get("action"));
576         if (testArgs.get("category") != null) {
577             command.append(" -c ").append(testArgs.get("category"));
578         }
579         if (testArgs.get("mime_type") != null) {
580             command.append(" -t ").append(testArgs.get("mime_type"));
581         }
582         final String output = getDevice().executeShellCommand(command.toString()).trim();
583         return !"No activities found".equals(output);
584     }
585 
dumpArgs(Map<String, String> testArgs)586     private static final String dumpArgs(Map<String, String> testArgs) {
587         final StringBuffer dump = new StringBuffer();
588         dump.append("action: ").append(testArgs.get("action"));
589         if (testArgs.get("category") != null) {
590             dump.append(", category: ").append(testArgs.get("category"));
591         }
592         if (testArgs.get("mime_type") != null) {
593             dump.append(", type: ").append(testArgs.get("mime_type"));
594         }
595         return dump.toString();
596     }
597 
installApp(String apk)598     private void installApp(String apk) throws Exception {
599         new InstallMultiple(false /* instant */)
600                 .addFile(apk)
601                 .run();
602     }
603 
installApp(String apk, String installer)604     private void installApp(String apk, String installer) throws Exception {
605         new InstallMultiple(false /* instant */)
606                 .addFile(apk)
607                 .addArg("-i " + installer)
608                 .run();
609     }
610 
installEphemeralApp(String apk)611     private void installEphemeralApp(String apk) throws Exception {
612         new InstallMultiple(true /* instant */)
613                 .addFile(apk)
614                 .run();
615     }
616 
installEphemeralApp(String apk, String installer)617     private void installEphemeralApp(String apk, String installer) throws Exception {
618         new InstallMultiple(true /* instant */)
619                 .addFile(apk)
620                 .addArg("-i " + installer)
621                 .run();
622     }
623 
installFullApp(String apk)624     private void installFullApp(String apk) throws Exception {
625         new InstallMultiple(false /* instant */)
626                 .addFile(apk)
627                 .addArg("--full")
628                 .run();
629     }
630 
installTestPackages()631     private void installTestPackages() throws Exception {
632         installApp(NORMAL_APK);
633         installApp(UNEXPOSED_APK);
634         installApp(IMPLICIT_APK);
635 
636         installEphemeralApp(EPHEMERAL_1_APK);
637         installEphemeralApp(EPHEMERAL_2_APK);
638     }
639 
uninstallTestPackages()640     private void uninstallTestPackages() throws Exception {
641         uninstallPackage(NORMAL_PKG);
642         uninstallPackage(UNEXPOSED_PKG);
643         uninstallPackage(IMPLICIT_PKG);
644         uninstallPackage(EPHEMERAL_1_PKG);
645         uninstallPackage(EPHEMERAL_2_PKG);
646         uninstallPackage(UPGRADED_PKG);
647     }
648 }
649