Merge "Allow dangerous reentrant behavior for older apps"
This commit is contained in:
committed by
Android (Google) Code Review
commit
e6b44f270f
@@ -370,7 +370,7 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
|
||||
public BackStackRecord(FragmentManagerImpl manager) {
|
||||
mManager = manager;
|
||||
mAllowOptimization = getTargetSdk() > Build.VERSION_CODES.N_MR1;
|
||||
mAllowOptimization = mManager.getTargetSdk() > Build.VERSION_CODES.N_MR1;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
@@ -423,7 +423,7 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
}
|
||||
|
||||
private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
|
||||
if (getTargetSdk() > Build.VERSION_CODES.N_MR1) {
|
||||
if (mManager.getTargetSdk() > Build.VERSION_CODES.N_MR1) {
|
||||
final Class fragmentClass = fragment.getClass();
|
||||
final int modifiers = fragmentClass.getModifiers();
|
||||
if ((fragmentClass.isAnonymousClass() || !Modifier.isPublic(modifiers)
|
||||
@@ -1022,22 +1022,4 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
public boolean isEmpty() {
|
||||
return mOps.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the target SDK of the FragmentManager's application info. If the
|
||||
* FragmentManager has been torn down, then 0 is returned.
|
||||
*/
|
||||
private int getTargetSdk() {
|
||||
FragmentHostCallback host = mManager.mHost;
|
||||
if (host != null) {
|
||||
Context context = host.getContext();
|
||||
if (context != null) {
|
||||
ApplicationInfo info = context.getApplicationInfo();
|
||||
if (info != null) {
|
||||
return info.targetSdkVersion;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,9 +23,11 @@ import android.animation.AnimatorSet;
|
||||
import android.animation.PropertyValuesHolder;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources.NotFoundException;
|
||||
import android.content.res.TypedArray;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Debug;
|
||||
import android.os.Looper;
|
||||
@@ -674,6 +676,10 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
|
||||
// Postponed transactions.
|
||||
ArrayList<StartEnterTransitionListener> mPostponedTransactions;
|
||||
|
||||
// Prior to O, we allowed executing transactions during fragment manager state changes.
|
||||
// This is dangerous, but we want to keep from breaking old applications.
|
||||
boolean mAllowOldReentrantBehavior;
|
||||
|
||||
Runnable mExecCommit = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -2815,69 +2821,92 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
|
||||
mHost = host;
|
||||
mContainer = container;
|
||||
mParent = parent;
|
||||
mAllowOldReentrantBehavior = getTargetSdk() <= Build.VERSION_CODES.N_MR1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the target SDK of the FragmentManager's application info. If the
|
||||
* FragmentManager has been torn down, then 0 is returned.
|
||||
*/
|
||||
int getTargetSdk() {
|
||||
if (mHost != null) {
|
||||
Context context = mHost.getContext();
|
||||
if (context != null) {
|
||||
ApplicationInfo info = context.getApplicationInfo();
|
||||
if (info != null) {
|
||||
return info.targetSdkVersion;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void noteStateNotSaved() {
|
||||
mStateSaved = false;
|
||||
}
|
||||
|
||||
public void dispatchCreate() {
|
||||
mStateSaved = false;
|
||||
mExecutingActions = true;
|
||||
moveToState(Fragment.CREATED, false);
|
||||
mExecutingActions = false;
|
||||
dispatchMoveToState(Fragment.CREATED);
|
||||
}
|
||||
|
||||
public void dispatchActivityCreated() {
|
||||
mStateSaved = false;
|
||||
mExecutingActions = true;
|
||||
moveToState(Fragment.ACTIVITY_CREATED, false);
|
||||
mExecutingActions = false;
|
||||
dispatchMoveToState(Fragment.ACTIVITY_CREATED);
|
||||
}
|
||||
|
||||
public void dispatchStart() {
|
||||
mStateSaved = false;
|
||||
mExecutingActions = true;
|
||||
moveToState(Fragment.STARTED, false);
|
||||
mExecutingActions = false;
|
||||
dispatchMoveToState(Fragment.STARTED);
|
||||
}
|
||||
|
||||
public void dispatchResume() {
|
||||
mStateSaved = false;
|
||||
mExecutingActions = true;
|
||||
moveToState(Fragment.RESUMED, false);
|
||||
mExecutingActions = false;
|
||||
dispatchMoveToState(Fragment.RESUMED);
|
||||
}
|
||||
|
||||
public void dispatchPause() {
|
||||
mExecutingActions = true;
|
||||
moveToState(Fragment.STARTED, false);
|
||||
mExecutingActions = false;
|
||||
dispatchMoveToState(Fragment.STARTED);
|
||||
}
|
||||
|
||||
public void dispatchStop() {
|
||||
mExecutingActions = true;
|
||||
moveToState(Fragment.STOPPED, false);
|
||||
mExecutingActions = false;
|
||||
dispatchMoveToState(Fragment.STOPPED);
|
||||
}
|
||||
|
||||
public void dispatchDestroyView() {
|
||||
mExecutingActions = true;
|
||||
moveToState(Fragment.CREATED, false);
|
||||
mExecutingActions = false;
|
||||
dispatchMoveToState(Fragment.CREATED);
|
||||
}
|
||||
|
||||
public void dispatchDestroy() {
|
||||
mDestroyed = true;
|
||||
execPendingActions();
|
||||
mExecutingActions = true;
|
||||
moveToState(Fragment.INITIALIZING, false);
|
||||
mExecutingActions = false;
|
||||
dispatchMoveToState(Fragment.INITIALIZING);
|
||||
mHost = null;
|
||||
mContainer = null;
|
||||
mParent = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called by dispatch* methods to change the FragmentManager's state.
|
||||
* It calls moveToState directly if the target SDK is older than O. Otherwise, it sets and
|
||||
* clears mExecutingActions to ensure that there is no reentrancy while the
|
||||
* FragmentManager is changing state.
|
||||
*
|
||||
* @param state The new state of the FragmentManager.
|
||||
*/
|
||||
private void dispatchMoveToState(int state) {
|
||||
if (mAllowOldReentrantBehavior) {
|
||||
moveToState(state, false);
|
||||
} else {
|
||||
try {
|
||||
mExecutingActions = true;
|
||||
moveToState(state, false);
|
||||
} finally {
|
||||
mExecutingActions = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void dispatchMultiWindowModeChanged(boolean isInMultiWindowMode) {
|
||||
if (mAdded == null) {
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user