1 /*
2  * Copyright (C) 2021 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.managedprovisioning;
18 
19 import static com.android.managedprovisioning.ManagedProvisioningScreens.ADMIN_INTEGRATED_PREPARE;
20 import static com.android.managedprovisioning.ManagedProvisioningScreens.ENCRYPT;
21 import static com.android.managedprovisioning.ManagedProvisioningScreens.FINALIZATION_INSIDE_SUW;
22 import static com.android.managedprovisioning.ManagedProvisioningScreens.FINANCED_DEVICE_LANDING;
23 import static com.android.managedprovisioning.ManagedProvisioningScreens.LANDING;
24 import static com.android.managedprovisioning.ManagedProvisioningScreens.POST_ENCRYPT;
25 import static com.android.managedprovisioning.ManagedProvisioningScreens.PRE_PROVISIONING;
26 import static com.android.managedprovisioning.ManagedProvisioningScreens.PROVISIONING;
27 import static com.android.managedprovisioning.ManagedProvisioningScreens.RESET_AND_RETURN_DEVICE;
28 import static com.android.managedprovisioning.ManagedProvisioningScreens.TERMS;
29 import static com.android.managedprovisioning.ManagedProvisioningScreens.WEB;
30 
31 import static com.google.common.truth.Truth.assertThat;
32 
33 import static org.junit.Assert.assertThrows;
34 
35 import android.app.Activity;
36 import android.content.Context;
37 import android.content.pm.PackageInfo;
38 import android.content.pm.PackageManager;
39 
40 import androidx.test.InstrumentationRegistry;
41 import androidx.test.filters.SmallTest;
42 
43 import com.android.managedprovisioning.finalization.FinalizationInsideSuwActivity;
44 import com.android.managedprovisioning.preprovisioning.EncryptDeviceActivity;
45 import com.android.managedprovisioning.preprovisioning.PostEncryptionActivity;
46 import com.android.managedprovisioning.preprovisioning.PreProvisioningActivity;
47 import com.android.managedprovisioning.preprovisioning.WebActivity;
48 import com.android.managedprovisioning.preprovisioning.terms.TermsActivity;
49 import com.android.managedprovisioning.provisioning.AdminIntegratedFlowPrepareActivity;
50 import com.android.managedprovisioning.provisioning.FinancedDeviceLandingActivity;
51 import com.android.managedprovisioning.provisioning.LandingActivity;
52 import com.android.managedprovisioning.provisioning.ProvisioningActivity;
53 import com.android.managedprovisioning.provisioning.ResetAndReturnDeviceActivity;
54 
55 import org.junit.Test;
56 
57 import java.util.Arrays;
58 import java.util.Collection;
59 import java.util.HashMap;
60 import java.util.HashSet;
61 import java.util.List;
62 import java.util.Map;
63 import java.util.Set;
64 import java.util.stream.Collectors;
65 
66 @SmallTest
67 public final class ScreenManagerTest {
68     private static final int EXPECTED_NUMBER_OF_SCREENS = 11;
69     private static final Map<ManagedProvisioningScreens, Class<? extends Activity>>
70             TEST_SCREEN_TO_ACTIVITY_MAP = createTestScreenToActivityMap();
71     private static final Map<ManagedProvisioningScreens, Class<? extends Activity>>
72             TEST_INVALID_SCREEN_TO_ACTIVITY_MAP = createInvalidTestScreenToActivityMap();
73     private static final Set<String> NON_OVERRIDABLE_ACTIVITIES = new HashSet<>(Arrays.asList(
74             // The following activity aliases target PreProvisioningActivity
75             "com.android.managedprovisioning.PreProvisioningActivityAfterEncryption",
76             "com.android.managedprovisioning.PreProvisioningActivityViaTrustedApp",
77             "com.android.managedprovisioning.PreProvisioningActivityViaNfc",
78             TrampolineActivity.class.getName()
79     ));
80 
81     private final Context mContext = InstrumentationRegistry.getTargetContext();
82 
83     @Test
getActivityClassForScreen_withDefaultMap_success()84     public void getActivityClassForScreen_withDefaultMap_success() {
85         ScreenManager screenManager =
86                 new ScreenManager(ScreenManager.DEFAULT_SCREEN_TO_ACTIVITY_MAP);
87 
88         assertThat(screenManager.getActivityClassForScreen(LANDING))
89                 .isEqualTo(LandingActivity.class);
90         assertThat(screenManager.getActivityClassForScreen(PRE_PROVISIONING))
91                 .isEqualTo(PreProvisioningActivity.class);
92         assertThat(screenManager.getActivityClassForScreen(PROVISIONING))
93                 .isEqualTo(ProvisioningActivity.class);
94         assertThat(screenManager.getActivityClassForScreen(ADMIN_INTEGRATED_PREPARE))
95                 .isEqualTo(AdminIntegratedFlowPrepareActivity.class);
96         assertThat(screenManager.getActivityClassForScreen(RESET_AND_RETURN_DEVICE))
97                 .isEqualTo(ResetAndReturnDeviceActivity.class);
98         assertThat(screenManager.getActivityClassForScreen(WEB))
99                 .isEqualTo(WebActivity.class);
100         assertThat(screenManager.getActivityClassForScreen(ENCRYPT))
101                 .isEqualTo(EncryptDeviceActivity.class);
102         assertThat(screenManager.getActivityClassForScreen(POST_ENCRYPT))
103                 .isEqualTo(PostEncryptionActivity.class);
104         assertThat(screenManager.getActivityClassForScreen(FINALIZATION_INSIDE_SUW))
105                 .isEqualTo(FinalizationInsideSuwActivity.class);
106         assertThat(screenManager.getActivityClassForScreen(TERMS))
107                 .isEqualTo(TermsActivity.class);
108         assertThat(screenManager.getActivityClassForScreen(FINANCED_DEVICE_LANDING))
109                 .isEqualTo(FinancedDeviceLandingActivity.class);
110     }
111 
112     @Test
defaultScreenToActivityMap_hasExpectedSize()113     public void defaultScreenToActivityMap_hasExpectedSize() {
114         assertThat(ScreenManager.DEFAULT_SCREEN_TO_ACTIVITY_MAP.size())
115                 .isEqualTo(EXPECTED_NUMBER_OF_SCREENS);
116     }
117 
118     @Test
getActivityClassForScreen_withCustomMap_success()119     public void getActivityClassForScreen_withCustomMap_success() {
120         ScreenManager screenManager = new ScreenManager(TEST_SCREEN_TO_ACTIVITY_MAP);
121 
122         assertThat(screenManager.getActivityClassForScreen(LANDING)).isEqualTo(Activity.class);
123     }
124 
125     @Test
setOverrideActivity_success()126     public void setOverrideActivity_success() {
127         ScreenManager screenManager =
128                 new ScreenManager(ScreenManager.DEFAULT_SCREEN_TO_ACTIVITY_MAP);
129 
130         screenManager.setOverrideActivity(
131                 ManagedProvisioningScreens.LANDING,
132                 Activity.class);
133 
134         assertThat(screenManager.getActivityClassForScreen(LANDING)).isEqualTo(Activity.class);
135     }
136 
137     @Test
constructObject_withInvalidMap_throwsException()138     public void constructObject_withInvalidMap_throwsException() {
139         assertThrows(IllegalStateException.class,
140                 () -> new ScreenManager(TEST_INVALID_SCREEN_TO_ACTIVITY_MAP));
141     }
142 
143     @Test
verifyEveryActivityIsMapped()144     public void verifyEveryActivityIsMapped() throws PackageManager.NameNotFoundException {
145         List<String> activities = getManagedProvisioningActivityNames();
146 
147         List<String> unmappedActivities = getUnmappedOverridableActivities(activities);
148 
149         assertThat(unmappedActivities).isEmpty();
150     }
151 
getUnmappedOverridableActivities(List<String> activities)152     private List<String> getUnmappedOverridableActivities(List<String> activities) {
153         return activities
154                 .stream()
155                 .filter(activityName -> !isActivityMapped(activityName))
156                 .filter(this::isActivityOverridable)
157                 .collect(Collectors.toList());
158     }
159 
isActivityOverridable(String activityName)160     private boolean isActivityOverridable(String activityName) {
161         return !NON_OVERRIDABLE_ACTIVITIES.contains(activityName);
162     }
163 
isActivityMapped(String activityName)164     private boolean isActivityMapped(String activityName) {
165         Collection<Class<? extends Activity>> mappedActivities =
166                 ScreenManager.DEFAULT_SCREEN_TO_ACTIVITY_MAP.values();
167         return mappedActivities
168                 .stream()
169                 .anyMatch(activityClass -> activityClass.getName().equals(activityName));
170     }
171 
getManagedProvisioningActivityNames()172     private List<String> getManagedProvisioningActivityNames()
173             throws PackageManager.NameNotFoundException {
174         PackageManager packageManager = mContext.getPackageManager();
175         PackageInfo packageInfo = packageManager.getPackageInfo(
176                 mContext.getPackageName(),
177                 PackageManager.GET_ACTIVITIES);
178         return Arrays.stream(packageInfo.activities)
179                 .map(activityInfo -> activityInfo.name)
180                 .collect(Collectors.toList());
181     }
182 
183     private static Map<ManagedProvisioningScreens, Class<? extends Activity>>
createTestScreenToActivityMap()184             createTestScreenToActivityMap() {
185         Map<ManagedProvisioningScreens, Class<? extends Activity>> map = new HashMap<>();
186         map.put(LANDING, Activity.class);
187         map.put(PRE_PROVISIONING, Activity.class);
188         map.put(PROVISIONING, Activity.class);
189         map.put(ADMIN_INTEGRATED_PREPARE, Activity.class);
190         map.put(RESET_AND_RETURN_DEVICE, Activity.class);
191         map.put(WEB, Activity.class);
192         map.put(ENCRYPT, Activity.class);
193         map.put(POST_ENCRYPT, Activity.class);
194         map.put(FINALIZATION_INSIDE_SUW, Activity.class);
195         map.put(TERMS, Activity.class);
196         map.put(FINANCED_DEVICE_LANDING, Activity.class);
197         return map;
198     }
199 
200     private static Map<ManagedProvisioningScreens, Class<? extends Activity>>
createInvalidTestScreenToActivityMap()201             createInvalidTestScreenToActivityMap() {
202         return Map.of(LANDING, LandingActivity.class);
203     }
204 }
205