• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.server.wm;
18 
19 import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
20 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
21 
22 import static com.google.common.truth.Truth.assertThat;
23 
24 import static org.junit.Assume.assumeTrue;
25 
26 import android.app.ActivityManager;
27 import android.app.ActivityOptions;
28 import android.content.ComponentName;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.os.Bundle;
32 import android.os.RemoteCallback;
33 import android.os.UserHandle;
34 import android.os.UserManager;
35 import android.platform.test.annotations.Presubmit;
36 
37 import androidx.test.platform.app.InstrumentationRegistry;
38 
39 import org.junit.AfterClass;
40 import org.junit.Before;
41 import org.junit.BeforeClass;
42 import org.junit.Test;
43 
44 import java.util.concurrent.CountDownLatch;
45 import java.util.concurrent.TimeUnit;
46 
47 @Presubmit
48 public class StartActivityAsUserTests {
49     static final String EXTRA_CALLBACK = "callback";
50     static final String KEY_USER_ID = "user id";
51 
52     private static final String PACKAGE = "android.server.wm.cts";
53     private static final String CLASS = "android.server.wm.StartActivityAsUserActivity";
54     private static final int INVALID_STACK = -1;
55     private static final boolean SUPPORTS_MULTIPLE_USERS = UserManager.supportsMultipleUsers();
56 
57     private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
58     private final ActivityManager mAm = mContext.getSystemService(ActivityManager.class);
59 
60     private static int sSecondUserId;
61     private WindowManagerStateHelper mAmWmState = new WindowManagerStateHelper();
62 
63     @BeforeClass
createSecondUser()64     public static void createSecondUser() {
65         if (!SUPPORTS_MULTIPLE_USERS) {
66             return;
67         }
68 
69         final Context context = InstrumentationRegistry.getInstrumentation().getContext();
70         final String output = runShellCommand(
71                 "pm create-user --user-type android.os.usertype.profile.CLONE --profileOf "
72                         + context.getUserId() + " user2");
73         sSecondUserId = Integer.parseInt(output.substring(output.lastIndexOf(" ")).trim());
74         if (sSecondUserId == 0) {
75             return;
76         }
77         runShellCommand("pm install-existing --user " + sSecondUserId + " android.server.wm.cts");
78         runShellCommand("am start-user -w " + sSecondUserId);
79     }
80 
81     @AfterClass
removeSecondUser()82     public static void removeSecondUser() {
83         if (sSecondUserId == 0) {
84             return;
85         }
86         runShellCommand("am stop-user -w -f " + sSecondUserId);
87         runShellCommand("pm remove-user " + sSecondUserId);
88         sSecondUserId = 0;
89     }
90 
91     @Before
checkMultipleUsersNotSupportedOrSecondUserCreated()92     public void checkMultipleUsersNotSupportedOrSecondUserCreated() {
93         assumeTrue(SUPPORTS_MULTIPLE_USERS);
94         assertThat(sSecondUserId).isNotEqualTo(0);
95     }
96 
97     @Test
startActivityValidUser()98     public void startActivityValidUser() throws Throwable {
99         verifyStartActivityAsValidUser(false /* withOptions */);
100     }
101 
102     @Test
startActivityInvalidUser()103     public void startActivityInvalidUser() {
104         verifyStartActivityAsInvalidUser(false /* withOptions */);
105     }
106 
107     @Test
startActivityAsValidUserWithOptions()108     public void startActivityAsValidUserWithOptions() throws Throwable {
109         verifyStartActivityAsValidUser(true /* withOptions */);
110     }
111 
112     @Test
startActivityAsInvalidUserWithOptions()113     public void startActivityAsInvalidUserWithOptions() {
114         verifyStartActivityAsInvalidUser(true /* withOptions */);
115     }
116 
verifyStartActivityAsValidUser(boolean withOptions)117     private void verifyStartActivityAsValidUser(boolean withOptions) throws Throwable {
118         int[] secondUser = {-1};
119         CountDownLatch latch = new CountDownLatch(1);
120         RemoteCallback cb = new RemoteCallback((Bundle result) -> {
121             secondUser[0] = result.getInt(KEY_USER_ID);
122             latch.countDown();
123         });
124 
125         final Intent intent = new Intent(mContext, StartActivityAsUserActivity.class);
126         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
127         intent.putExtra(EXTRA_CALLBACK, cb);
128         UserHandle secondUserHandle = UserHandle.of(sSecondUserId);
129 
130         runWithShellPermissionIdentity(() -> {
131             if (withOptions) {
132                 mContext.startActivityAsUser(intent, ActivityOptions.makeBasic().toBundle(),
133                         secondUserHandle);
134             } else {
135                 mContext.startActivityAsUser(intent, secondUserHandle);
136             }
137         });
138 
139         latch.await(5, TimeUnit.SECONDS);
140         assertThat(secondUser[0]).isEqualTo(sSecondUserId);
141 
142         // The StartActivityAsUserActivity calls finish() in onCreate and here waits for the
143         // activity removed to prevent impacting other tests.
144         mAmWmState.waitForActivityRemoved(intent.getComponent());
145     }
146 
verifyStartActivityAsInvalidUser(boolean withOptions)147     private void verifyStartActivityAsInvalidUser(boolean withOptions) {
148         UserHandle secondUserHandle = UserHandle.of(sSecondUserId * 100);
149         int[] stackId = {-1};
150 
151         final Intent intent = new Intent(mContext, StartActivityAsUserActivity.class);
152         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
153 
154         runWithShellPermissionIdentity(() -> {
155             if (withOptions) {
156                 mContext.startActivityAsUser(intent, ActivityOptions.makeBasic().toBundle(),
157                         secondUserHandle);
158             } else {
159                 mContext.startActivityAsUser(intent, secondUserHandle);
160             }
161             WindowManagerState amState = mAmWmState;
162             amState.computeState();
163             ComponentName componentName = ComponentName.createRelative(PACKAGE, CLASS);
164             stackId[0] = amState.getRootTaskIdByActivity(componentName);
165         });
166 
167         assertThat(stackId[0]).isEqualTo(INVALID_STACK);
168     }
169 }
170