Merge "Don't throw exception for duplicate resume" into pi-dev
am: ee83dd2cd0
Change-Id: I91a3009cd6e81632f203659c21c261b00e417e15
This commit is contained in:
@@ -124,6 +124,7 @@ import android.widget.Toast;
|
||||
import android.widget.Toolbar;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.app.IVoiceInteractor;
|
||||
import com.android.internal.app.ToolbarActionBar;
|
||||
import com.android.internal.app.WindowDecorActionBar;
|
||||
@@ -7110,6 +7111,12 @@ public class Activity extends ContextThemeWrapper
|
||||
return mParent != null ? mParent.getActivityToken() : mToken;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@VisibleForTesting
|
||||
public final ActivityThread getActivityThread() {
|
||||
return mMainThread;
|
||||
}
|
||||
|
||||
final void performCreate(Bundle icicle) {
|
||||
performCreate(icicle, null);
|
||||
}
|
||||
|
||||
@@ -3722,16 +3722,27 @@ public final class ActivityThread extends ClientTransactionHandler {
|
||||
//Slog.i(TAG, "Running services: " + mServices);
|
||||
}
|
||||
|
||||
ActivityClientRecord performResumeActivity(IBinder token, boolean clearHide, String reason) {
|
||||
ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest,
|
||||
String reason) {
|
||||
ActivityClientRecord r = mActivities.get(token);
|
||||
if (localLOGV) Slog.v(TAG, "Performing resume of " + r
|
||||
+ " finished=" + r.activity.mFinished);
|
||||
if (r != null && !r.activity.mFinished) {
|
||||
if (r.getLifecycleState() == ON_RESUME) {
|
||||
throw new IllegalStateException(
|
||||
"Trying to resume activity which is already resumed");
|
||||
if (!finalStateRequest) {
|
||||
final RuntimeException e = new IllegalStateException(
|
||||
"Trying to resume activity which is already resumed");
|
||||
Slog.e(TAG, e.getMessage(), e);
|
||||
Slog.e(TAG, r.getStateString());
|
||||
// TODO(lifecycler): A double resume request is possible when an activity
|
||||
// receives two consequent transactions with relaunch requests and "resumed"
|
||||
// final state requests and the second relaunch is omitted. We still try to
|
||||
// handle two resume requests for the final state. For cases other than this
|
||||
// one, we don't expect it to happen.
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (clearHide) {
|
||||
if (finalStateRequest) {
|
||||
r.hideForNow = false;
|
||||
r.activity.mStartedActivity = false;
|
||||
}
|
||||
@@ -3782,7 +3793,7 @@ public final class ActivityThread extends ClientTransactionHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward,
|
||||
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
|
||||
String reason) {
|
||||
// If we are getting ready to gc after going to the background, well
|
||||
// we are back active so skip it.
|
||||
@@ -3790,7 +3801,7 @@ public final class ActivityThread extends ClientTransactionHandler {
|
||||
mSomeActivitiesChanged = true;
|
||||
|
||||
// TODO Push resumeArgs into the activity for consideration
|
||||
final ActivityClientRecord r = performResumeActivity(token, clearHide, reason);
|
||||
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
|
||||
|
||||
if (r != null) {
|
||||
final Activity a = r.activity;
|
||||
|
||||
@@ -67,9 +67,16 @@ public abstract class ClientTransactionHandler {
|
||||
public abstract void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving,
|
||||
int configChanges, PendingTransactionActions pendingActions, String reason);
|
||||
|
||||
/** Resume the activity. */
|
||||
public abstract void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward,
|
||||
String reason);
|
||||
/**
|
||||
* Resume the activity.
|
||||
* @param token Target activity token.
|
||||
* @param finalStateRequest Flag indicating if this call is handling final lifecycle state
|
||||
* request for a transaction.
|
||||
* @param isForward Flag indicating if next transition is forward.
|
||||
* @param reason Reason for performing this operation.
|
||||
*/
|
||||
public abstract void handleResumeActivity(IBinder token, boolean finalStateRequest,
|
||||
boolean isForward, String reason);
|
||||
|
||||
/** Stop the activity. */
|
||||
public abstract void handleStopActivity(IBinder token, boolean show, int configChanges,
|
||||
|
||||
@@ -48,7 +48,8 @@ public class ResumeActivityItem extends ActivityLifecycleItem {
|
||||
public void execute(ClientTransactionHandler client, IBinder token,
|
||||
PendingTransactionActions pendingActions) {
|
||||
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
|
||||
client.handleResumeActivity(token, true /* clearHide */, mIsForward, "RESUME_ACTIVITY");
|
||||
client.handleResumeActivity(token, true /* finalStateRequest */, mIsForward,
|
||||
"RESUME_ACTIVITY");
|
||||
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
|
||||
}
|
||||
|
||||
|
||||
@@ -191,7 +191,7 @@ public class TransactionExecutor {
|
||||
mTransactionHandler.handleStartActivity(r, mPendingActions);
|
||||
break;
|
||||
case ON_RESUME:
|
||||
mTransactionHandler.handleResumeActivity(r.token, false /* clearHide */,
|
||||
mTransactionHandler.handleResumeActivity(r.token, false /* finalStateRequest */,
|
||||
r.isForward, "LIFECYCLER_RESUME_ACTIVITY");
|
||||
break;
|
||||
case ON_PAUSE:
|
||||
|
||||
@@ -1379,6 +1379,10 @@
|
||||
android:theme="@style/Theme">
|
||||
</activity>
|
||||
|
||||
<activity android:name="android.app.activity.ActivityThreadTest$TestActivity"
|
||||
android:exported="true">
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="android.os.TestVrActivity"
|
||||
android:enableVrMode="com.android.frameworks.coretests/android.os.TestVrActivity$TestVrListenerService">
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app.activity;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.IApplicationThread;
|
||||
import android.app.servertransaction.ActivityRelaunchItem;
|
||||
import android.app.servertransaction.ClientTransaction;
|
||||
import android.app.servertransaction.ClientTransactionItem;
|
||||
import android.app.servertransaction.ResumeActivityItem;
|
||||
import android.content.Intent;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.filters.MediumTest;
|
||||
import android.support.test.rule.ActivityTestRule;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.util.MergedConfiguration;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* Test for verifying {@link android.app.ActivityThread} class.
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@MediumTest
|
||||
public class ActivityThreadTest {
|
||||
|
||||
private final ActivityTestRule mActivityTestRule =
|
||||
new ActivityTestRule(TestActivity.class, true /* initialTouchMode */,
|
||||
false /* launchActivity */);
|
||||
|
||||
@Test
|
||||
public void testDoubleRelaunch() throws Exception {
|
||||
final Activity activity = mActivityTestRule.launchActivity(new Intent());
|
||||
final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
|
||||
|
||||
appThread.scheduleTransaction(newRelaunchResumeTransaction(activity));
|
||||
appThread.scheduleTransaction(newRelaunchResumeTransaction(activity));
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResumeAfterRelaunch() throws Exception {
|
||||
final Activity activity = mActivityTestRule.launchActivity(new Intent());
|
||||
final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
|
||||
|
||||
appThread.scheduleTransaction(newRelaunchResumeTransaction(activity));
|
||||
appThread.scheduleTransaction(newResumeTransaction(activity));
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
}
|
||||
|
||||
private static ClientTransaction newRelaunchResumeTransaction(Activity activity) {
|
||||
final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(null,
|
||||
null, 0, new MergedConfiguration(),
|
||||
false /* preserveWindow */);
|
||||
final ResumeActivityItem resumeStateRequest =
|
||||
ResumeActivityItem.obtain(true /* isForward */);
|
||||
final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
|
||||
final ClientTransaction transaction =
|
||||
ClientTransaction.obtain(appThread, activity.getActivityToken());
|
||||
transaction.addCallback(callbackItem);
|
||||
transaction.setLifecycleStateRequest(resumeStateRequest);
|
||||
|
||||
return transaction;
|
||||
}
|
||||
|
||||
private static ClientTransaction newResumeTransaction(Activity activity) {
|
||||
final ResumeActivityItem resumeStateRequest =
|
||||
ResumeActivityItem.obtain(true /* isForward */);
|
||||
final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
|
||||
final ClientTransaction transaction =
|
||||
ClientTransaction.obtain(appThread, activity.getActivityToken());
|
||||
transaction.setLifecycleStateRequest(resumeStateRequest);
|
||||
|
||||
return transaction;
|
||||
}
|
||||
|
||||
// Test activity
|
||||
public static class TestActivity extends Activity {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user