xref: /aosp_15_r20/cts/tests/tests/match_flags/src/android/matchflags/cts/MatchFlagTests.java (revision b7c941bb3fa97aba169d73cee0bed2de8ac964bf)
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.matchflags.cts;
18 
19 import static org.junit.Assert.fail;
20 import static org.junit.Assume.assumeFalse;
21 
22 import android.content.ActivityNotFoundException;
23 import android.content.Intent;
24 import android.content.pm.PackageManager;
25 import android.net.Uri;
26 
27 import androidx.test.ext.junit.runners.AndroidJUnit4;
28 import androidx.test.platform.app.InstrumentationRegistry;
29 
30 import com.android.compatibility.common.util.FeatureUtil;
31 import com.android.compatibility.common.util.ShellUtils;
32 
33 import org.junit.After;
34 import org.junit.Before;
35 import org.junit.Rule;
36 import org.junit.Test;
37 import org.junit.rules.TestName;
38 import org.junit.runner.RunWith;
39 
40 @RunWith(AndroidJUnit4.class)
41 public class MatchFlagTests {
42 
43     private static final String ONLY_BROWSER_URI =
44             "https://nohandler-02xgpcssu1v7xvpek0skc905glnyu7ihjtza3eufox0mauqyri.com";
45     private static final String UNIQUE_URI =
46             "https://unique-5gle2bs6woovjn8xabwyb3js01xl0ducci3gd3fpe622h48lyg.com";
47 
48     private static final String SHARED_PKG_NAME = "android.matchflags.app.shared";
49     private static final String UNIQUE_AND_SHARED_PKG_NAME =
50             "android.matchflags.app.uniqueandshared";
51 
52     @Rule
53     public TestName name = new TestName();
54 
55     @Before
56     @After
removeApprovals()57     public void removeApprovals() {
58         setDomainUserSelectionApproval(false);
59     }
60 
61     @Test
startNoBrowserIntentWithNoMatchingApps()62     public void startNoBrowserIntentWithNoMatchingApps() throws Exception {
63         assumeFalse("Skipping test for watch",
64                 InstrumentationRegistry.getInstrumentation().getTargetContext()
65                         .getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH));
66 
67         Intent onlyBrowserIntent = new Intent(Intent.ACTION_VIEW)
68                 .addCategory(Intent.CATEGORY_BROWSABLE)
69                 .setData(Uri.parse(ONLY_BROWSER_URI));
70 
71         if (isBrowserPresent(true)) {
72             startActivity(onlyBrowserIntent);
73         } else {
74             try {
75                 startActivity(onlyBrowserIntent);
76                 fail("Device without browser should not launch browser only intent");
77             } catch (ActivityNotFoundException e) {
78                 // hooray
79             }
80         }
81 
82         Intent noBrowserWithBrowserOnlyIntent = new Intent(onlyBrowserIntent)
83                 .addFlags(Intent.FLAG_ACTIVITY_REQUIRE_NON_BROWSER);
84 
85         try {
86             startActivity(noBrowserWithBrowserOnlyIntent);
87             fail("Should not have started a browser-only intent with NON_BROWSER flag set");
88         } catch (ActivityNotFoundException e) {
89             // hooray!
90         }
91     }
92 
93     @Test
startRequireDefaultWithNoDefault()94     public void startRequireDefaultWithNoDefault() throws Exception {
95         Intent sharedIntent = new Intent("android.matchflags.app.SHARED_ACTION");
96 
97         startActivity(sharedIntent);
98 
99         Intent sharedIntentRequireDefault = new Intent(sharedIntent)
100                 .addFlags(Intent.FLAG_ACTIVITY_REQUIRE_DEFAULT);
101 
102         try {
103             startActivity(sharedIntentRequireDefault);
104             fail("Should have started intent with no default when default required");
105         } catch (ActivityNotFoundException e) {
106             // hooray!
107         }
108     }
109 
110     @Test
startRequireDefaultWithSingleMatch()111     public void startRequireDefaultWithSingleMatch() throws Exception {
112         Intent uniqueIntent = new Intent("android.matchflags.app.UNIQUE_ACTION")
113                 .addFlags(Intent.FLAG_ACTIVITY_REQUIRE_DEFAULT);
114         startActivity(uniqueIntent);
115     }
116 
117     @Test
startNoBrowserRequireDefault()118     public void startNoBrowserRequireDefault() throws Exception {
119         setDomainUserSelectionApproval(true);
120         startNoBrowserRequireDefaultInternal(true);
121     }
122 
123     @Test
startNoBrowserRequireDefaultUnapproved()124     public void startNoBrowserRequireDefaultUnapproved() throws Exception {
125         assumeFalse("Skipping test for watch", FeatureUtil.isWatch());
126         assumeFalse("Skipping test for car", FeatureUtil.isAutomotive());
127         setDomainUserSelectionApproval(false);
128         startNoBrowserRequireDefaultInternal(false);
129     }
130 
startNoBrowserRequireDefaultInternal(boolean isDomainApproved)131     private void startNoBrowserRequireDefaultInternal(boolean isDomainApproved) {
132         Intent uniqueUriIntent = new Intent(Intent.ACTION_VIEW)
133                 .addCategory(Intent.CATEGORY_BROWSABLE)
134                 .setData(Uri.parse(UNIQUE_URI));
135 
136         startActivity(uniqueUriIntent);
137 
138         Intent uniqueUriIntentNoBrowserRequireDefault = new Intent(uniqueUriIntent)
139                 .addFlags(Intent.FLAG_ACTIVITY_REQUIRE_NON_BROWSER)
140                 .addFlags(Intent.FLAG_ACTIVITY_REQUIRE_DEFAULT);
141 
142         if (isBrowserPresent(false)) {
143             // with non-browser, we'd expect the resolver
144             // with require default, we'll get activity not found
145             try {
146                 startActivity(uniqueUriIntentNoBrowserRequireDefault);
147                 if (!isDomainApproved) {
148                     fail("Should fail to launch when started with non-browser and require default"
149                             + " when browser present");
150                 }
151             } catch (ActivityNotFoundException e) {
152                 // hooray!
153                 if (isDomainApproved) {
154                     // Domain approval should force only the test Activity to be returned, which
155                     // means it should pass the above flags and launch.
156                     fail("Should succeed launch when started with non-browser and require default"
157                             + " when browser present");
158                 }
159             }
160         } else {
161             // with non-browser, but no browser present, we'd get a single result
162             // with require default, we'll resolve to that single result
163             try {
164                 startActivity(uniqueUriIntentNoBrowserRequireDefault);
165                 if (!isDomainApproved) {
166                     fail("Should fail to launch when started with non-browser and require default"
167                             + " when browser not present");
168                 }
169             } catch (ActivityNotFoundException e) {
170                 if (isDomainApproved) {
171                     fail("Should succeed launch when started with non-browser and require default"
172                             + " when browser not present");
173                 }
174             }
175         }
176     }
177 
isBrowserPresent(boolean includeFallback)178     private static boolean isBrowserPresent(boolean includeFallback) {
179         return InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageManager()
180                 .queryIntentActivities(new Intent(Intent.ACTION_VIEW).addCategory(
181                         Intent.CATEGORY_BROWSABLE).setData(Uri.parse(ONLY_BROWSER_URI)),
182                         0 /* flags */)
183                 .stream().anyMatch(resolveInfo ->
184                         resolveInfo.handleAllWebDataURI
185                         && (includeFallback || resolveInfo.priority >= 0));
186     }
187 
startActivity(Intent onlyBrowserIntent)188     private static void startActivity(Intent onlyBrowserIntent) {
189         InstrumentationRegistry.getInstrumentation().getContext().startActivity(
190                 onlyBrowserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
191     }
192 
setDomainUserSelectionApproval(boolean approved)193     private static void setDomainUserSelectionApproval(boolean approved) {
194         String template = "pm set-app-links-user-selection --package %s --user all %b all";
195         ShellUtils.runShellCommand(template, SHARED_PKG_NAME, approved);
196         ShellUtils.runShellCommand(template, UNIQUE_AND_SHARED_PKG_NAME, approved);
197     }
198 }
199