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