Home | History | Annotate | Download | only in app
      1 /*
      2  * Copyright (C) 2010 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;
     18 
     19 import android.os.Parcel;
     20 import android.os.Parcelable;
     21 import android.text.TextUtils;
     22 import android.util.Log;
     23 import android.util.LogWriter;
     24 import com.android.internal.util.FastPrintWriter;
     25 
     26 import java.io.FileDescriptor;
     27 import java.io.PrintWriter;
     28 import java.util.ArrayList;
     29 
     30 final class BackStackState implements Parcelable {
     31     final int[] mOps;
     32     final int mTransition;
     33     final int mTransitionStyle;
     34     final String mName;
     35     final int mIndex;
     36     final int mBreadCrumbTitleRes;
     37     final CharSequence mBreadCrumbTitleText;
     38     final int mBreadCrumbShortTitleRes;
     39     final CharSequence mBreadCrumbShortTitleText;
     40 
     41     public BackStackState(FragmentManagerImpl fm, BackStackRecord bse) {
     42         int numRemoved = 0;
     43         BackStackRecord.Op op = bse.mHead;
     44         while (op != null) {
     45             if (op.removed != null) numRemoved += op.removed.size();
     46             op = op.next;
     47         }
     48         mOps = new int[bse.mNumOp*7 + numRemoved];
     49 
     50         if (!bse.mAddToBackStack) {
     51             throw new IllegalStateException("Not on back stack");
     52         }
     53 
     54         op = bse.mHead;
     55         int pos = 0;
     56         while (op != null) {
     57             mOps[pos++] = op.cmd;
     58             mOps[pos++] = op.fragment != null ? op.fragment.mIndex : -1;
     59             mOps[pos++] = op.enterAnim;
     60             mOps[pos++] = op.exitAnim;
     61             mOps[pos++] = op.popEnterAnim;
     62             mOps[pos++] = op.popExitAnim;
     63             if (op.removed != null) {
     64                 final int N = op.removed.size();
     65                 mOps[pos++] = N;
     66                 for (int i=0; i<N; i++) {
     67                     mOps[pos++] = op.removed.get(i).mIndex;
     68                 }
     69             } else {
     70                 mOps[pos++] = 0;
     71             }
     72             op = op.next;
     73         }
     74         mTransition = bse.mTransition;
     75         mTransitionStyle = bse.mTransitionStyle;
     76         mName = bse.mName;
     77         mIndex = bse.mIndex;
     78         mBreadCrumbTitleRes = bse.mBreadCrumbTitleRes;
     79         mBreadCrumbTitleText = bse.mBreadCrumbTitleText;
     80         mBreadCrumbShortTitleRes = bse.mBreadCrumbShortTitleRes;
     81         mBreadCrumbShortTitleText = bse.mBreadCrumbShortTitleText;
     82     }
     83 
     84     public BackStackState(Parcel in) {
     85         mOps = in.createIntArray();
     86         mTransition = in.readInt();
     87         mTransitionStyle = in.readInt();
     88         mName = in.readString();
     89         mIndex = in.readInt();
     90         mBreadCrumbTitleRes = in.readInt();
     91         mBreadCrumbTitleText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
     92         mBreadCrumbShortTitleRes = in.readInt();
     93         mBreadCrumbShortTitleText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
     94     }
     95 
     96     public BackStackRecord instantiate(FragmentManagerImpl fm) {
     97         BackStackRecord bse = new BackStackRecord(fm);
     98         int pos = 0;
     99         int num = 0;
    100         while (pos < mOps.length) {
    101             BackStackRecord.Op op = new BackStackRecord.Op();
    102             op.cmd = mOps[pos++];
    103             if (FragmentManagerImpl.DEBUG) Log.v(FragmentManagerImpl.TAG,
    104                     "Instantiate " + bse + " op #" + num + " base fragment #" + mOps[pos]);
    105             int findex = mOps[pos++];
    106             if (findex >= 0) {
    107                 Fragment f = fm.mActive.get(findex);
    108                 op.fragment = f;
    109             } else {
    110                 op.fragment = null;
    111             }
    112             op.enterAnim = mOps[pos++];
    113             op.exitAnim = mOps[pos++];
    114             op.popEnterAnim = mOps[pos++];
    115             op.popExitAnim = mOps[pos++];
    116             final int N = mOps[pos++];
    117             if (N > 0) {
    118                 op.removed = new ArrayList<Fragment>(N);
    119                 for (int i=0; i<N; i++) {
    120                     if (FragmentManagerImpl.DEBUG) Log.v(FragmentManagerImpl.TAG,
    121                             "Instantiate " + bse + " set remove fragment #" + mOps[pos]);
    122                     Fragment r = fm.mActive.get(mOps[pos++]);
    123                     op.removed.add(r);
    124                 }
    125             }
    126             bse.addOp(op);
    127             num++;
    128         }
    129         bse.mTransition = mTransition;
    130         bse.mTransitionStyle = mTransitionStyle;
    131         bse.mName = mName;
    132         bse.mIndex = mIndex;
    133         bse.mAddToBackStack = true;
    134         bse.mBreadCrumbTitleRes = mBreadCrumbTitleRes;
    135         bse.mBreadCrumbTitleText = mBreadCrumbTitleText;
    136         bse.mBreadCrumbShortTitleRes = mBreadCrumbShortTitleRes;
    137         bse.mBreadCrumbShortTitleText = mBreadCrumbShortTitleText;
    138         bse.bumpBackStackNesting(1);
    139         return bse;
    140     }
    141 
    142     public int describeContents() {
    143         return 0;
    144     }
    145 
    146     public void writeToParcel(Parcel dest, int flags) {
    147         dest.writeIntArray(mOps);
    148         dest.writeInt(mTransition);
    149         dest.writeInt(mTransitionStyle);
    150         dest.writeString(mName);
    151         dest.writeInt(mIndex);
    152         dest.writeInt(mBreadCrumbTitleRes);
    153         TextUtils.writeToParcel(mBreadCrumbTitleText, dest, 0);
    154         dest.writeInt(mBreadCrumbShortTitleRes);
    155         TextUtils.writeToParcel(mBreadCrumbShortTitleText, dest, 0);
    156     }
    157 
    158     public static final Parcelable.Creator<BackStackState> CREATOR
    159             = new Parcelable.Creator<BackStackState>() {
    160         public BackStackState createFromParcel(Parcel in) {
    161             return new BackStackState(in);
    162         }
    163 
    164         public BackStackState[] newArray(int size) {
    165             return new BackStackState[size];
    166         }
    167     };
    168 }
    169 
    170 /**
    171  * @hide Entry of an operation on the fragment back stack.
    172  */
    173 final class BackStackRecord extends FragmentTransaction implements
    174         FragmentManager.BackStackEntry, Runnable {
    175     static final String TAG = FragmentManagerImpl.TAG;
    176 
    177     final FragmentManagerImpl mManager;
    178 
    179     static final int OP_NULL = 0;
    180     static final int OP_ADD = 1;
    181     static final int OP_REPLACE = 2;
    182     static final int OP_REMOVE = 3;
    183     static final int OP_HIDE = 4;
    184     static final int OP_SHOW = 5;
    185     static final int OP_DETACH = 6;
    186     static final int OP_ATTACH = 7;
    187 
    188     static final class Op {
    189         Op next;
    190         Op prev;
    191         int cmd;
    192         Fragment fragment;
    193         int enterAnim;
    194         int exitAnim;
    195         int popEnterAnim;
    196         int popExitAnim;
    197         ArrayList<Fragment> removed;
    198     }
    199 
    200     Op mHead;
    201     Op mTail;
    202     int mNumOp;
    203     int mEnterAnim;
    204     int mExitAnim;
    205     int mPopEnterAnim;
    206     int mPopExitAnim;
    207     int mTransition;
    208     int mTransitionStyle;
    209     boolean mAddToBackStack;
    210     boolean mAllowAddToBackStack = true;
    211     String mName;
    212     boolean mCommitted;
    213     int mIndex = -1;
    214 
    215     int mBreadCrumbTitleRes;
    216     CharSequence mBreadCrumbTitleText;
    217     int mBreadCrumbShortTitleRes;
    218     CharSequence mBreadCrumbShortTitleText;
    219 
    220     @Override
    221     public String toString() {
    222         StringBuilder sb = new StringBuilder(128);
    223         sb.append("BackStackEntry{");
    224         sb.append(Integer.toHexString(System.identityHashCode(this)));
    225         if (mIndex >= 0) {
    226             sb.append(" #");
    227             sb.append(mIndex);
    228         }
    229         if (mName != null) {
    230             sb.append(" ");
    231             sb.append(mName);
    232         }
    233         sb.append("}");
    234         return sb.toString();
    235     }
    236 
    237     public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
    238         dump(prefix, writer, true);
    239     }
    240 
    241     void dump(String prefix, PrintWriter writer, boolean full) {
    242         if (full) {
    243             writer.print(prefix); writer.print("mName="); writer.print(mName);
    244                     writer.print(" mIndex="); writer.print(mIndex);
    245                     writer.print(" mCommitted="); writer.println(mCommitted);
    246             if (mTransition != FragmentTransaction.TRANSIT_NONE) {
    247                 writer.print(prefix); writer.print("mTransition=#");
    248                         writer.print(Integer.toHexString(mTransition));
    249                         writer.print(" mTransitionStyle=#");
    250                         writer.println(Integer.toHexString(mTransitionStyle));
    251             }
    252             if (mEnterAnim != 0 || mExitAnim !=0) {
    253                 writer.print(prefix); writer.print("mEnterAnim=#");
    254                         writer.print(Integer.toHexString(mEnterAnim));
    255                         writer.print(" mExitAnim=#");
    256                         writer.println(Integer.toHexString(mExitAnim));
    257             }
    258             if (mPopEnterAnim != 0 || mPopExitAnim !=0) {
    259                 writer.print(prefix); writer.print("mPopEnterAnim=#");
    260                         writer.print(Integer.toHexString(mPopEnterAnim));
    261                         writer.print(" mPopExitAnim=#");
    262                         writer.println(Integer.toHexString(mPopExitAnim));
    263             }
    264             if (mBreadCrumbTitleRes != 0 || mBreadCrumbTitleText != null) {
    265                 writer.print(prefix); writer.print("mBreadCrumbTitleRes=#");
    266                         writer.print(Integer.toHexString(mBreadCrumbTitleRes));
    267                         writer.print(" mBreadCrumbTitleText=");
    268                         writer.println(mBreadCrumbTitleText);
    269             }
    270             if (mBreadCrumbShortTitleRes != 0 || mBreadCrumbShortTitleText != null) {
    271                 writer.print(prefix); writer.print("mBreadCrumbShortTitleRes=#");
    272                         writer.print(Integer.toHexString(mBreadCrumbShortTitleRes));
    273                         writer.print(" mBreadCrumbShortTitleText=");
    274                         writer.println(mBreadCrumbShortTitleText);
    275             }
    276         }
    277 
    278         if (mHead != null) {
    279             writer.print(prefix); writer.println("Operations:");
    280             String innerPrefix = prefix + "    ";
    281             Op op = mHead;
    282             int num = 0;
    283             while (op != null) {
    284                 String cmdStr;
    285                 switch (op.cmd) {
    286                     case OP_NULL: cmdStr="NULL"; break;
    287                     case OP_ADD: cmdStr="ADD"; break;
    288                     case OP_REPLACE: cmdStr="REPLACE"; break;
    289                     case OP_REMOVE: cmdStr="REMOVE"; break;
    290                     case OP_HIDE: cmdStr="HIDE"; break;
    291                     case OP_SHOW: cmdStr="SHOW"; break;
    292                     case OP_DETACH: cmdStr="DETACH"; break;
    293                     case OP_ATTACH: cmdStr="ATTACH"; break;
    294                     default: cmdStr="cmd=" + op.cmd; break;
    295                 }
    296                 writer.print(prefix); writer.print("  Op #"); writer.print(num);
    297                         writer.print(": "); writer.print(cmdStr);
    298                         writer.print(" "); writer.println(op.fragment);
    299                 if (full) {
    300                     if (op.enterAnim != 0 || op.exitAnim != 0) {
    301                         writer.print(innerPrefix); writer.print("enterAnim=#");
    302                                 writer.print(Integer.toHexString(op.enterAnim));
    303                                 writer.print(" exitAnim=#");
    304                                 writer.println(Integer.toHexString(op.exitAnim));
    305                     }
    306                     if (op.popEnterAnim != 0 || op.popExitAnim != 0) {
    307                         writer.print(innerPrefix); writer.print("popEnterAnim=#");
    308                                 writer.print(Integer.toHexString(op.popEnterAnim));
    309                                 writer.print(" popExitAnim=#");
    310                                 writer.println(Integer.toHexString(op.popExitAnim));
    311                     }
    312                 }
    313                 if (op.removed != null && op.removed.size() > 0) {
    314                     for (int i=0; i<op.removed.size(); i++) {
    315                         writer.print(innerPrefix);
    316                         if (op.removed.size() == 1) {
    317                             writer.print("Removed: ");
    318                         } else {
    319                             if (i == 0) {
    320                                 writer.println("Removed:");
    321                             }
    322                             writer.print(innerPrefix); writer.print("  #"); writer.print(i);
    323                                     writer.print(": ");
    324                         }
    325                         writer.println(op.removed.get(i));
    326                     }
    327                 }
    328                 op = op.next;
    329                 num++;
    330             }
    331         }
    332     }
    333 
    334     public BackStackRecord(FragmentManagerImpl manager) {
    335         mManager = manager;
    336     }
    337 
    338     public int getId() {
    339         return mIndex;
    340     }
    341 
    342     public int getBreadCrumbTitleRes() {
    343         return mBreadCrumbTitleRes;
    344     }
    345 
    346     public int getBreadCrumbShortTitleRes() {
    347         return mBreadCrumbShortTitleRes;
    348     }
    349 
    350     public CharSequence getBreadCrumbTitle() {
    351         if (mBreadCrumbTitleRes != 0) {
    352             return mManager.mActivity.getText(mBreadCrumbTitleRes);
    353         }
    354         return mBreadCrumbTitleText;
    355     }
    356 
    357     public CharSequence getBreadCrumbShortTitle() {
    358         if (mBreadCrumbShortTitleRes != 0) {
    359             return mManager.mActivity.getText(mBreadCrumbShortTitleRes);
    360         }
    361         return mBreadCrumbShortTitleText;
    362     }
    363 
    364     void addOp(Op op) {
    365         if (mHead == null) {
    366             mHead = mTail = op;
    367         } else {
    368             op.prev = mTail;
    369             mTail.next = op;
    370             mTail = op;
    371         }
    372         op.enterAnim = mEnterAnim;
    373         op.exitAnim = mExitAnim;
    374         op.popEnterAnim = mPopEnterAnim;
    375         op.popExitAnim = mPopExitAnim;
    376         mNumOp++;
    377     }
    378 
    379     public FragmentTransaction add(Fragment fragment, String tag) {
    380         doAddOp(0, fragment, tag, OP_ADD);
    381         return this;
    382     }
    383 
    384     public FragmentTransaction add(int containerViewId, Fragment fragment) {
    385         doAddOp(containerViewId, fragment, null, OP_ADD);
    386         return this;
    387     }
    388 
    389     public FragmentTransaction add(int containerViewId, Fragment fragment, String tag) {
    390         doAddOp(containerViewId, fragment, tag, OP_ADD);
    391         return this;
    392     }
    393 
    394     private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
    395         fragment.mFragmentManager = mManager;
    396 
    397         if (tag != null) {
    398             if (fragment.mTag != null && !tag.equals(fragment.mTag)) {
    399                 throw new IllegalStateException("Can't change tag of fragment "
    400                         + fragment + ": was " + fragment.mTag
    401                         + " now " + tag);
    402             }
    403             fragment.mTag = tag;
    404         }
    405 
    406         if (containerViewId != 0) {
    407             if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {
    408                 throw new IllegalStateException("Can't change container ID of fragment "
    409                         + fragment + ": was " + fragment.mFragmentId
    410                         + " now " + containerViewId);
    411             }
    412             fragment.mContainerId = fragment.mFragmentId = containerViewId;
    413         }
    414 
    415         Op op = new Op();
    416         op.cmd = opcmd;
    417         op.fragment = fragment;
    418         addOp(op);
    419     }
    420 
    421     public FragmentTransaction replace(int containerViewId, Fragment fragment) {
    422         return replace(containerViewId, fragment, null);
    423     }
    424 
    425     public FragmentTransaction replace(int containerViewId, Fragment fragment, String tag) {
    426         if (containerViewId == 0) {
    427             throw new IllegalArgumentException("Must use non-zero containerViewId");
    428         }
    429 
    430         doAddOp(containerViewId, fragment, tag, OP_REPLACE);
    431         return this;
    432     }
    433 
    434     public FragmentTransaction remove(Fragment fragment) {
    435         Op op = new Op();
    436         op.cmd = OP_REMOVE;
    437         op.fragment = fragment;
    438         addOp(op);
    439 
    440         return this;
    441     }
    442 
    443     public FragmentTransaction hide(Fragment fragment) {
    444         Op op = new Op();
    445         op.cmd = OP_HIDE;
    446         op.fragment = fragment;
    447         addOp(op);
    448 
    449         return this;
    450     }
    451 
    452     public FragmentTransaction show(Fragment fragment) {
    453         Op op = new Op();
    454         op.cmd = OP_SHOW;
    455         op.fragment = fragment;
    456         addOp(op);
    457 
    458         return this;
    459     }
    460 
    461     public FragmentTransaction detach(Fragment fragment) {
    462         Op op = new Op();
    463         op.cmd = OP_DETACH;
    464         op.fragment = fragment;
    465         addOp(op);
    466 
    467         return this;
    468     }
    469 
    470     public FragmentTransaction attach(Fragment fragment) {
    471         Op op = new Op();
    472         op.cmd = OP_ATTACH;
    473         op.fragment = fragment;
    474         addOp(op);
    475 
    476         return this;
    477     }
    478 
    479     public FragmentTransaction setCustomAnimations(int enter, int exit) {
    480         return setCustomAnimations(enter, exit, 0, 0);
    481     }
    482 
    483     public FragmentTransaction setCustomAnimations(int enter, int exit,
    484             int popEnter, int popExit) {
    485         mEnterAnim = enter;
    486         mExitAnim = exit;
    487         mPopEnterAnim = popEnter;
    488         mPopExitAnim = popExit;
    489         return this;
    490     }
    491 
    492     public FragmentTransaction setTransition(int transition) {
    493         mTransition = transition;
    494         return this;
    495     }
    496 
    497     public FragmentTransaction setTransitionStyle(int styleRes) {
    498         mTransitionStyle = styleRes;
    499         return this;
    500     }
    501 
    502     public FragmentTransaction addToBackStack(String name) {
    503         if (!mAllowAddToBackStack) {
    504             throw new IllegalStateException(
    505                     "This FragmentTransaction is not allowed to be added to the back stack.");
    506         }
    507         mAddToBackStack = true;
    508         mName = name;
    509         return this;
    510     }
    511 
    512     public boolean isAddToBackStackAllowed() {
    513         return mAllowAddToBackStack;
    514     }
    515 
    516     public FragmentTransaction disallowAddToBackStack() {
    517         if (mAddToBackStack) {
    518             throw new IllegalStateException(
    519                     "This transaction is already being added to the back stack");
    520         }
    521         mAllowAddToBackStack = false;
    522         return this;
    523     }
    524 
    525     public FragmentTransaction setBreadCrumbTitle(int res) {
    526         mBreadCrumbTitleRes = res;
    527         mBreadCrumbTitleText = null;
    528         return this;
    529     }
    530 
    531     public FragmentTransaction setBreadCrumbTitle(CharSequence text) {
    532         mBreadCrumbTitleRes = 0;
    533         mBreadCrumbTitleText = text;
    534         return this;
    535     }
    536 
    537     public FragmentTransaction setBreadCrumbShortTitle(int res) {
    538         mBreadCrumbShortTitleRes = res;
    539         mBreadCrumbShortTitleText = null;
    540         return this;
    541     }
    542 
    543     public FragmentTransaction setBreadCrumbShortTitle(CharSequence text) {
    544         mBreadCrumbShortTitleRes = 0;
    545         mBreadCrumbShortTitleText = text;
    546         return this;
    547     }
    548 
    549     void bumpBackStackNesting(int amt) {
    550         if (!mAddToBackStack) {
    551             return;
    552         }
    553         if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting in " + this
    554                 + " by " + amt);
    555         Op op = mHead;
    556         while (op != null) {
    557             if (op.fragment != null) {
    558                 op.fragment.mBackStackNesting += amt;
    559                 if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of "
    560                         + op.fragment + " to " + op.fragment.mBackStackNesting);
    561             }
    562             if (op.removed != null) {
    563                 for (int i=op.removed.size()-1; i>=0; i--) {
    564                     Fragment r = op.removed.get(i);
    565                     r.mBackStackNesting += amt;
    566                     if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of "
    567                             + r + " to " + r.mBackStackNesting);
    568                 }
    569             }
    570             op = op.next;
    571         }
    572     }
    573 
    574     public int commit() {
    575         return commitInternal(false);
    576     }
    577 
    578     public int commitAllowingStateLoss() {
    579         return commitInternal(true);
    580     }
    581 
    582     int commitInternal(boolean allowStateLoss) {
    583         if (mCommitted) throw new IllegalStateException("commit already called");
    584         if (FragmentManagerImpl.DEBUG) {
    585             Log.v(TAG, "Commit: " + this);
    586             LogWriter logw = new LogWriter(Log.VERBOSE, TAG);
    587             PrintWriter pw = new FastPrintWriter(logw, false, 1024);
    588             dump("  ", null, pw, null);
    589             pw.flush();
    590         }
    591         mCommitted = true;
    592         if (mAddToBackStack) {
    593             mIndex = mManager.allocBackStackIndex(this);
    594         } else {
    595             mIndex = -1;
    596         }
    597         mManager.enqueueAction(this, allowStateLoss);
    598         return mIndex;
    599     }
    600 
    601     public void run() {
    602         if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Run: " + this);
    603 
    604         if (mAddToBackStack) {
    605             if (mIndex < 0) {
    606                 throw new IllegalStateException("addToBackStack() called after commit()");
    607             }
    608         }
    609 
    610         bumpBackStackNesting(1);
    611 
    612         Op op = mHead;
    613         while (op != null) {
    614             switch (op.cmd) {
    615                 case OP_ADD: {
    616                     Fragment f = op.fragment;
    617                     f.mNextAnim = op.enterAnim;
    618                     mManager.addFragment(f, false);
    619                 } break;
    620                 case OP_REPLACE: {
    621                     Fragment f = op.fragment;
    622                     if (mManager.mAdded != null) {
    623                         for (int i=0; i<mManager.mAdded.size(); i++) {
    624                             Fragment old = mManager.mAdded.get(i);
    625                             if (FragmentManagerImpl.DEBUG) Log.v(TAG,
    626                                     "OP_REPLACE: adding=" + f + " old=" + old);
    627                             if (f == null || old.mContainerId == f.mContainerId) {
    628                                 if (old == f) {
    629                                     op.fragment = f = null;
    630                                 } else {
    631                                     if (op.removed == null) {
    632                                         op.removed = new ArrayList<Fragment>();
    633                                     }
    634                                     op.removed.add(old);
    635                                     old.mNextAnim = op.exitAnim;
    636                                     if (mAddToBackStack) {
    637                                         old.mBackStackNesting += 1;
    638                                         if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of "
    639                                                 + old + " to " + old.mBackStackNesting);
    640                                     }
    641                                     mManager.removeFragment(old, mTransition, mTransitionStyle);
    642                                 }
    643                             }
    644                         }
    645                     }
    646                     if (f != null) {
    647                         f.mNextAnim = op.enterAnim;
    648                         mManager.addFragment(f, false);
    649                     }
    650                 } break;
    651                 case OP_REMOVE: {
    652                     Fragment f = op.fragment;
    653                     f.mNextAnim = op.exitAnim;
    654                     mManager.removeFragment(f, mTransition, mTransitionStyle);
    655                 } break;
    656                 case OP_HIDE: {
    657                     Fragment f = op.fragment;
    658                     f.mNextAnim = op.exitAnim;
    659                     mManager.hideFragment(f, mTransition, mTransitionStyle);
    660                 } break;
    661                 case OP_SHOW: {
    662                     Fragment f = op.fragment;
    663                     f.mNextAnim = op.enterAnim;
    664                     mManager.showFragment(f, mTransition, mTransitionStyle);
    665                 } break;
    666                 case OP_DETACH: {
    667                     Fragment f = op.fragment;
    668                     f.mNextAnim = op.exitAnim;
    669                     mManager.detachFragment(f, mTransition, mTransitionStyle);
    670                 } break;
    671                 case OP_ATTACH: {
    672                     Fragment f = op.fragment;
    673                     f.mNextAnim = op.enterAnim;
    674                     mManager.attachFragment(f, mTransition, mTransitionStyle);
    675                 } break;
    676                 default: {
    677                     throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
    678                 }
    679             }
    680 
    681             op = op.next;
    682         }
    683 
    684         mManager.moveToState(mManager.mCurState, mTransition,
    685                 mTransitionStyle, true);
    686 
    687         if (mAddToBackStack) {
    688             mManager.addBackStackState(this);
    689         }
    690     }
    691 
    692     public void popFromBackStack(boolean doStateMove) {
    693         if (FragmentManagerImpl.DEBUG) {
    694             Log.v(TAG, "popFromBackStack: " + this);
    695             LogWriter logw = new LogWriter(Log.VERBOSE, TAG);
    696             PrintWriter pw = new FastPrintWriter(logw, false, 1024);
    697             dump("  ", null, pw, null);
    698             pw.flush();
    699         }
    700 
    701         bumpBackStackNesting(-1);
    702 
    703         Op op = mTail;
    704         while (op != null) {
    705             switch (op.cmd) {
    706                 case OP_ADD: {
    707                     Fragment f = op.fragment;
    708                     f.mNextAnim = op.popExitAnim;
    709                     mManager.removeFragment(f,
    710                             FragmentManagerImpl.reverseTransit(mTransition),
    711                             mTransitionStyle);
    712                 } break;
    713                 case OP_REPLACE: {
    714                     Fragment f = op.fragment;
    715                     if (f != null) {
    716                         f.mNextAnim = op.popExitAnim;
    717                         mManager.removeFragment(f,
    718                                 FragmentManagerImpl.reverseTransit(mTransition),
    719                                 mTransitionStyle);
    720                     }
    721                     if (op.removed != null) {
    722                         for (int i=0; i<op.removed.size(); i++) {
    723                             Fragment old = op.removed.get(i);
    724                             old.mNextAnim = op.popEnterAnim;
    725                             mManager.addFragment(old, false);
    726                         }
    727                     }
    728                 } break;
    729                 case OP_REMOVE: {
    730                     Fragment f = op.fragment;
    731                     f.mNextAnim = op.popEnterAnim;
    732                     mManager.addFragment(f, false);
    733                 } break;
    734                 case OP_HIDE: {
    735                     Fragment f = op.fragment;
    736                     f.mNextAnim = op.popEnterAnim;
    737                     mManager.showFragment(f,
    738                             FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
    739                 } break;
    740                 case OP_SHOW: {
    741                     Fragment f = op.fragment;
    742                     f.mNextAnim = op.popExitAnim;
    743                     mManager.hideFragment(f,
    744                             FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
    745                 } break;
    746                 case OP_DETACH: {
    747                     Fragment f = op.fragment;
    748                     f.mNextAnim = op.popEnterAnim;
    749                     mManager.attachFragment(f,
    750                             FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
    751                 } break;
    752                 case OP_ATTACH: {
    753                     Fragment f = op.fragment;
    754                     f.mNextAnim = op.popExitAnim;
    755                     mManager.detachFragment(f,
    756                             FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
    757                 } break;
    758                 default: {
    759                     throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
    760                 }
    761             }
    762 
    763             op = op.prev;
    764         }
    765 
    766         if (doStateMove) {
    767             mManager.moveToState(mManager.mCurState,
    768                     FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle, true);
    769         }
    770 
    771         if (mIndex >= 0) {
    772             mManager.freeBackStackIndex(mIndex);
    773             mIndex = -1;
    774         }
    775     }
    776 
    777     public String getName() {
    778         return mName;
    779     }
    780 
    781     public int getTransition() {
    782         return mTransition;
    783     }
    784 
    785     public int getTransitionStyle() {
    786         return mTransitionStyle;
    787     }
    788 
    789     public boolean isEmpty() {
    790         return mNumOp == 0;
    791     }
    792 }
    793