FragmentManager.java revision b4bc78b16a05554c57508b488e21dd8eca4e13e6
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
17package android.app;
18
19import android.content.res.TypedArray;
20import android.os.Bundle;
21import android.os.Handler;
22import android.os.Parcel;
23import android.os.Parcelable;
24import android.util.SparseArray;
25import android.view.ViewGroup;
26import android.view.animation.Animation;
27import android.view.animation.AnimationUtils;
28
29import java.util.ArrayList;
30import java.util.HashMap;
31
32final class BackStackEntry implements FragmentTransaction, Runnable {
33    final FragmentManager mManager;
34
35    ArrayList<Fragment> mAdded;
36    ArrayList<Fragment> mRemoved;
37    int mTransition;
38    int mTransitionStyle;
39    boolean mAddToBackStack;
40    String mName;
41    boolean mCommitted;
42
43    public BackStackEntry(FragmentManager manager) {
44        mManager = manager;
45    }
46
47    public FragmentTransaction add(Fragment fragment, String tag) {
48        fragment.mTag = tag;
49        return add(fragment, 0);
50    }
51
52    public FragmentTransaction add(Fragment fragment, int containerViewId) {
53        if (fragment.mActivity != null) {
54            throw new IllegalStateException("Fragment already added: " + fragment);
55        }
56        if (mRemoved != null) {
57            mRemoved.remove(fragment);
58        }
59        if (mAdded == null) {
60            mAdded = new ArrayList<Fragment>();
61        }
62        fragment.mContainerId = fragment.mFragmentId = containerViewId;
63        mAdded.add(fragment);
64        return this;
65    }
66
67    public FragmentTransaction replace(Fragment fragment, int containerViewId) {
68        if (containerViewId == 0) {
69            throw new IllegalArgumentException("Must use non-zero containerViewId");
70        }
71        if (mManager.mFragments != null) {
72            for (int i=0; i<mManager.mFragments.size(); i++) {
73                Fragment old = mManager.mFragments.get(i);
74                if (old.mContainerId == containerViewId) {
75                    remove(old);
76                }
77            }
78        }
79        return add(fragment, containerViewId);
80    }
81
82    public FragmentTransaction remove(Fragment fragment) {
83        if (fragment.mActivity == null) {
84            throw new IllegalStateException("Fragment not added: " + fragment);
85        }
86        if (mAdded != null) {
87            mAdded.remove(fragment);
88        }
89        if (mRemoved == null) {
90            mRemoved = new ArrayList<Fragment>();
91        }
92        mRemoved.add(fragment);
93        return this;
94    }
95
96    public FragmentTransaction setTransition(int transition) {
97        mTransition = transition;
98        return this;
99    }
100
101    public FragmentTransaction setTransitionStyle(int styleRes) {
102        mTransitionStyle = styleRes;
103        return this;
104    }
105
106    public FragmentTransaction addToBackStack(String name) {
107        mAddToBackStack = true;
108        mName = name;
109        return this;
110    }
111
112    public void commit() {
113        if (mCommitted) throw new IllegalStateException("commit already called");
114        mCommitted = true;
115        mManager.mActivity.mHandler.post(this);
116    }
117
118    public void run() {
119        if (mRemoved != null) {
120            for (int i=mRemoved.size()-1; i>=0; i--) {
121                mManager.removeFragment(mRemoved.get(i), mTransition,
122                        mTransitionStyle);
123            }
124        }
125        if (mAdded != null) {
126            for (int i=mAdded.size()-1; i>=0; i--) {
127                Fragment f = mAdded.get(i);
128                mManager.addFragment(f, false);
129                if (mAddToBackStack) {
130                    f.mBackStackNesting++;
131                }
132            }
133        }
134        mManager.moveToState(mManager.mCurState, mTransition,
135                mTransitionStyle, true);
136        if (mAddToBackStack) {
137            mManager.addBackStackState(this);
138        }
139    }
140
141    public void popFromBackStack() {
142        if (mAdded != null) {
143            for (int i=mAdded.size()-1; i>=0; i--) {
144                Fragment f = mAdded.get(i);
145                if (mAddToBackStack) {
146                    f.mBackStackNesting--;
147                }
148                mManager.removeFragment(f,
149                        FragmentManager.reverseTransit(mTransition),
150                        mTransitionStyle);
151            }
152        }
153        if (mRemoved != null) {
154            for (int i=mRemoved.size()-1; i>=0; i--) {
155                mManager.addFragment(mRemoved.get(i), false);
156            }
157        }
158    }
159
160    public String getName() {
161        return mName;
162    }
163
164    public int getTransition() {
165        return mTransition;
166    }
167
168    public int getTransitionStyle() {
169        return mTransitionStyle;
170    }
171}
172
173final class BackStackState implements Parcelable {
174    final int[] mAdded;
175    final int[] mRemoved;
176    final int mTransition;
177    final int mTransitionStyle;
178    final String mName;
179
180    public BackStackState(FragmentManager fm, BackStackEntry bse) {
181        mAdded = buildFragmentStateList(fm, bse.mAdded);
182        mRemoved = buildFragmentStateList(fm, bse.mRemoved);
183        mTransition = bse.mTransition;
184        mTransitionStyle = bse.mTransitionStyle;
185        mName = bse.mName;
186    }
187
188    public BackStackState(Parcel in) {
189        mAdded = in.createIntArray();
190        mRemoved = in.createIntArray();
191        mTransition = in.readInt();
192        mTransitionStyle = in.readInt();
193        mName = in.readString();
194    }
195
196    public BackStackEntry instantiate(FragmentManager fm) {
197        BackStackEntry bse = new BackStackEntry(fm);
198        bse.mAdded = buildFragmentList(fm, mAdded);
199        bse.mRemoved = buildFragmentList(fm, mRemoved);
200        bse.mTransition = mTransition;
201        bse.mTransitionStyle = mTransitionStyle;
202        bse.mName = mName;
203        return bse;
204    }
205
206    static int[] buildFragmentStateList(FragmentManager fm, ArrayList<Fragment> frags) {
207        if (frags == null) return null;
208        final int N = frags.size();
209        int[] ids = new int[N];
210        for (int i=0; i<N; i++) {
211            FragmentState fs = fm.saveFragment(frags.get(i));
212            ids[i] = fs.mSavedStateId;
213        }
214        return ids;
215    }
216
217    static ArrayList<Fragment> buildFragmentList(FragmentManager fm, int[] states) {
218        if (states == null) return null;
219        final int N = states.length;
220        ArrayList<Fragment> frags = new ArrayList<Fragment>(N);
221        for (int i=0; i<N; i++) {
222            frags.add(fm.mRestoredFragments.get(states[i]).instantiate(fm.mActivity));
223        }
224        return frags;
225    }
226
227    public int describeContents() {
228        return 0;
229    }
230
231    public void writeToParcel(Parcel dest, int flags) {
232        dest.writeIntArray(mAdded);
233        dest.writeIntArray(mRemoved);
234        dest.writeInt(mTransition);
235        dest.writeInt(mTransitionStyle);
236        dest.writeString(mName);
237    }
238
239    public static final Parcelable.Creator<BackStackState> CREATOR
240            = new Parcelable.Creator<BackStackState>() {
241        public BackStackState createFromParcel(Parcel in) {
242            return new BackStackState(in);
243        }
244
245        public BackStackState[] newArray(int size) {
246            return new BackStackState[size];
247        }
248    };
249}
250
251final class FragmentManagerState implements Parcelable {
252    FragmentState[] mFragments;
253    int[] mAdded;
254    BackStackState[] mBackStack;
255
256    public FragmentManagerState() {
257    }
258
259    public FragmentManagerState(Parcel in) {
260        mFragments = in.createTypedArray(FragmentState.CREATOR);
261        mAdded = in.createIntArray();
262        mBackStack = in.createTypedArray(BackStackState.CREATOR);
263    }
264
265    public int describeContents() {
266        return 0;
267    }
268
269    public void writeToParcel(Parcel dest, int flags) {
270        dest.writeTypedArray(mFragments, flags);
271        dest.writeIntArray(mAdded);
272        dest.writeTypedArray(mBackStack, flags);
273    }
274
275    public static final Parcelable.Creator<FragmentManagerState> CREATOR
276            = new Parcelable.Creator<FragmentManagerState>() {
277        public FragmentManagerState createFromParcel(Parcel in) {
278            return new FragmentManagerState(in);
279        }
280
281        public FragmentManagerState[] newArray(int size) {
282            return new FragmentManagerState[size];
283        }
284    };
285}
286
287/**
288 * @hide
289 * Container for fragments associated with an activity.
290 */
291public class FragmentManager {
292    ArrayList<Fragment> mFragments;
293    ArrayList<BackStackEntry> mBackStack;
294
295    int mCurState = Fragment.INITIALIZING;
296    Activity mActivity;
297
298    int mSaveStateSeq = 0;
299
300    // Temporary vars for state save and restore.
301    int mCurSaveId = 0;
302    HashMap<Fragment, FragmentState> mSavedFragments;
303    SparseArray<FragmentState> mRestoredFragments;
304    Bundle mStateBundle = null;
305    SparseArray<Parcelable> mStateArray = null;
306
307    Animation loadAnimation(Fragment fragment, int transit, boolean enter,
308            int transitionStyle) {
309        Animation animObj = fragment.onCreateAnimation(transitionStyle, enter);
310        if (animObj != null) {
311            return animObj;
312        }
313
314        if (transit == 0) {
315            return null;
316        }
317
318        int styleIndex = transitToStyleIndex(transit, enter);
319        if (styleIndex < 0) {
320            return null;
321        }
322
323        if (transitionStyle == 0 && mActivity.getWindow() != null) {
324            transitionStyle = mActivity.getWindow().getAttributes().windowAnimations;
325        }
326        if (transitionStyle == 0) {
327            return null;
328        }
329
330        TypedArray attrs = mActivity.obtainStyledAttributes(transitionStyle,
331                com.android.internal.R.styleable.WindowAnimation);
332        int anim = attrs.getResourceId(styleIndex, 0);
333        attrs.recycle();
334
335        if (anim == 0) {
336            return null;
337        }
338
339        return AnimationUtils.loadAnimation(mActivity, anim);
340    }
341
342    void moveToState(Fragment f, int newState, int transit, int transitionStyle) {
343        if (f.mState < newState) {
344            switch (f.mState) {
345                case Fragment.INITIALIZING:
346                    f.mActivity = mActivity;
347                    f.mCalled = false;
348                    f.onAttach(mActivity);
349                    if (!f.mCalled) {
350                        throw new SuperNotCalledException("Fragment " + f
351                                + " did not call through to super.onAttach()");
352                    }
353
354                    if (!f.mRetaining) {
355                        f.mCalled = false;
356                        f.onCreate(f.mSavedFragmentState);
357                        if (!f.mCalled) {
358                            throw new SuperNotCalledException("Fragment " + f
359                                    + " did not call through to super.onCreate()");
360                        }
361                    }
362                    f.mRetaining = false;
363                    if (f.mFromLayout) {
364                        // For fragments that are part of the content view
365                        // layout, we need to instantiate the view immediately
366                        // and the inflater will take care of adding it.
367                        f.mView = f.onCreateView(mActivity.getLayoutInflater(),
368                                null, f.mSavedFragmentState);
369                    }
370                case Fragment.CONTENT:
371                    if (newState > Fragment.CONTENT) {
372                        if (!f.mFromLayout) {
373                            ViewGroup container = null;
374                            if (f.mContainerId != 0) {
375                                container = (ViewGroup)mActivity.findViewById(f.mContainerId);
376                                if (container == null) {
377                                    throw new IllegalArgumentException("New view found for id 0x"
378                                            + Integer.toHexString(f.mContainerId)
379                                            + " for fragment " + f);
380                                }
381                            }
382                            f.mContainer = container;
383                            f.mView = f.onCreateView(mActivity.getLayoutInflater(),
384                                    container, f.mSavedFragmentState);
385                            if (f.mView != null) {
386                                f.mView.setSaveFromParentEnabled(false);
387                                if (container != null) {
388                                    Animation anim = loadAnimation(f, transit, true,
389                                            transitionStyle);
390                                    if (anim != null) {
391                                        f.mView.setAnimation(anim);
392                                    }
393                                    container.addView(f.mView);
394                                    f.restoreViewState();
395                                }
396                            }
397                        }
398
399                        f.mCalled = false;
400                        f.onReady(f.mSavedFragmentState);
401                        if (!f.mCalled) {
402                            throw new SuperNotCalledException("Fragment " + f
403                                    + " did not call through to super.onReady()");
404                        }
405                        f.mSavedFragmentState = null;
406                    }
407                case Fragment.CREATED:
408                    if (newState > Fragment.CREATED) {
409                        f.mCalled = false;
410                        f.onStart();
411                        if (!f.mCalled) {
412                            throw new SuperNotCalledException("Fragment " + f
413                                    + " did not call through to super.onStart()");
414                        }
415                    }
416                case Fragment.STARTED:
417                    if (newState > Fragment.STARTED) {
418                        f.mCalled = false;
419                        f.onResume();
420                        if (!f.mCalled) {
421                            throw new SuperNotCalledException("Fragment " + f
422                                    + " did not call through to super.onResume()");
423                        }
424                    }
425            }
426        } else if (f.mState > newState) {
427            switch (f.mState) {
428                case Fragment.RESUMED:
429                    if (newState < Fragment.RESUMED) {
430                        f.mCalled = false;
431                        f.onPause();
432                        if (!f.mCalled) {
433                            throw new SuperNotCalledException("Fragment " + f
434                                    + " did not call through to super.onPause()");
435                        }
436                    }
437                case Fragment.STARTED:
438                    if (newState < Fragment.STARTED) {
439                        f.mCalled = false;
440                        f.onStop();
441                        if (!f.mCalled) {
442                            throw new SuperNotCalledException("Fragment " + f
443                                    + " did not call through to super.onStop()");
444                        }
445                    }
446                case Fragment.CONTENT:
447                    if (newState < Fragment.CONTENT) {
448                        if (f.mView != null) {
449                            // Need to save the current view state if not
450                            // done already.
451                            if (!mActivity.isFinishing()) {
452                                saveFragmentViewState(f);
453                            }
454                            if (f.mContainer != null) {
455                                if (mCurState > Fragment.INITIALIZING) {
456                                    Animation anim = loadAnimation(f, transit, false,
457                                            transitionStyle);
458                                    if (anim != null) {
459                                        f.mView.setAnimation(anim);
460                                    }
461                                }
462                                f.mContainer.removeView(f.mView);
463                            }
464                        }
465                        f.mContainer = null;
466                        f.mView = null;
467                    }
468                case Fragment.CREATED:
469                    if (newState < Fragment.CREATED) {
470                        if (!f.mRetaining) {
471                            f.mCalled = false;
472                            f.onDestroy();
473                            if (!f.mCalled) {
474                                throw new SuperNotCalledException("Fragment " + f
475                                        + " did not call through to super.onDestroy()");
476                            }
477                        }
478
479                        f.mCalled = false;
480                        f.onDetach();
481                        if (!f.mCalled) {
482                            throw new SuperNotCalledException("Fragment " + f
483                                    + " did not call through to super.onDetach()");
484                        }
485                        f.mActivity = null;
486                    }
487            }
488        }
489
490        f.mState = newState;
491    }
492
493    void moveToState(int newState, boolean always) {
494        moveToState(newState, 0, 0, always);
495    }
496
497    void moveToState(int newState, int transit, int transitStyle, boolean always) {
498        if (mActivity == null && newState != Fragment.INITIALIZING) {
499            throw new IllegalStateException("No activity");
500        }
501
502        if (!always && mCurState == newState) {
503            return;
504        }
505
506        mCurState = newState;
507        if (mFragments != null) {
508            for (int i=0; i<mFragments.size(); i++) {
509                Fragment f = mFragments.get(i);
510                moveToState(f, newState, transit, transitStyle);
511            }
512        }
513    }
514
515    public void addFragment(Fragment fragment, boolean moveToStateNow) {
516        if (mFragments == null) {
517            mFragments = new ArrayList<Fragment>();
518        }
519        mFragments.add(fragment);
520        if (moveToStateNow) {
521            moveToState(fragment, mCurState, 0, 0);
522        }
523    }
524
525    public void removeFragment(Fragment fragment, int transition, int transitionStyle) {
526        mFragments.remove(fragment);
527        moveToState(fragment, Fragment.INITIALIZING, transition, transitionStyle);
528    }
529
530    public Fragment findFragmentById(int id) {
531        if (mFragments != null) {
532            for (int i=mFragments.size()-1; i>=0; i--) {
533                Fragment f = mFragments.get(i);
534                if (f.mFragmentId == id) {
535                    return f;
536                }
537            }
538        }
539        return null;
540    }
541
542    public Fragment findFragmentByTag(String tag) {
543        if (mFragments != null && tag != null) {
544            for (int i=mFragments.size()-1; i>=0; i--) {
545                Fragment f = mFragments.get(i);
546                if (tag.equals(f.mTag)) {
547                    return f;
548                }
549            }
550        }
551        return null;
552    }
553
554    public void addBackStackState(BackStackEntry state) {
555        if (mBackStack == null) {
556            mBackStack = new ArrayList<BackStackEntry>();
557        }
558        mBackStack.add(state);
559    }
560
561    public boolean popBackStackState(Handler handler, String name) {
562        if (mBackStack == null) {
563            return false;
564        }
565        if (name == null) {
566            int last = mBackStack.size()-1;
567            if (last < 0) {
568                return false;
569            }
570            final BackStackEntry bss = mBackStack.remove(last);
571            handler.post(new Runnable() {
572                public void run() {
573                    bss.popFromBackStack();
574                    moveToState(mCurState, reverseTransit(bss.getTransition()),
575                            bss.getTransitionStyle(), true);
576                }
577            });
578        } else {
579            int index = mBackStack.size()-1;
580            while (index >= 0) {
581                BackStackEntry bss = mBackStack.get(index);
582                if (name.equals(bss.getName())) {
583                    break;
584                }
585            }
586            if (index < 0 || index == mBackStack.size()-1) {
587                return false;
588            }
589            final ArrayList<BackStackEntry> states
590                    = new ArrayList<BackStackEntry>();
591            for (int i=mBackStack.size()-1; i>index; i--) {
592                states.add(mBackStack.remove(i));
593            }
594            handler.post(new Runnable() {
595                public void run() {
596                    for (int i=0; i<states.size(); i++) {
597                        states.get(i).popFromBackStack();
598                    }
599                    moveToState(mCurState, true);
600                }
601            });
602        }
603        return true;
604    }
605
606    ArrayList<Fragment> retainNonConfig() {
607        ArrayList<Fragment> fragments = null;
608        if (mFragments != null) {
609            for (int i=0; i<mFragments.size(); i++) {
610                Fragment f = mFragments.get(i);
611                if (f.mBackStackNesting <= 0 && f.mRetainInstance && f.mTag != null) {
612                    if (fragments == null) {
613                        fragments = new ArrayList<Fragment>();
614                    }
615                    fragments.add(f);
616                    f.mRetaining = true;
617                }
618            }
619        }
620        return fragments;
621    }
622
623    void saveFragmentViewState(Fragment f) {
624        if (f.mSavedViewState != null) {
625            return;
626        }
627        if (mStateArray == null) {
628            mStateArray = new SparseArray<Parcelable>();
629        }
630        f.mView.saveHierarchyState(mStateArray);
631        if (mStateArray.size() > 0) {
632            f.mSavedViewState = mStateArray;
633            mStateArray = null;
634        }
635    }
636
637    FragmentState saveFragment(Fragment f) {
638        if (mSavedFragments != null) {
639            FragmentState fs = mSavedFragments.get(f);
640            if (fs != null) {
641                return fs;
642            }
643        } else {
644            mSavedFragments = new HashMap<Fragment, FragmentState>();
645        }
646
647        f.mSavedStateSeq = mSaveStateSeq;
648        f.mSavedStateId = ++mCurSaveId;
649
650        FragmentState fs = new FragmentState(f);
651        mSavedFragments.put(f, fs);
652
653        if (mStateBundle == null) {
654            mStateBundle = new Bundle();
655        }
656        f.onSaveInstanceState(mStateBundle);
657        if (!mStateBundle.isEmpty()) {
658            fs.mSavedFragmentState = mStateBundle;
659            mStateBundle = null;
660        }
661
662        if (f.mView != null) {
663            saveFragmentViewState(f);
664            if (f.mSavedViewState != null) {
665                if (fs.mSavedFragmentState == null) {
666                    fs.mSavedFragmentState = new Bundle();
667                }
668                fs.mSavedFragmentState.putSparseParcelableArray(
669                        FragmentState.VIEW_STATE_TAG, f.mSavedViewState);
670            }
671        }
672
673        return fs;
674    }
675
676    Parcelable saveAllState() {
677        mSavedFragments = null;
678        mSaveStateSeq++;
679
680        if (mFragments == null) {
681            return null;
682        }
683
684        int[] added = null;
685        BackStackState[] backStack = null;
686
687        // First collect all active fragments.
688        int N = mFragments.size();
689        if (N > 0) {
690            added = new int[N];
691            for (int i=0; i<N; i++) {
692                added[i] = saveFragment(mFragments.get(i)).mSavedStateId;
693            }
694        }
695
696        // Now save back stack.
697        if (mBackStack != null) {
698            N = mBackStack.size();
699            if (N > 0) {
700                backStack = new BackStackState[N];
701                for (int i=0; i<N; i++) {
702                    backStack[i] = new BackStackState(this, mBackStack.get(i));
703                }
704            }
705        }
706
707        if (mSavedFragments == null) {
708            return null;
709        }
710        N = mSavedFragments.size();
711        if (N <= 0) {
712            return null;
713        }
714
715        FragmentManagerState fms = new FragmentManagerState();
716        fms.mFragments = new FragmentState[N];
717        int i = 0;
718        for (FragmentState fs : mSavedFragments.values()) {
719            fms.mFragments[i] = fs;
720            i++;
721        }
722        fms.mAdded = added;
723        fms.mBackStack = backStack;
724        return fms;
725    }
726
727    void restoreAllState(Parcelable state, ArrayList<Fragment> nonConfig) {
728        // If there is no saved state at all, then there can not be
729        // any nonConfig fragments either, so that is that.
730        if (state == null) return;
731        FragmentManagerState fms = (FragmentManagerState)state;
732        if (fms.mFragments == null) return;
733
734        // First build our lookup table of all known Fragment objects.
735        mRestoredFragments = new SparseArray<FragmentState>();
736        for (int i=0; i<fms.mFragments.length; i++) {
737            FragmentState fs = fms.mFragments[i];
738            mRestoredFragments.put(fs.mSavedStateId, fs);
739        }
740
741        // Stick any non-config instances we are retaining directly
742        // into the lookup table, so we don't try to instantiate them again.
743        if (nonConfig != null) {
744            for (int i=0; i<nonConfig.size(); i++) {
745                Fragment f = nonConfig.get(i);
746                FragmentState fs = mRestoredFragments.get(f.mSavedStateId);
747                fs.mInstance = f;
748                f.mSavedViewState = null;
749                if (fs.mSavedFragmentState != null) {
750                    f.mSavedViewState = fs.mSavedFragmentState.getSparseParcelableArray(
751                            FragmentState.VIEW_STATE_TAG);
752                }
753                addFragment(f, false);
754            }
755        }
756
757        // Now build our data structures from the saved state, instantiating
758        // the fragment objects as needed.
759        if (fms.mAdded != null) {
760            if (mFragments == null) {
761                mFragments = new ArrayList<Fragment>(fms.mAdded.length);
762            }
763            for (int i=0; i<fms.mAdded.length; i++) {
764                FragmentState fs = mRestoredFragments.get(fms.mAdded[i]);
765                Fragment f = fs.instantiate(mActivity);
766                // This will return null if this is a layout fragment,
767                // since the instance for such a fragment will be created
768                // later during layout inflation.
769                if (f != null) {
770                    mFragments.add(f);
771                }
772            }
773        }
774        if (fms.mBackStack != null) {
775            mBackStack = new ArrayList<BackStackEntry>(fms.mBackStack.length);
776            for (int i=0; i<fms.mBackStack.length; i++) {
777                BackStackEntry bse = fms.mBackStack[i].instantiate(this);
778                mBackStack.add(bse);
779            }
780        }
781    }
782
783    public void attachActivity(Activity activity) {
784        if (mActivity != null) throw new IllegalStateException();
785        mActivity = activity;
786    }
787
788    public void dispatchCreate() {
789        moveToState(Fragment.CREATED, false);
790    }
791
792    public void dispatchStart() {
793        moveToState(Fragment.STARTED, false);
794    }
795
796    public void dispatchResume() {
797        moveToState(Fragment.RESUMED, false);
798    }
799
800    public void dispatchPause() {
801        moveToState(Fragment.STARTED, false);
802    }
803
804    public void dispatchStop() {
805        moveToState(Fragment.CREATED, false);
806    }
807
808    public void dispatchDestroy() {
809        moveToState(Fragment.INITIALIZING, false);
810        mActivity = null;
811    }
812
813    public static int reverseTransit(int transit) {
814        int rev = 0;
815        switch (transit) {
816            case FragmentTransaction.TRANSIT_ENTER:
817                rev = FragmentTransaction.TRANSIT_EXIT;
818                break;
819            case FragmentTransaction.TRANSIT_EXIT:
820                rev = FragmentTransaction.TRANSIT_ENTER;
821                break;
822            case FragmentTransaction.TRANSIT_SHOW:
823                rev = FragmentTransaction.TRANSIT_HIDE;
824                break;
825            case FragmentTransaction.TRANSIT_HIDE:
826                rev = FragmentTransaction.TRANSIT_SHOW;
827                break;
828            case FragmentTransaction.TRANSIT_ACTIVITY_OPEN:
829                rev = FragmentTransaction.TRANSIT_ACTIVITY_CLOSE;
830                break;
831            case FragmentTransaction.TRANSIT_ACTIVITY_CLOSE:
832                rev = FragmentTransaction.TRANSIT_ACTIVITY_OPEN;
833                break;
834            case FragmentTransaction.TRANSIT_TASK_OPEN:
835                rev = FragmentTransaction.TRANSIT_TASK_CLOSE;
836                break;
837            case FragmentTransaction.TRANSIT_TASK_CLOSE:
838                rev = FragmentTransaction.TRANSIT_TASK_OPEN;
839                break;
840            case FragmentTransaction.TRANSIT_TASK_TO_FRONT:
841                rev = FragmentTransaction.TRANSIT_TASK_TO_BACK;
842                break;
843            case FragmentTransaction.TRANSIT_TASK_TO_BACK:
844                rev = FragmentTransaction.TRANSIT_TASK_TO_FRONT;
845                break;
846            case FragmentTransaction.TRANSIT_WALLPAPER_OPEN:
847                rev = FragmentTransaction.TRANSIT_WALLPAPER_CLOSE;
848                break;
849            case FragmentTransaction.TRANSIT_WALLPAPER_CLOSE:
850                rev = FragmentTransaction.TRANSIT_WALLPAPER_OPEN;
851                break;
852            case FragmentTransaction.TRANSIT_WALLPAPER_INTRA_OPEN:
853                rev = FragmentTransaction.TRANSIT_WALLPAPER_INTRA_CLOSE;
854                break;
855            case FragmentTransaction.TRANSIT_WALLPAPER_INTRA_CLOSE:
856                rev = FragmentTransaction.TRANSIT_WALLPAPER_INTRA_OPEN;
857                break;
858        }
859        return rev;
860
861    }
862
863    public static int transitToStyleIndex(int transit, boolean enter) {
864        int animAttr = -1;
865        switch (transit) {
866            case FragmentTransaction.TRANSIT_ENTER:
867                animAttr = com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation;
868                break;
869            case FragmentTransaction.TRANSIT_EXIT:
870                animAttr = com.android.internal.R.styleable.WindowAnimation_windowExitAnimation;
871                break;
872            case FragmentTransaction.TRANSIT_SHOW:
873                animAttr = com.android.internal.R.styleable.WindowAnimation_windowShowAnimation;
874                break;
875            case FragmentTransaction.TRANSIT_HIDE:
876                animAttr = com.android.internal.R.styleable.WindowAnimation_windowHideAnimation;
877                break;
878            case FragmentTransaction.TRANSIT_ACTIVITY_OPEN:
879                animAttr = enter
880                        ? com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation
881                        : com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation;
882                break;
883            case FragmentTransaction.TRANSIT_ACTIVITY_CLOSE:
884                animAttr = enter
885                        ? com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation
886                        : com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation;
887                break;
888            case FragmentTransaction.TRANSIT_TASK_OPEN:
889                animAttr = enter
890                        ? com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation
891                        : com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation;
892                break;
893            case FragmentTransaction.TRANSIT_TASK_CLOSE:
894                animAttr = enter
895                        ? com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation
896                        : com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation;
897                break;
898            case FragmentTransaction.TRANSIT_TASK_TO_FRONT:
899                animAttr = enter
900                        ? com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation
901                        : com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation;
902                break;
903            case FragmentTransaction.TRANSIT_TASK_TO_BACK:
904                animAttr = enter
905                        ? com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation
906                        : com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation;
907                break;
908            case FragmentTransaction.TRANSIT_WALLPAPER_OPEN:
909                animAttr = enter
910                        ? com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation
911                        : com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
912                break;
913            case FragmentTransaction.TRANSIT_WALLPAPER_CLOSE:
914                animAttr = enter
915                        ? com.android.internal.R.styleable.WindowAnimation_wallpaperCloseEnterAnimation
916                        : com.android.internal.R.styleable.WindowAnimation_wallpaperCloseExitAnimation;
917                break;
918            case FragmentTransaction.TRANSIT_WALLPAPER_INTRA_OPEN:
919                animAttr = enter
920                        ? com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation
921                        : com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
922                break;
923            case FragmentTransaction.TRANSIT_WALLPAPER_INTRA_CLOSE:
924                animAttr = enter
925                        ? com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation
926                        : com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation;
927                break;
928        }
929        return animAttr;
930    }
931}
932