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.server.am;
18 
19 import static android.server.am.ComponentNameUtils.getActivityName;
20 import static android.server.am.Components.ENTRY_POINT_ALIAS_ACTIVITY;
21 import static android.server.am.Components.SINGLE_TASK_ACTIVITY;
22 import static android.server.am.Components.TEST_ACTIVITY;
23 import static android.server.am.UiDeviceUtils.pressHomeButton;
24 
25 import static org.hamcrest.MatcherAssert.assertThat;
26 import static org.hamcrest.Matchers.greaterThanOrEqualTo;
27 import static org.junit.Assert.assertEquals;
28 import static org.junit.Assert.assertNotEquals;
29 import static org.junit.Assert.fail;
30 
31 import android.content.ComponentName;
32 
33 import org.junit.Test;
34 
35 import java.util.regex.Matcher;
36 import java.util.regex.Pattern;
37 
38 /**
39  * Build/Install/Run:
40  *     atest CtsActivityManagerDeviceTestCases:ActivityManagerAmStartOptionsTests
41  */
42 public class ActivityManagerAmStartOptionsTests extends ActivityManagerTestBase {
43 
44     @Test
testDashD()45     public void testDashD() {
46         // Run at least 2 rounds to verify that -D works with an existing process.
47         // -D could fail in this case if the force stop of process is broken.
48         int prevProcId = -1;
49         for (int i = 0; i < 2; i++) {
50             executeShellCommand("am start -n " + getActivityName(TEST_ACTIVITY) + " -D");
51 
52             mAmWmState.waitForDebuggerWindowVisible(TEST_ACTIVITY);
53             int procId = mAmWmState.getAmState().getActivityProcId(TEST_ACTIVITY);
54 
55             assertThat("Invalid ProcId.", procId, greaterThanOrEqualTo(0));
56             if (i > 0) {
57                 assertNotEquals("Run " + i + " didn't start new proc.", prevProcId, procId);
58             }
59             prevProcId = procId;
60         }
61     }
62 
63     @Test
testDashW_Direct()64     public void testDashW_Direct() throws Exception {
65         testDashW(SINGLE_TASK_ACTIVITY, SINGLE_TASK_ACTIVITY);
66     }
67 
68     @Test
testDashW_Indirect()69     public void testDashW_Indirect() throws Exception {
70         testDashW(ENTRY_POINT_ALIAS_ACTIVITY, SINGLE_TASK_ACTIVITY);
71     }
72 
testDashW(final ComponentName entryActivity, final ComponentName actualActivity)73     private void testDashW(final ComponentName entryActivity, final ComponentName actualActivity)
74             throws Exception {
75         // Test cold start
76         startActivityAndVerifyResult(entryActivity, actualActivity, true);
77 
78         // Test warm start
79         pressHomeButton();
80         startActivityAndVerifyResult(entryActivity, actualActivity, false);
81 
82         // Test "hot" start (app already in front)
83         startActivityAndVerifyResult(entryActivity, actualActivity, false);
84     }
85 
startActivityAndVerifyResult(final ComponentName entryActivity, final ComponentName actualActivity, boolean shouldStart)86     private void startActivityAndVerifyResult(final ComponentName entryActivity,
87             final ComponentName actualActivity, boolean shouldStart) {
88         // See TODO below
89         // final LogSeparator logSeparator = separateLogs();
90 
91         // Pass in different data only when cold starting. This is to make the intent
92         // different in subsequent warm/hot launches, so that the entrypoint alias
93         // activity is always started, but the actual activity is not started again
94         // because of the NEW_TASK and singleTask flags.
95         final String result = executeShellCommand(
96                 "am start -n " + getActivityName(entryActivity) + " -W"
97                 + (shouldStart ? " -d about:blank" : ""));
98 
99         // Verify shell command return value
100         verifyShellOutput(result, actualActivity, shouldStart);
101 
102         // TODO: Disable logcat check for now.
103         // Logcat of WM or AM tag could be lost (eg. chatty if earlier events generated
104         // too many lines), and make the test look flaky. We need to either use event
105         // log or swith to other mechanisms. Only verify shell output for now, it should
106         // still catch most failures.
107 
108         // Verify adb logcat log
109         //verifyLogcat(actualActivity, shouldStart, logSeparator);
110     }
111 
112     private static final Pattern sNotStartedWarningPattern = Pattern.compile(
113             "Warning: Activity not started(.*)");
114     private static final Pattern sStatusPattern = Pattern.compile(
115             "Status: (.*)");
116     private static final Pattern sActivityPattern = Pattern.compile(
117             "Activity: (.*)");
118     private static final String sStatusOk = "ok";
119 
verifyShellOutput( final String result, final ComponentName activity, boolean shouldStart)120     private void verifyShellOutput(
121             final String result, final ComponentName activity, boolean shouldStart) {
122         boolean warningFound = false;
123         String status = null;
124         String reportedActivity = null;
125 
126         final String[] lines = result.split("\\n");
127         // Going from the end of logs to beginning in case if some other activity is started first.
128         for (int i = lines.length - 1; i >= 0; i--) {
129             final String line = lines[i].trim();
130             Matcher matcher = sNotStartedWarningPattern.matcher(line);
131             if (matcher.matches()) {
132                 warningFound = true;
133                 continue;
134             }
135             matcher = sStatusPattern.matcher(line);
136             if (matcher.matches()) {
137                 status = matcher.group(1);
138                 continue;
139             }
140             matcher = sActivityPattern.matcher(line);
141             if (matcher.matches()) {
142                 reportedActivity = matcher.group(1);
143                 continue;
144             }
145         }
146 
147         assertEquals("Status is ok", sStatusOk, status);
148         assertEquals("Reported activity is " +  getActivityName(activity),
149                 getActivityName(activity), reportedActivity);
150 
151         if (shouldStart && warningFound) {
152             fail("Should start new activity but brought something to front.");
153         } else if (!shouldStart && !warningFound){
154             fail("Should bring existing activity to front but started new activity.");
155         }
156     }
157 }
158