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