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