Merge "Work on issue #7232641: ISE crash when rotating phone in label list mode" into jb-mr1-dev

This commit is contained in:
Dianne Hackborn
2012-09-27 00:53:39 -07:00
committed by Android (Google) Code Review
2 changed files with 138 additions and 62 deletions

View File

@@ -20,6 +20,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.Log;
import android.util.LogWriter;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -94,11 +95,12 @@ final class BackStackState implements Parcelable {
public BackStackRecord instantiate(FragmentManagerImpl fm) {
BackStackRecord bse = new BackStackRecord(fm);
int pos = 0;
int num = 0;
while (pos < mOps.length) {
BackStackRecord.Op op = new BackStackRecord.Op();
op.cmd = mOps[pos++];
if (FragmentManagerImpl.DEBUG) Log.v(FragmentManagerImpl.TAG,
"BSE " + bse + " set base fragment #" + mOps[pos]);
"Instantiate " + bse + " op #" + num + " base fragment #" + mOps[pos]);
int findex = mOps[pos++];
if (findex >= 0) {
Fragment f = fm.mActive.get(findex);
@@ -115,12 +117,13 @@ final class BackStackState implements Parcelable {
op.removed = new ArrayList<Fragment>(N);
for (int i=0; i<N; i++) {
if (FragmentManagerImpl.DEBUG) Log.v(FragmentManagerImpl.TAG,
"BSE " + bse + " set remove fragment #" + mOps[pos]);
"Instantiate " + bse + " set remove fragment #" + mOps[pos]);
Fragment r = fm.mActive.get(mOps[pos++]);
op.removed.add(r);
}
}
bse.addOp(op);
num++;
}
bse.mTransition = mTransition;
bse.mTransitionStyle = mTransitionStyle;
@@ -168,7 +171,7 @@ final class BackStackState implements Parcelable {
*/
final class BackStackRecord extends FragmentTransaction implements
FragmentManager.BackStackEntry, Runnable {
static final String TAG = "BackStackEntry";
static final String TAG = FragmentManagerImpl.TAG;
final FragmentManagerImpl mManager;
@@ -206,46 +209,69 @@ final class BackStackRecord extends FragmentTransaction implements
boolean mAllowAddToBackStack = true;
String mName;
boolean mCommitted;
int mIndex;
int mIndex = -1;
int mBreadCrumbTitleRes;
CharSequence mBreadCrumbTitleText;
int mBreadCrumbShortTitleRes;
CharSequence mBreadCrumbShortTitleText;
@Override
public String toString() {
StringBuilder sb = new StringBuilder(128);
sb.append("BackStackEntry{");
sb.append(Integer.toHexString(System.identityHashCode(this)));
if (mIndex >= 0) {
sb.append(" #");
sb.append(mIndex);
}
if (mName != null) {
sb.append(" ");
sb.append(mName);
}
sb.append("}");
return sb.toString();
}
public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
writer.print(prefix); writer.print("mName="); writer.print(mName);
writer.print(" mIndex="); writer.print(mIndex);
writer.print(" mCommitted="); writer.println(mCommitted);
if (mTransition != FragmentTransaction.TRANSIT_NONE) {
writer.print(prefix); writer.print("mTransition=#");
writer.print(Integer.toHexString(mTransition));
writer.print(" mTransitionStyle=#");
writer.println(Integer.toHexString(mTransitionStyle));
}
if (mEnterAnim != 0 || mExitAnim !=0) {
writer.print(prefix); writer.print("mEnterAnim=#");
writer.print(Integer.toHexString(mEnterAnim));
writer.print(" mExitAnim=#");
writer.println(Integer.toHexString(mExitAnim));
}
if (mPopEnterAnim != 0 || mPopExitAnim !=0) {
writer.print(prefix); writer.print("mPopEnterAnim=#");
writer.print(Integer.toHexString(mPopEnterAnim));
writer.print(" mPopExitAnim=#");
writer.println(Integer.toHexString(mPopExitAnim));
}
if (mBreadCrumbTitleRes != 0 || mBreadCrumbTitleText != null) {
writer.print(prefix); writer.print("mBreadCrumbTitleRes=#");
writer.print(Integer.toHexString(mBreadCrumbTitleRes));
writer.print(" mBreadCrumbTitleText=");
writer.println(mBreadCrumbTitleText);
}
if (mBreadCrumbShortTitleRes != 0 || mBreadCrumbShortTitleText != null) {
writer.print(prefix); writer.print("mBreadCrumbShortTitleRes=#");
writer.print(Integer.toHexString(mBreadCrumbShortTitleRes));
writer.print(" mBreadCrumbShortTitleText=");
writer.println(mBreadCrumbShortTitleText);
dump(prefix, writer, true);
}
void dump(String prefix, PrintWriter writer, boolean full) {
if (full) {
writer.print(prefix); writer.print("mName="); writer.print(mName);
writer.print(" mIndex="); writer.print(mIndex);
writer.print(" mCommitted="); writer.println(mCommitted);
if (mTransition != FragmentTransaction.TRANSIT_NONE) {
writer.print(prefix); writer.print("mTransition=#");
writer.print(Integer.toHexString(mTransition));
writer.print(" mTransitionStyle=#");
writer.println(Integer.toHexString(mTransitionStyle));
}
if (mEnterAnim != 0 || mExitAnim !=0) {
writer.print(prefix); writer.print("mEnterAnim=#");
writer.print(Integer.toHexString(mEnterAnim));
writer.print(" mExitAnim=#");
writer.println(Integer.toHexString(mExitAnim));
}
if (mPopEnterAnim != 0 || mPopExitAnim !=0) {
writer.print(prefix); writer.print("mPopEnterAnim=#");
writer.print(Integer.toHexString(mPopEnterAnim));
writer.print(" mPopExitAnim=#");
writer.println(Integer.toHexString(mPopExitAnim));
}
if (mBreadCrumbTitleRes != 0 || mBreadCrumbTitleText != null) {
writer.print(prefix); writer.print("mBreadCrumbTitleRes=#");
writer.print(Integer.toHexString(mBreadCrumbTitleRes));
writer.print(" mBreadCrumbTitleText=");
writer.println(mBreadCrumbTitleText);
}
if (mBreadCrumbShortTitleRes != 0 || mBreadCrumbShortTitleText != null) {
writer.print(prefix); writer.print("mBreadCrumbShortTitleRes=#");
writer.print(Integer.toHexString(mBreadCrumbShortTitleRes));
writer.print(" mBreadCrumbShortTitleText=");
writer.println(mBreadCrumbShortTitleText);
}
}
if (mHead != null) {
@@ -254,21 +280,34 @@ final class BackStackRecord extends FragmentTransaction implements
Op op = mHead;
int num = 0;
while (op != null) {
writer.print(prefix); writer.print(" Op #"); writer.print(num);
writer.println(":");
writer.print(innerPrefix); writer.print("cmd="); writer.print(op.cmd);
writer.print(" fragment="); writer.println(op.fragment);
if (op.enterAnim != 0 || op.exitAnim != 0) {
writer.print(prefix); writer.print("enterAnim=#");
writer.print(Integer.toHexString(op.enterAnim));
writer.print(" exitAnim=#");
writer.println(Integer.toHexString(op.exitAnim));
String cmdStr;
switch (op.cmd) {
case OP_NULL: cmdStr="NULL"; break;
case OP_ADD: cmdStr="ADD"; break;
case OP_REPLACE: cmdStr="REPLACE"; break;
case OP_REMOVE: cmdStr="REMOVE"; break;
case OP_HIDE: cmdStr="HIDE"; break;
case OP_SHOW: cmdStr="SHOW"; break;
case OP_DETACH: cmdStr="DETACH"; break;
case OP_ATTACH: cmdStr="ATTACH"; break;
default: cmdStr="cmd=" + op.cmd; break;
}
if (op.popEnterAnim != 0 || op.popExitAnim != 0) {
writer.print(prefix); writer.print("popEnterAnim=#");
writer.print(Integer.toHexString(op.popEnterAnim));
writer.print(" popExitAnim=#");
writer.println(Integer.toHexString(op.popExitAnim));
writer.print(prefix); writer.print(" Op #"); writer.print(num);
writer.print(": "); writer.print(cmdStr);
writer.print(" "); writer.println(op.fragment);
if (full) {
if (op.enterAnim != 0 || op.exitAnim != 0) {
writer.print(innerPrefix); writer.print("enterAnim=#");
writer.print(Integer.toHexString(op.enterAnim));
writer.print(" exitAnim=#");
writer.println(Integer.toHexString(op.exitAnim));
}
if (op.popEnterAnim != 0 || op.popExitAnim != 0) {
writer.print(innerPrefix); writer.print("popEnterAnim=#");
writer.print(Integer.toHexString(op.popEnterAnim));
writer.print(" popExitAnim=#");
writer.println(Integer.toHexString(op.popExitAnim));
}
}
if (op.removed != null && op.removed.size() > 0) {
for (int i=0; i<op.removed.size(); i++) {
@@ -276,14 +315,17 @@ final class BackStackRecord extends FragmentTransaction implements
if (op.removed.size() == 1) {
writer.print("Removed: ");
} else {
writer.println("Removed:");
writer.print(innerPrefix); writer.print(" #"); writer.print(num);
if (i == 0) {
writer.println("Removed:");
}
writer.print(innerPrefix); writer.print(" #"); writer.print(i);
writer.print(": ");
}
writer.println(op.removed.get(i));
}
}
op = op.next;
num++;
}
}
}
@@ -538,7 +580,12 @@ final class BackStackRecord extends FragmentTransaction implements
int commitInternal(boolean allowStateLoss) {
if (mCommitted) throw new IllegalStateException("commit already called");
if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Commit: " + this);
if (FragmentManagerImpl.DEBUG) {
Log.v(TAG, "Commit: " + this);
LogWriter logw = new LogWriter(Log.VERBOSE, TAG);
PrintWriter pw = new PrintWriter(logw);
dump(" ", null, pw, null);
}
mCommitted = true;
if (mAddToBackStack) {
mIndex = mManager.allocBackStackIndex(this);
@@ -641,7 +688,12 @@ final class BackStackRecord extends FragmentTransaction implements
}
public void popFromBackStack(boolean doStateMove) {
if (FragmentManagerImpl.DEBUG) Log.v(TAG, "popFromBackStack: " + this);
if (FragmentManagerImpl.DEBUG) {
Log.v(TAG, "popFromBackStack: " + this);
LogWriter logw = new LogWriter(Log.VERBOSE, TAG);
PrintWriter pw = new PrintWriter(logw);
dump(" ", null, pw, null);
}
bumpBackStackNesting(-1);

View File

@@ -22,6 +22,7 @@ import android.animation.AnimatorListenerAdapter;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
import android.os.Looper;
import android.os.Parcel;
@@ -771,9 +772,9 @@ final class FragmentManagerImpl extends FragmentManager {
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
//if (DEBUG) Log.v(TAG, "moveToState: " + f
// + " oldState=" + f.mState + " newState=" + newState
// + " mRemoving=" + f.mRemoving + " Callers=" + Debug.getCallers(5));
if (DEBUG && false) Log.v(TAG, "moveToState: " + f
+ " oldState=" + f.mState + " newState=" + newState
+ " mRemoving=" + f.mRemoving + " Callers=" + Debug.getCallers(5));
// Fragments that are not currently added will sit in the onCreate() state.
if ((!f.mAdded || f.mDetached) && newState > Fragment.CREATED) {
@@ -1112,6 +1113,9 @@ final class FragmentManagerImpl extends FragmentManager {
if (DEBUG) Log.v(TAG, "add: " + fragment);
makeActive(fragment);
if (!fragment.mDetached) {
if (mAdded.contains(fragment)) {
throw new IllegalStateException("Fragment already added: " + fragment);
}
mAdded.add(fragment);
fragment.mAdded = true;
fragment.mRemoving = false;
@@ -1128,6 +1132,14 @@ final class FragmentManagerImpl extends FragmentManager {
if (DEBUG) Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting);
final boolean inactive = !fragment.isInBackStack();
if (!fragment.mDetached || inactive) {
if (false) {
// Would be nice to catch a bad remove here, but we need
// time to test this to make sure we aren't crashes cases
// where it is not a problem.
if (!mAdded.contains(fragment)) {
throw new IllegalStateException("Fragment not added: " + fragment);
}
}
if (mAdded != null) {
mAdded.remove(fragment);
}
@@ -1200,6 +1212,7 @@ final class FragmentManagerImpl extends FragmentManager {
if (fragment.mAdded) {
// We are not already in back stack, so need to remove the fragment.
if (mAdded != null) {
if (DEBUG) Log.v(TAG, "remove from detach: " + fragment);
mAdded.remove(fragment);
}
if (fragment.mHasMenu && fragment.mMenuVisible) {
@@ -1219,6 +1232,10 @@ final class FragmentManagerImpl extends FragmentManager {
if (mAdded == null) {
mAdded = new ArrayList<Fragment>();
}
if (mAdded.contains(fragment)) {
throw new IllegalStateException("Fragment already added: " + fragment);
}
if (DEBUG) Log.v(TAG, "add from attach: " + fragment);
mAdded.add(fragment);
fragment.mAdded = true;
if (fragment.mHasMenu && fragment.mMenuVisible) {
@@ -1717,19 +1734,18 @@ final class FragmentManagerImpl extends FragmentManager {
FragmentState fs = fms.mActive[i];
if (fs != null) {
Fragment f = fs.instantiate(mActivity, mParent);
if (DEBUG) Log.v(TAG, "restoreAllState: adding #" + i + ": " + f);
if (DEBUG) Log.v(TAG, "restoreAllState: active #" + i + ": " + f);
mActive.add(f);
// Now that the fragment is instantiated (or came from being
// retained above), clear mInstance in case we end up re-restoring
// from this FragmentState again.
fs.mInstance = null;
} else {
if (DEBUG) Log.v(TAG, "restoreAllState: adding #" + i + ": (null)");
mActive.add(null);
if (mAvailIndices == null) {
mAvailIndices = new ArrayList<Integer>();
}
if (DEBUG) Log.v(TAG, "restoreAllState: adding avail #" + i);
if (DEBUG) Log.v(TAG, "restoreAllState: avail #" + i);
mAvailIndices.add(i);
}
}
@@ -1760,7 +1776,10 @@ final class FragmentManagerImpl extends FragmentManager {
"No instantiated fragment for index #" + fms.mAdded[i]));
}
f.mAdded = true;
if (DEBUG) Log.v(TAG, "restoreAllState: making added #" + i + ": " + f);
if (DEBUG) Log.v(TAG, "restoreAllState: added #" + i + ": " + f);
if (mAdded.contains(f)) {
throw new IllegalStateException("Already added!");
}
mAdded.add(f);
}
} else {
@@ -1772,8 +1791,13 @@ final class FragmentManagerImpl extends FragmentManager {
mBackStack = new ArrayList<BackStackRecord>(fms.mBackStack.length);
for (int i=0; i<fms.mBackStack.length; i++) {
BackStackRecord bse = fms.mBackStack[i].instantiate(this);
if (DEBUG) Log.v(TAG, "restoreAllState: adding bse #" + i
if (DEBUG) {
Log.v(TAG, "restoreAllState: back stack #" + i
+ " (index " + bse.mIndex + "): " + bse);
LogWriter logw = new LogWriter(Log.VERBOSE, TAG);
PrintWriter pw = new PrintWriter(logw);
bse.dump(" ", pw, false);
}
mBackStack.add(bse);
if (bse.mIndex >= 0) {
setBackStackIndex(bse.mIndex, bse);