1 /*
2  * Copyright 2018 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.app.activity;
18 
19 import static android.content.Intent.ACTION_EDIT;
20 import static android.content.Intent.ACTION_VIEW;
21 
22 import static org.junit.Assert.assertNull;
23 import static org.junit.Assert.assertTrue;
24 
25 import android.app.Activity;
26 import android.app.ActivityThread;
27 import android.app.IApplicationThread;
28 import android.app.servertransaction.ActivityRelaunchItem;
29 import android.app.servertransaction.ClientTransaction;
30 import android.app.servertransaction.ClientTransactionItem;
31 import android.app.servertransaction.ResumeActivityItem;
32 import android.app.servertransaction.StopActivityItem;
33 import android.content.Intent;
34 import android.os.IBinder;
35 import android.support.test.InstrumentationRegistry;
36 import android.support.test.filters.MediumTest;
37 import android.support.test.rule.ActivityTestRule;
38 import android.support.test.runner.AndroidJUnit4;
39 import android.util.MergedConfiguration;
40 
41 import org.junit.Test;
42 import org.junit.runner.RunWith;
43 
44 /**
45  * Test for verifying {@link android.app.ActivityThread} class.
46  * Build/Install/Run:
47  *  atest FrameworksCoreTests:android.app.activity.ActivityThreadTest
48  */
49 @RunWith(AndroidJUnit4.class)
50 @MediumTest
51 public class ActivityThreadTest {
52 
53     private final ActivityTestRule mActivityTestRule =
54             new ActivityTestRule(TestActivity.class, true /* initialTouchMode */,
55                     false /* launchActivity */);
56 
57     @Test
testDoubleRelaunch()58     public void testDoubleRelaunch() throws Exception {
59         final Activity activity = mActivityTestRule.launchActivity(new Intent());
60         final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
61 
62         appThread.scheduleTransaction(newRelaunchResumeTransaction(activity));
63         appThread.scheduleTransaction(newRelaunchResumeTransaction(activity));
64         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
65     }
66 
67     @Test
testResumeAfterRelaunch()68     public void testResumeAfterRelaunch() throws Exception {
69         final Activity activity = mActivityTestRule.launchActivity(new Intent());
70         final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
71 
72         appThread.scheduleTransaction(newRelaunchResumeTransaction(activity));
73         appThread.scheduleTransaction(newResumeTransaction(activity));
74         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
75     }
76 
77     @Test
testSleepAndStop()78     public void testSleepAndStop() throws Exception {
79         final Activity activity = mActivityTestRule.launchActivity(new Intent());
80         final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
81 
82         appThread.scheduleSleeping(activity.getActivityToken(), true /* sleeping */);
83         appThread.scheduleTransaction(newStopTransaction(activity));
84         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
85     }
86 
87     /** Verify that repeated resume requests to activity will be ignored. */
88     @Test
testRepeatedResume()89     public void testRepeatedResume() throws Exception {
90         final Activity activity = mActivityTestRule.launchActivity(new Intent());
91         final ActivityThread activityThread = activity.getActivityThread();
92         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
93             activityThread.executeTransaction(newResumeTransaction(activity));
94             assertNull(activityThread.performResumeActivity(activity.getActivityToken(),
95                     true /* finalStateRequest */, "test"));
96 
97             assertNull(activityThread.performResumeActivity(activity.getActivityToken(),
98                     false /* finalStateRequest */, "test"));
99         });
100     }
101 
102     /** Verify that custom intent set via Activity#setIntent() is preserved on relaunch. */
103     @Test
testCustomIntentPreservedOnRelaunch()104     public void testCustomIntentPreservedOnRelaunch() throws Exception {
105         final Intent initIntent = new Intent();
106         initIntent.setAction(ACTION_VIEW);
107         final Activity activity = mActivityTestRule.launchActivity(initIntent);
108         IBinder token = activity.getActivityToken();
109 
110         final ActivityThread activityThread = activity.getActivityThread();
111         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
112             // Recreate and check that intent is still the same.
113             activity.recreate();
114 
115             final Activity newActivity = activityThread.getActivity(token);
116             assertTrue("Original intent must be preserved after recreate",
117                     initIntent.filterEquals(newActivity.getIntent()));
118 
119             // Set custom intent, recreate and check if it is preserved.
120             final Intent customIntent = new Intent();
121             customIntent.setAction(ACTION_EDIT);
122             newActivity.setIntent(customIntent);
123 
124             activity.recreate();
125 
126             final Activity lastActivity = activityThread.getActivity(token);
127             assertTrue("Custom intent must be preserved after recreate",
128                     customIntent.filterEquals(lastActivity.getIntent()));
129         });
130     }
131 
newRelaunchResumeTransaction(Activity activity)132     private static ClientTransaction newRelaunchResumeTransaction(Activity activity) {
133         final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(null,
134                 null, 0, new MergedConfiguration(), false /* preserveWindow */);
135         final ResumeActivityItem resumeStateRequest =
136                 ResumeActivityItem.obtain(true /* isForward */);
137 
138         final ClientTransaction transaction = newTransaction(activity);
139         transaction.addCallback(callbackItem);
140         transaction.setLifecycleStateRequest(resumeStateRequest);
141 
142         return transaction;
143     }
144 
newResumeTransaction(Activity activity)145     private static ClientTransaction newResumeTransaction(Activity activity) {
146         final ResumeActivityItem resumeStateRequest =
147                 ResumeActivityItem.obtain(true /* isForward */);
148 
149         final ClientTransaction transaction = newTransaction(activity);
150         transaction.setLifecycleStateRequest(resumeStateRequest);
151 
152         return transaction;
153     }
154 
newStopTransaction(Activity activity)155     private static ClientTransaction newStopTransaction(Activity activity) {
156         final StopActivityItem stopStateRequest =
157                 StopActivityItem.obtain(false /* showWindow */, 0 /* configChanges */);
158 
159         final ClientTransaction transaction = newTransaction(activity);
160         transaction.setLifecycleStateRequest(stopStateRequest);
161 
162         return transaction;
163     }
164 
newTransaction(Activity activity)165     private static ClientTransaction newTransaction(Activity activity) {
166         final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
167         return ClientTransaction.obtain(appThread, activity.getActivityToken());
168     }
169 
170     // Test activity
171     public static class TestActivity extends Activity {
172     }
173 }
174