Project: cow
Code Examples
/*
 * Copyright (C) 2011 The Android Open Source Project 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 */
 
package android.support.v4.app; 
 
import android.content.Context; 
import android.content.res.Configuration; 
import android.os.Bundle; 
import android.os.Handler; 
import android.os.Looper; 
import android.os.Parcel; 
import android.os.Parcelable; 
import android.support.v4.util.DebugUtils; 
import android.support.v4.util.LogWriter; 
import android.util.Log; 
import android.util.SparseArray; 
import android.view.animation.AccelerateInterpolator; 
import android.view.animation.AlphaAnimation; 
import android.view.animation.Animation; 
import android.view.animation.AnimationSet; 
import android.view.animation.AnimationUtils; 
import android.view.animation.DecelerateInterpolator; 
import android.view.animation.Interpolator; 
import android.view.animation.ScaleAnimation; 
import android.view.animation.Animation.AnimationListener; 
import android.view.View; 
import android.view.ViewGroup; 
 
import java.io.FileDescriptor; 
import java.io.PrintWriter; 
import java.util.ArrayList; 
import java.util.Arrays; 
 
import com.actionbarsherlock.view.Menu; 
import com.actionbarsherlock.view.MenuInflater; 
import com.actionbarsherlock.view.MenuItem; 
 
/**
 * Static library support version of the framework's {@link android.app.FragmentManager}. 
 * Used to write apps that run on platforms prior to Android 3.0.  When running 
 * on Android 3.0 or above, this implementation is still used; it does not try 
 * to switch to the framework's implementation.  See the framework SDK 
 * documentation for a class overview. 
 * 
 * <p>Your activity must derive from {@link FragmentActivity} to use this. 
 */
 
public abstract class FragmentManager { 
    /**
     * Representation of an entry on the fragment back stack, as created 
     * with {@link FragmentTransaction#addToBackStack(String) 
     * FragmentTransaction.addToBackStack()}.  Entries can later be 
     * retrieved with {@link FragmentManager#getBackStackEntryAt(int) 
     * FragmentManager.getBackStackEntry()}. 
     * 
     * <p>Note that you should never hold on to a BackStackEntry object; 
     * the identifier as returned by {@link #getId} is the only thing that 
     * will be persisted across activity instances. 
     */
 
    public interface BackStackEntry { 
        /**
         * Return the unique identifier for the entry.  This is the only 
         * representation of the entry that will persist across activity 
         * instances. 
         */
 
        public int getId(); 
 
        /**
         * Get the name that was supplied to 
         * {@link FragmentTransaction#addToBackStack(String) 
         * FragmentTransaction.addToBackStack(String)} when creating this entry. 
         */
 
        public String getName(); 
 
        /**
         * Return the full bread crumb title resource identifier for the entry, 
         * or 0 if it does not have one. 
         */
 
        public int getBreadCrumbTitleRes(); 
 
        /**
         * Return the short bread crumb title resource identifier for the entry, 
         * or 0 if it does not have one. 
         */
 
        public int getBreadCrumbShortTitleRes(); 
 
        /**
         * Return the full bread crumb title for the entry, or null if it 
         * does not have one. 
         */
 
        public CharSequence getBreadCrumbTitle(); 
 
        /**
         * Return the short bread crumb title for the entry, or null if it 
         * does not have one. 
         */
 
        public CharSequence getBreadCrumbShortTitle(); 
    } 
 
    /**
     * Interface to watch for changes to the back stack. 
     */
 
    public interface OnBackStackChangedListener { 
        /**
         * Called whenever the contents of the back stack change. 
         */
 
        public void onBackStackChanged(); 
    } 
 
    /**
     * Start a series of edit operations on the Fragments associated with 
     * this FragmentManager. 
     * 
     * <p>Note: A fragment transaction can only be created/committed prior 
     * to an activity saving its state.  If you try to commit a transaction 
     * after {@link FragmentActivity#onSaveInstanceState FragmentActivity.onSaveInstanceState()} 
     * (and prior to a following {@link FragmentActivity#onStart FragmentActivity.onStart} 
     * or {@link FragmentActivity#onResume FragmentActivity.onResume()}, you will get an error. 
     * This is because the framework takes care of saving your current fragments 
     * in the state, and if changes are made after the state is saved then they 
     * will be lost.</p> 
     */
 
    public abstract FragmentTransaction beginTransaction(); 
 
    /** @hide -- remove once prebuilts are in. */ 
    @Deprecated 
    public FragmentTransaction openTransaction() { 
        return beginTransaction(); 
    } 
 
    /**
     * After a {@link FragmentTransaction} is committed with 
     * {@link FragmentTransaction#commit FragmentTransaction.commit()}, it 
     * is scheduled to be executed asynchronously on the process's main thread. 
     * If you want to immediately executing any such pending operations, you 
     * can call this function (only from the main thread) to do so.  Note that 
     * all callbacks and other related behavior will be done from within this 
     * call, so be careful about where this is called from. 
     * 
     * @return Returns true if there were any pending transactions to be 
     * executed. 
     */
 
    public abstract boolean executePendingTransactions(); 
 
    /**
     * Finds a fragment that was identified by the given id either when inflated 
     * from XML or as the container ID when added in a transaction.  This first 
     * searches through fragments that are currently added to the manager's 
     * activity; if no such fragment is found, then all fragments currently 
     * on the back stack associated with this ID are searched. 
     * @return The fragment if found or null otherwise. 
     */
 
    public abstract Fragment findFragmentById(int id); 
 
    /**
     * Finds a fragment that was identified by the given tag either when inflated 
     * from XML or as supplied when added in a transaction.  This first 
     * searches through fragments that are currently added to the manager's 
     * activity; if no such fragment is found, then all fragments currently 
     * on the back stack are searched. 
     * @return The fragment if found or null otherwise. 
     */
 
    public abstract Fragment findFragmentByTag(String tag); 
 
    /**
     * Flag for {@link #popBackStack(String, int)} 
     * and {@link #popBackStack(int, int)}: If set, and the name or ID of 
     * a back stack entry has been supplied, then all matching entries will 
     * be consumed until one that doesn't match is found or the bottom of 
     * the stack is reached.  Otherwise, all entries up to but not including that entry 
     * will be removed. 
     */
 
    public static final int POP_BACK_STACK_INCLUSIVE = 1<<0
 
    /**
     * Pop the top state off the back stack.  Returns true if there was one 
     * to pop, else false.  This function is asynchronous -- it enqueues the 
     * request to pop, but the action will not be performed until the application 
     * returns to its event loop. 
     */
 
    public abstract void popBackStack(); 
 
    /**
     * Like {@link #popBackStack()}, but performs the operation immediately 
     * inside of the call.  This is like calling {@link #executePendingTransactions()} 
     * afterwards. 
     * @return Returns true if there was something popped, else false. 
     */
 
    public abstract boolean popBackStackImmediate(); 
 
    /**
     * Pop the last fragment transition from the manager's fragment 
     * back stack.  If there is nothing to pop, false is returned. 
     * This function is asynchronous -- it enqueues the 
     * request to pop, but the action will not be performed until the application 
     * returns to its event loop. 
     * 
     * @param name If non-null, this is the name of a previous back state 
     * to look for; if found, all states up to that state will be popped.  The 
     * {@link #POP_BACK_STACK_INCLUSIVE} flag can be used to control whether 
     * the named state itself is popped. If null, only the top state is popped. 
     * @param flags Either 0 or {@link #POP_BACK_STACK_INCLUSIVE}. 
     */
 
    public abstract void popBackStack(String name, int flags); 
 
    /**
     * Like {@link #popBackStack(String, int)}, but performs the operation immediately 
     * inside of the call.  This is like calling {@link #executePendingTransactions()} 
     * afterwards. 
     * @return Returns true if there was something popped, else false. 
     */
 
    public abstract boolean popBackStackImmediate(String name, int flags); 
 
    /**
     * Pop all back stack states up to the one with the given identifier. 
     * This function is asynchronous -- it enqueues the 
     * request to pop, but the action will not be performed until the application 
     * returns to its event loop. 
     * 
     * @param id Identifier of the stated to be popped. If no identifier exists, 
     * false is returned. 
     * The identifier is the number returned by 
     * {@link FragmentTransaction#commit() FragmentTransaction.commit()}.  The 
     * {@link #POP_BACK_STACK_INCLUSIVE} flag can be used to control whether 
     * the named state itself is popped. 
     * @param flags Either 0 or {@link #POP_BACK_STACK_INCLUSIVE}. 
     */
 
    public abstract void popBackStack(int id, int flags); 
 
    /**
     * Like {@link #popBackStack(int, int)}, but performs the operation immediately 
     * inside of the call.  This is like calling {@link #executePendingTransactions()} 
     * afterwards. 
     * @return Returns true if there was something popped, else false. 
     */
 
    public abstract boolean popBackStackImmediate(int id, int flags); 
 
    /**
     * Return the number of entries currently in the back stack. 
     */
 
    public abstract int getBackStackEntryCount(); 
 
    /**
     * Return the BackStackEntry at index <var>index</var> in the back stack; 
     * entries start index 0 being the bottom of the stack. 
     */
 
    public abstract BackStackEntry getBackStackEntryAt(int index); 
 
    /**
     * Add a new listener for changes to the fragment back stack. 
     */
 
    public abstract void addOnBackStackChangedListener(OnBackStackChangedListener listener); 
 
    /**
     * Remove a listener that was previously added with 
     * {@link #addOnBackStackChangedListener(OnBackStackChangedListener)}. 
     */
 
    public abstract void removeOnBackStackChangedListener(OnBackStackChangedListener listener); 
 
    /**
     * Put a reference to a fragment in a Bundle.  This Bundle can be 
     * persisted as saved state, and when later restoring 
     * {@link #getFragment(Bundle, String)} will return the current 
     * instance of the same fragment. 
     * 
     * @param bundle The bundle in which to put the fragment reference. 
     * @param key The name of the entry in the bundle. 
     * @param fragment The Fragment whose reference is to be stored. 
     */
 
    public abstract void putFragment(Bundle bundle, String key, Fragment fragment); 
 
    /**
     * Retrieve the current Fragment instance for a reference previously 
     * placed with {@link #putFragment(Bundle, String, Fragment)}. 
     * 
     * @param bundle The bundle from which to retrieve the fragment reference. 
     * @param key The name of the entry in the bundle. 
     * @return Returns the current Fragment instance that is associated with 
     * the given reference. 
     */
 
    public abstract Fragment getFragment(Bundle bundle, String key); 
 
    /**
     * Save the current instance state of the given Fragment.  This can be 
     * used later when creating a new instance of the Fragment and adding 
     * it to the fragment manager, to have it create itself to match the 
     * current state returned here.  Note that there are limits on how 
     * this can be used: 
     * 
     * <ul> 
     * <li>The Fragment must currently be attached to the FragmentManager. 
     * <li>A new Fragment created using this saved state must be the same class 
     * type as the Fragment it was created from. 
     * <li>The saved state can not contain dependencies on other fragments -- 
     * that is it can't use {@link #putFragment(Bundle, String, Fragment)} to 
     * store a fragment reference because that reference may not be valid when 
     * this saved state is later used.  Likewise the Fragment's target and 
     * result code are not included in this state. 
     * </ul> 
     * 
     * @param f The Fragment whose state is to be saved. 
     * @return The generated state.  This will be null if there was no 
     * interesting state created by the fragment. 
     */
 
    public abstract Fragment.SavedState saveFragmentInstanceState(Fragment f); 
 
    /**
     * Print the FragmentManager's state into the given stream. 
     * 
     * @param prefix Text to print at the front of each line. 
     * @param fd The raw file descriptor that the dump is being sent to. 
     * @param writer A PrintWriter to which the dump is to be set. 
     * @param args Additional arguments to the dump request. 
     */
 
    public abstract void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args); 
 
    /**
     * Control whether the framework's internal fragment manager debugging 
     * logs are turned on.  If enabled, you will see output in logcat as 
     * the framework performs fragment operations. 
     */
 
    public static void enableDebugLogging(boolean enabled) { 
        FragmentManagerImpl.DEBUG = enabled; 
    } 
 
final class FragmentManagerState implements Parcelable { 
    FragmentState[] mActive; 
    int[] mAdded; 
    BackStackState[] mBackStack; 
 
    public FragmentManagerState() { 
    } 
 
    public FragmentManagerState(Parcel in) { 
        mActive = in.createTypedArray(FragmentState.CREATOR); 
        mAdded = in.createIntArray(); 
        mBackStack = in.createTypedArray(BackStackState.CREATOR); 
    } 
 
    public int describeContents() { 
        return 0
    } 
 
    public void writeToParcel(Parcel dest, int flags) { 
        dest.writeTypedArray(mActive, flags); 
        dest.writeIntArray(mAdded); 
        dest.writeTypedArray(mBackStack, flags); 
    } 
 
    public static final Parcelable.Creator<FragmentManagerState> CREATOR 
            = new Parcelable.Creator<FragmentManagerState>() { 
        public FragmentManagerState createFromParcel(Parcel in) { 
            return new FragmentManagerState(in); 
        } 
 
        public FragmentManagerState[] newArray(int size) { 
            return new FragmentManagerState[size]; 
        } 
    }; 
 
/**
 * Container for fragments associated with an activity. 
 */
 
final class FragmentManagerImpl extends FragmentManager { 
    static boolean DEBUG = false
    static final String TAG = "FragmentManager"
 
    static final boolean HONEYCOMB = android.os.Build.VERSION.SDK_INT >= 11
 
    static final String TARGET_REQUEST_CODE_STATE_TAG = "android:target_req_state"
    static final String TARGET_STATE_TAG = "android:target_state"
    static final String VIEW_STATE_TAG = "android:view_state"
    static final String USER_VISIBLE_HINT_TAG = "android:user_visible_hint"
 
    ArrayList<Runnable> mPendingActions; 
    Runnable[] mTmpActions; 
    boolean mExecutingActions; 
 
    ArrayList<Fragment> mActive; 
    ArrayList<Fragment> mAdded; 
    ArrayList<Integer> mAvailIndices; 
    ArrayList<BackStackRecord> mBackStack; 
    ArrayList<Fragment> mCreatedMenus; 
 
    // Must be accessed while locked. 
    ArrayList<BackStackRecord> mBackStackIndices; 
    ArrayList<Integer> mAvailBackStackIndices; 
 
    ArrayList<OnBackStackChangedListener> mBackStackChangeListeners; 
 
    int mCurState = Fragment.INITIALIZING; 
    FragmentActivity mActivity; 
 
    boolean mNeedMenuInvalidate; 
    boolean mStateSaved; 
    boolean mDestroyed; 
    String mNoTransactionsBecause; 
    boolean mHavePendingDeferredStart; 
 
    // Temporary vars for state save and restore. 
    Bundle mStateBundle = null
    SparseArray<Parcelable> mStateArray = null
 
    Runnable mExecCommit = new Runnable() { 
        @Override 
        public void run() { 
            execPendingActions(); 
        } 
    }; 
 
    @Override 
    public FragmentTransaction beginTransaction() { 
        return new BackStackRecord(this); 
    } 
 
    @Override 
    public boolean executePendingTransactions() { 
        return execPendingActions(); 
    } 
 
    @Override 
    public void popBackStack() { 
        enqueueAction(new Runnable() { 
            @Override public void run() { 
                popBackStackState(mActivity.mHandler, null, -10); 
            } 
        }, false); 
    } 
 
    @Override 
    public boolean popBackStackImmediate() { 
        checkStateLoss(); 
        executePendingTransactions(); 
        return popBackStackState(mActivity.mHandler, null, -10); 
    } 
 
    @Override 
    public void popBackStack(final String name, final int flags) { 
        enqueueAction(new Runnable() { 
            @Override public void run() { 
                popBackStackState(mActivity.mHandler, name, -1, flags); 
            } 
        }, false); 
    } 
 
    @Override 
    public boolean popBackStackImmediate(String name, int flags) { 
        checkStateLoss(); 
        executePendingTransactions(); 
        return popBackStackState(mActivity.mHandler, name, -1, flags); 
    } 
 
    @Override 
    public void popBackStack(final int id, final int flags) { 
        if (id < 0) { 
            throw new IllegalArgumentException("Bad id: " + id); 
        } 
        enqueueAction(new Runnable() { 
            @Override public void run() { 
                popBackStackState(mActivity.mHandler, null, id, flags); 
            } 
        }, false); 
    } 
 
    @Override 
    public boolean popBackStackImmediate(int id, int flags) { 
        checkStateLoss(); 
        executePendingTransactions(); 
        if (id < 0) { 
            throw new IllegalArgumentException("Bad id: " + id); 
        } 
        return popBackStackState(mActivity.mHandler, null, id, flags); 
    } 
 
    @Override 
    public int getBackStackEntryCount() { 
        return mBackStack != null ? mBackStack.size() : 0
    } 
 
    @Override 
    public BackStackEntry getBackStackEntryAt(int index) { 
        return mBackStack.get(index); 
    } 
 
    @Override 
    public void addOnBackStackChangedListener(OnBackStackChangedListener listener) { 
        if (mBackStackChangeListeners == null) { 
            mBackStackChangeListeners = new ArrayList<OnBackStackChangedListener>(); 
        } 
        mBackStackChangeListeners.add(listener); 
    } 
 
    @Override 
    public void removeOnBackStackChangedListener(OnBackStackChangedListener listener) { 
        if (mBackStackChangeListeners != null) { 
            mBackStackChangeListeners.remove(listener); 
        } 
    } 
 
    @Override 
    public void putFragment(Bundle bundle, String key, Fragment fragment) { 
        if (fragment.mIndex < 0) { 
            throw new IllegalStateException("Fragment " + fragment 
                    + " is not currently in the FragmentManager"); 
        } 
        bundle.putInt(key, fragment.mIndex); 
    } 
 
    @Override 
    public Fragment getFragment(Bundle bundle, String key) { 
        int index = bundle.getInt(key, -1); 
        if (index == -1) { 
            return null
        } 
        if (index >= mActive.size()) { 
            throw new IllegalStateException("Fragement no longer exists for key " 
                    + key + ": index " + index); 
        } 
        Fragment f = mActive.get(index); 
        if (f == null) { 
            throw new IllegalStateException("Fragement no longer exists for key " 
                    + key + ": index " + index); 
        } 
        return f; 
    } 
 
    @Override 
    public Fragment.SavedState saveFragmentInstanceState(Fragment fragment) { 
        if (fragment.mIndex < 0) { 
            throw new IllegalStateException("Fragment " + fragment 
                    + " is not currently in the FragmentManager"); 
        } 
        if (fragment.mState > Fragment.INITIALIZING) { 
            Bundle result = saveFragmentBasicState(fragment); 
            return result != null ? new Fragment.SavedState(result) : null
        } 
        return null
    } 
 
    @Override 
    public String toString() { 
        StringBuilder sb = new StringBuilder(128); 
        sb.append("FragmentManager{"); 
        sb.append(Integer.toHexString(System.identityHashCode(this))); 
        sb.append(" in "); 
        DebugUtils.buildShortClassTag(mActivity, sb); 
        sb.append("}}"); 
        return sb.toString(); 
    } 
 
    @Override 
    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { 
        String innerPrefix = prefix + "    "
 
        int N; 
        if (mActive != null) { 
            N = mActive.size(); 
            if (N > 0) { 
                writer.print(prefix); writer.print("Active Fragments in "); 
                        writer.print(Integer.toHexString(System.identityHashCode(this))); 
                        writer.println(":"); 
                for (int i=0; i<N; i++) { 
                    Fragment f = mActive.get(i); 
                    writer.print(prefix); writer.print("  #"); writer.print(i); 
                            writer.print(": "); writer.println(f); 
                    if (f != null) { 
                        f.dump(innerPrefix, fd, writer, args); 
                    } 
                } 
            } 
        } 
 
        if (mAdded != null) { 
            N = mAdded.size(); 
            if (N > 0) { 
                writer.print(prefix); writer.println("Added Fragments:"); 
                for (int i=0; i<N; i++) { 
                    Fragment f = mAdded.get(i); 
                    writer.print(prefix); writer.print("  #"); writer.print(i); 
                            writer.print(": "); writer.println(f.toString()); 
                } 
            } 
        } 
 
        if (mCreatedMenus != null) { 
            N = mCreatedMenus.size(); 
            if (N > 0) { 
                writer.print(prefix); writer.println("Fragments Created Menus:"); 
                for (int i=0; i<N; i++) { 
                    Fragment f = mCreatedMenus.get(i); 
                    writer.print(prefix); writer.print("  #"); writer.print(i); 
                            writer.print(": "); writer.println(f.toString()); 
                } 
            } 
        } 
 
        if (mBackStack != null) { 
            N = mBackStack.size(); 
            if (N > 0) { 
                writer.print(prefix); writer.println("Back Stack:"); 
                for (int i=0; i<N; i++) { 
                    BackStackRecord bs = mBackStack.get(i); 
                    writer.print(prefix); writer.print("  #"); writer.print(i); 
                            writer.print(": "); writer.println(bs.toString()); 
                    bs.dump(innerPrefix, fd, writer, args); 
                } 
            } 
        } 
 
        synchronized (this) { 
            if (mBackStackIndices != null) { 
                N = mBackStackIndices.size(); 
                if (N > 0) { 
                    writer.print(prefix); writer.println("Back Stack Indices:"); 
                    for (int i=0; i<N; i++) { 
                        BackStackRecord bs = mBackStackIndices.get(i); 
                        writer.print(prefix); writer.print("  #"); writer.print(i); 
                                writer.print(": "); writer.println(bs); 
                    } 
                } 
            } 
 
            if (mAvailBackStackIndices != null && mAvailBackStackIndices.size() > 0) { 
                writer.print(prefix); writer.print("mAvailBackStackIndices: "); 
                        writer.println(Arrays.toString(mAvailBackStackIndices.toArray())); 
            } 
        } 
 
        if (mPendingActions != null) { 
            N = mPendingActions.size(); 
            if (N > 0) { 
                writer.print(prefix); writer.println("Pending Actions:"); 
                for (int i=0; i<N; i++) { 
                    Runnable r = mPendingActions.get(i); 
                    writer.print(prefix); writer.print("  #"); writer.print(i); 
                            writer.print(": "); writer.println(r); 
                } 
            } 
        } 
 
        writer.print(prefix); writer.println("FragmentManager misc state:"); 
        writer.print(prefix); writer.print("  mCurState="); writer.print(mCurState); 
                writer.print(" mStateSaved="); writer.print(mStateSaved); 
                writer.print(" mDestroyed="); writer.println(mDestroyed); 
        if (mNeedMenuInvalidate) { 
            writer.print(prefix); writer.print("  mNeedMenuInvalidate="); 
                    writer.println(mNeedMenuInvalidate); 
        } 
        if (mNoTransactionsBecause != null) { 
            writer.print(prefix); writer.print("  mNoTransactionsBecause="); 
                    writer.println(mNoTransactionsBecause); 
        } 
        if (mAvailIndices != null && mAvailIndices.size() > 0) { 
            writer.print(prefix); writer.print("  mAvailIndices: "); 
                    writer.println(Arrays.toString(mAvailIndices.toArray())); 
        } 
    } 
 
    static final Interpolator DECELERATE_QUINT = new DecelerateInterpolator(2.5f); 
    static final Interpolator DECELERATE_CUBIC = new DecelerateInterpolator(1.5f); 
    static final Interpolator ACCELERATE_QUINT = new AccelerateInterpolator(2.5f); 
    static final Interpolator ACCELERATE_CUBIC = new AccelerateInterpolator(1.5f); 
 
    static final int ANIM_DUR = 220
 
    static Animation makeOpenCloseAnimation(Context context, float startScale, 
            float endScale, float startAlpha, float endAlpha) { 
        AnimationSet set = new AnimationSet(false); 
        ScaleAnimation scale = new ScaleAnimation(startScale, endScale, startScale, endScale, 
                Animation.RELATIVE_TO_SELF, .5f, Animation.RELATIVE_TO_SELF, .5f); 
        scale.setInterpolator(DECELERATE_QUINT); 
        scale.setDuration(ANIM_DUR); 
        set.addAnimation(scale); 
        AlphaAnimation alpha = new AlphaAnimation(startAlpha, endAlpha); 
        alpha.setInterpolator(DECELERATE_CUBIC); 
        alpha.setDuration(ANIM_DUR); 
        set.addAnimation(alpha); 
        return set; 
    } 
 
    static Animation makeFadeAnimation(Context context, float start, float end) { 
        AlphaAnimation anim = new AlphaAnimation(start, end); 
        anim.setInterpolator(DECELERATE_CUBIC); 
        anim.setDuration(ANIM_DUR); 
        return anim; 
    } 
 
    Animation loadAnimation(Fragment fragment, int transit, boolean enter, 
            int transitionStyle) { 
        Animation animObj = fragment.onCreateAnimation(transit, enter, 
                fragment.mNextAnim); 
        if (animObj != null) { 
            return animObj; 
        } 
 
        if (fragment.mNextAnim != 0) { 
            Animation anim = AnimationUtils.loadAnimation(mActivity, fragment.mNextAnim); 
            if (anim != null) { 
                return anim; 
            } 
        } 
 
        if (transit == 0) { 
            return null
        } 
 
        int styleIndex = transitToStyleIndex(transit, enter); 
        if (styleIndex < 0) { 
            return null
        } 
 
        switch (styleIndex) { 
            case ANIM_STYLE_OPEN_ENTER: 
                return makeOpenCloseAnimation(mActivity, 1.125f1.0f01); 
            case ANIM_STYLE_OPEN_EXIT: 
                return makeOpenCloseAnimation(mActivity, 1.0f.975f10); 
            case ANIM_STYLE_CLOSE_ENTER: 
                return makeOpenCloseAnimation(mActivity, .975f1.0f01); 
            case ANIM_STYLE_CLOSE_EXIT: 
                return makeOpenCloseAnimation(mActivity, 1.0f1.075f10); 
            case ANIM_STYLE_FADE_ENTER: 
                return makeFadeAnimation(mActivity, 01); 
            case ANIM_STYLE_FADE_EXIT: 
                return makeFadeAnimation(mActivity, 10); 
        } 
 
        if (transitionStyle == 0 && mActivity.getWindow() != null) { 
            transitionStyle = mActivity.getWindow().getAttributes().windowAnimations; 
        } 
        if (transitionStyle == 0) { 
            return null
        } 
 
        //TypedArray attrs = mActivity.obtainStyledAttributes(transitionStyle, 
        //        com.android.internal.R.styleable.FragmentAnimation); 
        //int anim = attrs.getResourceId(styleIndex, 0); 
        //attrs.recycle(); 
 
        //if (anim == 0) { 
        //    return null; 
        //} 
 
        //return AnimatorInflater.loadAnimator(mActivity, anim); 
        return null
    } 
 
    public void performPendingDeferredStart(Fragment f) { 
        if (f.mDeferStart) { 
            if (mExecutingActions) { 
                // Wait until we're done executing our pending transactions 
                mHavePendingDeferredStart = true
                return
            } 
            f.mDeferStart = false
            moveToState(f, mCurState, 00); 
        } 
    } 
 
    void moveToState(Fragment f, int newState, int transit, int transitionStyle) { 
        // Fragments that are not currently added will sit in the onCreate() state. 
        if (!f.mAdded && newState > Fragment.CREATED) { 
            newState = Fragment.CREATED; 
        } 
        if (f.mRemoving && newState > f.mState) { 
            // While removing a fragment, we can't change it to a higher state. 
            newState = f.mState; 
        } 
        // Defer start if requested; don't allow it to move to STARTED or higher 
        // if it's not already started. 
        if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.STOPPED) { 
            newState = Fragment.STOPPED; 
        } 
        if (f.mState < newState) { 
            // For fragments that are created from a layout, when restoring from 
            // state we don't want to allow them to be created until they are 
            // being reloaded from the layout. 
            if (f.mFromLayout && !f.mInLayout) { 
                return
            } 
            if (f.mAnimatingAway != null) { 
                // The fragment is currently being animated...  but!  Now we 
                // want to move our state back up.  Give up on waiting for the 
                // animation, move to whatever the final state should be once 
                // the animation is done, and then we can proceed from there. 
                f.mAnimatingAway = null
                moveToState(f, f.mStateAfterAnimating, 00); 
            } 
            switch (f.mState) { 
                case Fragment.INITIALIZING: 
                    if (DEBUG) Log.v(TAG, "moveto CREATED: " + f); 
                    if (f.mSavedFragmentState != null) { 
                        f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray( 
                                FragmentManagerImpl.VIEW_STATE_TAG); 
                        f.mTarget = getFragment(f.mSavedFragmentState, 
                                FragmentManagerImpl.TARGET_STATE_TAG); 
                        if (f.mTarget != null) { 
                            f.mTargetRequestCode = f.mSavedFragmentState.getInt( 
                                    FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0); 
                        } 
                        f.mUserVisibleHint = f.mSavedFragmentState.getBoolean( 
                                FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true); 
                        if (!f.mUserVisibleHint) { 
                            f.mDeferStart = true
                            if (newState > Fragment.STOPPED) { 
                                newState = Fragment.STOPPED; 
                            } 
                        } 
                    } 
                    f.mActivity = mActivity; 
                    f.mFragmentManager = mActivity.mFragments; 
                    f.mCalled = false
                    f.onAttach(mActivity); 
                    if (!f.mCalled) { 
                        throw new SuperNotCalledException("Fragment " + f 
                                + " did not call through to super.onAttach()"); 
                    } 
                    mActivity.onAttachFragment(f); 
 
                    if (!f.mRetaining) { 
                        f.mCalled = false
                        f.onCreate(f.mSavedFragmentState); 
                        if (!f.mCalled) { 
                            throw new SuperNotCalledException("Fragment " + f 
                                    + " did not call through to super.onCreate()"); 
                        } 
                    } 
                    f.mRetaining = false
                    if (f.mFromLayout) { 
                        // For fragments that are part of the content view 
                        // layout, we need to instantiate the view immediately 
                        // and the inflater will take care of adding it. 
                        f.mView = f.onCreateView(f.getLayoutInflater(f.mSavedFragmentState), 
                                null, f.mSavedFragmentState); 
                        if (f.mView != null) { 
                            f.mInnerView = f.mView; 
                            f.mView = NoSaveStateFrameLayout.wrap(f.mView); 
                            if (f.mHidden) f.mView.setVisibility(View.GONE); 
                            f.onViewCreated(f.mView, f.mSavedFragmentState); 
                        } else { 
                            f.mInnerView = null
                        } 
                    } 
                case Fragment.CREATED: 
                    if (newState > Fragment.CREATED) { 
                        if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f); 
                        if (!f.mFromLayout) { 
                            ViewGroup container = null
                            if (f.mContainerId != 0) { 
                                container = (ViewGroup)mActivity.findViewById(f.mContainerId); 
                                if (container == null && !f.mRestored) { 
                                    throw new IllegalArgumentException("No view found for id 0x" 
                                            + Integer.toHexString(f.mContainerId) 
                                            + " for fragment " + f); 
                                } 
                            } 
                            f.mContainer = container; 
                            f.mView = f.onCreateView(f.getLayoutInflater(f.mSavedFragmentState), 
                                    container, f.mSavedFragmentState); 
                            if (f.mView != null) { 
                                f.mInnerView = f.mView; 
                                f.mView = NoSaveStateFrameLayout.wrap(f.mView); 
                                if (container != null) { 
                                    Animation anim = loadAnimation(f, transit, true
                                            transitionStyle); 
                                    if (anim != null) { 
                                        f.mView.startAnimation(anim); 
                                    } 
                                    container.addView(f.mView); 
                                } 
                                if (f.mHidden) f.mView.setVisibility(View.GONE); 
                                f.onViewCreated(f.mView, f.mSavedFragmentState); 
                            } else { 
                                f.mInnerView = null
                            } 
                        } 
 
                        f.mCalled = false
                        f.onActivityCreated(f.mSavedFragmentState); 
                        if (!f.mCalled) { 
                            throw new SuperNotCalledException("Fragment " + f 
                                    + " did not call through to super.onActivityCreated()"); 
                        } 
                        if (f.mView != null) { 
                            f.restoreViewState(); 
                        } 
                        f.mSavedFragmentState = null
                    } 
                case Fragment.ACTIVITY_CREATED: 
                case Fragment.STOPPED: 
                    if (newState > Fragment.STOPPED) { 
                        if (DEBUG) Log.v(TAG, "moveto STARTED: " + f); 
                        f.mCalled = false
                        f.performStart(); 
                        if (!f.mCalled) { 
                            throw new SuperNotCalledException("Fragment " + f 
                                    + " did not call through to super.onStart()"); 
                        } 
                    } 
                case Fragment.STARTED: 
                    if (newState > Fragment.STARTED) { 
                        if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f); 
                        f.mCalled = false
                        f.mResumed = true
                        f.onResume(); 
                        if (!f.mCalled) { 
                            throw new SuperNotCalledException("Fragment " + f 
                                    + " did not call through to super.onResume()"); 
                        } 
                        f.mSavedFragmentState = null
                        f.mSavedViewState = null
                    } 
            } 
        } else if (f.mState > newState) { 
            switch (f.mState) { 
                case Fragment.RESUMED: 
                    if (newState < Fragment.RESUMED) { 
                        if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f); 
                        f.mCalled = false
                        f.onPause(); 
                        if (!f.mCalled) { 
                            throw new SuperNotCalledException("Fragment " + f 
                                    + " did not call through to super.onPause()"); 
                        } 
                        f.mResumed = false
                    } 
                case Fragment.STARTED: 
                    if (newState < Fragment.STARTED) { 
                        if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f); 
                        f.mCalled = false
                        f.performStop(); 
                        if (!f.mCalled) { 
                            throw new SuperNotCalledException("Fragment " + f 
                                    + " did not call through to super.onStop()"); 
                        } 
                    } 
                case Fragment.STOPPED: 
                    if (newState < Fragment.STOPPED) { 
                        if (DEBUG) Log.v(TAG, "movefrom STOPPED: " + f); 
                        f.performReallyStop(); 
                    } 
                case Fragment.ACTIVITY_CREATED: 
                    if (newState < Fragment.ACTIVITY_CREATED) { 
                        if (DEBUG) Log.v(TAG, "movefrom ACTIVITY_CREATED: " + f); 
                        if (f.mView != null) { 
                            // Need to save the current view state if not 
                            // done already. 
                            if (!mActivity.isFinishing() && f.mSavedViewState == null) { 
                                saveFragmentViewState(f); 
                            } 
                        } 
                        f.mCalled = false
                        f.performDestroyView(); 
                        if (!f.mCalled) { 
                            throw new SuperNotCalledException("Fragment " + f 
                                    + " did not call through to super.onDestroyView()"); 
                        } 
                        if (f.mView != null && f.mContainer != null) { 
                            Animation anim = null
                            if (mCurState > Fragment.INITIALIZING && !mDestroyed) { 
                                anim = loadAnimation(f, transit, false
                                        transitionStyle); 
                            } 
                            if (anim != null) { 
                                final Fragment fragment = f; 
                                f.mAnimatingAway = f.mView; 
                                f.mStateAfterAnimating = newState; 
                                anim.setAnimationListener(new AnimationListener() { 
                                    @Override 
                                    public void onAnimationEnd(Animation animation) { 
                                        if (fragment.mAnimatingAway != null) { 
                                            fragment.mAnimatingAway = null
                                            moveToState(fragment, fragment.mStateAfterAnimating, 
                                                    00); 
                                        } 
                                    } 
                                    @Override 
                                    public void onAnimationRepeat(Animation animation) { 
                                    } 
                                    @Override 
                                    public void onAnimationStart(Animation animation) { 
                                    } 
                                }); 
                                f.mView.startAnimation(anim); 
                            } 
                            f.mContainer.removeView(f.mView); 
                        } 
                        f.mContainer = null
                        f.mView = null
                        f.mInnerView = null
                    } 
                case Fragment.CREATED: 
                    if (newState < Fragment.CREATED) { 
                        if (mDestroyed) { 
                            if (f.mAnimatingAway != null) { 
                                // The fragment's containing activity is 
                                // being destroyed, but this fragment is 
                                // currently animating away.  Stop the 
                                // animation right now -- it is not needed, 
                                // and we can't wait any more on destroying 
                                // the fragment. 
                                View v = f.mAnimatingAway; 
                                f.mAnimatingAway = null
                                v.clearAnimation(); 
                            } 
                        } 
                        if (f.mAnimatingAway != null) { 
                            // We are waiting for the fragment's view to finish 
                            // animating away.  Just make a note of the state 
                            // the fragment now should move to once the animation 
                            // is done. 
                            f.mStateAfterAnimating = newState; 
                            newState = Fragment.CREATED; 
                        } else { 
                            if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f); 
                            if (!f.mRetaining) { 
                                f.mCalled = false
                                f.onDestroy(); 
                                if (!f.mCalled) { 
                                    throw new SuperNotCalledException("Fragment " + f 
                                            + " did not call through to super.onDestroy()"); 
                                } 
                            } 
 
                            f.mCalled = false
                            f.onDetach(); 
                            if (!f.mCalled) { 
                                throw new SuperNotCalledException("Fragment " + f 
                                        + " did not call through to super.onDetach()"); 
                            } 
                            if (!f.mRetaining) { 
                                makeInactive(f); 
                            } else { 
                                f.mActivity = null
                                f.mFragmentManager = null
                            } 
                        } 
                    } 
            } 
        } 
 
        f.mState = newState; 
    } 
 
    void moveToState(Fragment f) { 
        moveToState(f, mCurState, 00); 
    } 
 
    void moveToState(int newState, boolean always) { 
        moveToState(newState, 00, always); 
    } 
 
    void moveToState(int newState, int transit, int transitStyle, boolean always) { 
        if (mActivity == null && newState != Fragment.INITIALIZING) { 
            throw new IllegalStateException("No activity"); 
        } 
 
        if (!always && mCurState == newState) { 
            return
        } 
 
        mCurState = newState; 
        if (mActive != null) { 
            boolean loadersRunning = false
            for (int i=0; i<mActive.size(); i++) { 
                Fragment f = mActive.get(i); 
                if (f != null) { 
                    moveToState(f, newState, transit, transitStyle); 
                    if (f.mLoaderManager != null) { 
                        loadersRunning |= f.mLoaderManager.hasRunningLoaders(); 
                    } 
                } 
            } 
 
            if (!loadersRunning) { 
                startPendingDeferredFragments(); 
            } 
 
            if (mNeedMenuInvalidate && mActivity != null && mCurState == Fragment.RESUMED) { 
                mActivity.supportInvalidateOptionsMenu(); 
                mNeedMenuInvalidate = false
            } 
        } 
    } 
 
    void startPendingDeferredFragments() { 
        if (mActive == nullreturn
 
        for (int i=0; i<mActive.size(); i++) { 
            Fragment f = mActive.get(i); 
            if (f != null) { 
                performPendingDeferredStart(f); 
            } 
        } 
    } 
 
    void makeActive(Fragment f) { 
        if (f.mIndex >= 0) { 
            return
        } 
 
        if (mAvailIndices == null || mAvailIndices.size() <= 0) { 
            if (mActive == null) { 
                mActive = new ArrayList<Fragment>(); 
            } 
            f.setIndex(mActive.size()); 
            mActive.add(f); 
 
        } else { 
            f.setIndex(mAvailIndices.remove(mAvailIndices.size()-1)); 
            mActive.set(f.mIndex, f); 
        } 
    } 
 
    void makeInactive(Fragment f) { 
        if (f.mIndex < 0) { 
            return
        } 
 
        if (DEBUG) Log.v(TAG, "Freeing fragment index " + f.mIndex); 
        mActive.set(f.mIndex, null); 
        if (mAvailIndices == null) { 
            mAvailIndices = new ArrayList<Integer>(); 
        } 
        mAvailIndices.add(f.mIndex); 
        mActivity.invalidateSupportFragmentIndex(f.mIndex); 
        f.initState(); 
    } 
 
    public void addFragment(Fragment fragment, boolean moveToStateNow) { 
        if (mAdded == null) { 
            mAdded = new ArrayList<Fragment>(); 
        } 
        if (DEBUG) Log.v(TAG, "add: " + fragment); 
        makeActive(fragment); 
        if (!fragment.mDetached) { 
            mAdded.add(fragment); 
            fragment.mAdded = true
            fragment.mRemoving = false
            if (fragment.mHasMenu && fragment.mMenuVisible) { 
                mNeedMenuInvalidate = true
            } 
            if (moveToStateNow) { 
                moveToState(fragment); 
            } 
        } 
    } 
 
    public void removeFragment(Fragment fragment, int transition, int transitionStyle) { 
        if (DEBUG) Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting); 
        final boolean inactive = !fragment.isInBackStack(); 
        if (!fragment.mDetached || inactive) { 
            mAdded.remove(fragment); 
            if (fragment.mHasMenu && fragment.mMenuVisible) { 
                mNeedMenuInvalidate = true
            } 
            fragment.mAdded = false
            fragment.mRemoving = true
            moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED, 
                    transition, transitionStyle); 
        } 
    } 
 
    public void hideFragment(Fragment fragment, int transition, int transitionStyle) { 
        if (DEBUG) Log.v(TAG, "hide: " + fragment); 
        if (!fragment.mHidden) { 
            fragment.mHidden = true
            if (fragment.mView != null) { 
                Animation anim = loadAnimation(fragment, transition, true
                        transitionStyle); 
                if (anim != null) { 
                    fragment.mView.startAnimation(anim); 
                } 
                fragment.mView.setVisibility(View.GONE); 
            } 
            if (fragment.mAdded && fragment.mHasMenu && fragment.mMenuVisible) { 
                mNeedMenuInvalidate = true
            } 
            fragment.onHiddenChanged(true); 
        } 
    } 
 
    public void showFragment(Fragment fragment, int transition, int transitionStyle) { 
        if (DEBUG) Log.v(TAG, "show: " + fragment); 
        if (fragment.mHidden) { 
            fragment.mHidden = false
            if (fragment.mView != null) { 
                Animation anim = loadAnimation(fragment, transition, true
                        transitionStyle); 
                if (anim != null) { 
                    fragment.mView.startAnimation(anim); 
                } 
                fragment.mView.setVisibility(View.VISIBLE); 
            } 
            if (fragment.mAdded && fragment.mHasMenu && fragment.mMenuVisible) { 
                mNeedMenuInvalidate = true
            } 
            fragment.onHiddenChanged(false); 
        } 
    } 
 
    public void detachFragment(Fragment fragment, int transition, int transitionStyle) { 
        if (DEBUG) Log.v(TAG, "detach: " + fragment); 
        if (!fragment.mDetached) { 
            fragment.mDetached = true
            if (fragment.mAdded) { 
                // We are not already in back stack, so need to remove the fragment. 
                mAdded.remove(fragment); 
                if (fragment.mHasMenu && fragment.mMenuVisible) { 
                    mNeedMenuInvalidate = true
                } 
                fragment.mAdded = false
                moveToState(fragment, Fragment.CREATED, transition, transitionStyle); 
            } 
        } 
    } 
 
    public void attachFragment(Fragment fragment, int transition, int transitionStyle) { 
        if (DEBUG) Log.v(TAG, "attach: " + fragment); 
        if (fragment.mDetached) { 
            fragment.mDetached = false
            if (!fragment.mAdded) { 
                mAdded.add(fragment); 
                fragment.mAdded = true
                if (fragment.mHasMenu && fragment.mMenuVisible) { 
                    mNeedMenuInvalidate = true
                } 
                moveToState(fragment, mCurState, transition, transitionStyle); 
            } 
        } 
    } 
 
    public Fragment findFragmentById(int id) { 
        if (mActive != null) { 
            // First look through added fragments. 
            for (int i=mAdded.size()-1; i>=0; i--) { 
                Fragment f = mAdded.get(i); 
                if (f != null && f.mFragmentId == id) { 
                    return f; 
                } 
            } 
            // Now for any known fragment. 
            for (int i=mActive.size()-1; i>=0; i--) { 
                Fragment f = mActive.get(i); 
                if (f != null && f.mFragmentId == id) { 
                    return f; 
                } 
            } 
        } 
        return null
    } 
 
    public Fragment findFragmentByTag(String tag) { 
        if (mActive != null && tag != null) { 
            // First look through added fragments. 
            for (int i=mAdded.size()-1; i>=0; i--) { 
                Fragment f = mAdded.get(i); 
                if (f != null && tag.equals(f.mTag)) { 
                    return f; 
                } 
            } 
            // Now for any known fragment. 
            for (int i=mActive.size()-1; i>=0; i--) { 
                Fragment f = mActive.get(i); 
                if (f != null && tag.equals(f.mTag)) { 
                    return f; 
                } 
            } 
        } 
        return null
    } 
 
    public Fragment findFragmentByWho(String who) { 
        if (mActive != null && who != null) { 
            for (int i=mActive.size()-1; i>=0; i--) { 
                Fragment f = mActive.get(i); 
                if (f != null && who.equals(f.mWho)) { 
                    return f; 
                } 
            } 
        } 
        return null
    } 
 
    private void checkStateLoss() { 
        if (mStateSaved) { 
            throw new IllegalStateException( 
                    "Can not perform this action after onSaveInstanceState"); 
        } 
        if (mNoTransactionsBecause != null) { 
            throw new IllegalStateException( 
                    "Can not perform this action inside of " + mNoTransactionsBecause); 
        } 
    } 
 
    public void enqueueAction(Runnable action, boolean allowStateLoss) { 
        if (!allowStateLoss) { 
            checkStateLoss(); 
        } 
        synchronized (this) { 
            if (mActivity == null) { 
                throw new IllegalStateException("Activity has been destroyed"); 
            } 
            if (mPendingActions == null) { 
                mPendingActions = new ArrayList<Runnable>(); 
            } 
            mPendingActions.add(action); 
            if (mPendingActions.size() == 1) { 
                mActivity.mHandler.removeCallbacks(mExecCommit); 
                mActivity.mHandler.post(mExecCommit); 
            } 
        } 
    } 
 
    public int allocBackStackIndex(BackStackRecord bse) { 
        synchronized (this) { 
            if (mAvailBackStackIndices == null || mAvailBackStackIndices.size() <= 0) { 
                if (mBackStackIndices == null) { 
                    mBackStackIndices = new ArrayList<BackStackRecord>(); 
                } 
                int index = mBackStackIndices.size(); 
                if (DEBUG) Log.v(TAG, "Setting back stack index " + index + " to " + bse); 
                mBackStackIndices.add(bse); 
                return index; 
 
            } else { 
                int index = mAvailBackStackIndices.remove(mAvailBackStackIndices.size()-1); 
                if (DEBUG) Log.v(TAG, "Adding back stack index " + index + " with " + bse); 
                mBackStackIndices.set(index, bse); 
                return index; 
            } 
        } 
    } 
 
    public void setBackStackIndex(int index, BackStackRecord bse) { 
        synchronized (this) { 
            if (mBackStackIndices == null) { 
                mBackStackIndices = new ArrayList<BackStackRecord>(); 
            } 
            int N = mBackStackIndices.size(); 
            if (index < N) { 
                if (DEBUG) Log.v(TAG, "Setting back stack index " + index + " to " + bse); 
                mBackStackIndices.set(index, bse); 
            } else { 
                while (N < index) { 
                    mBackStackIndices.add(null); 
                    if (mAvailBackStackIndices == null) { 
                        mAvailBackStackIndices = new ArrayList<Integer>(); 
                    } 
                    if (DEBUG) Log.v(TAG, "Adding available back stack index " + N); 
                    mAvailBackStackIndices.add(N); 
                    N++; 
                } 
                if (DEBUG) Log.v(TAG, "Adding back stack index " + index + " with " + bse); 
                mBackStackIndices.add(bse); 
            } 
        } 
    } 
 
    public void freeBackStackIndex(int index) { 
        synchronized (this) { 
            mBackStackIndices.set(index, null); 
            if (mAvailBackStackIndices == null) { 
                mAvailBackStackIndices = new ArrayList<Integer>(); 
            } 
            if (DEBUG) Log.v(TAG, "Freeing back stack index " + index); 
            mAvailBackStackIndices.add(index); 
        } 
    } 
 
    /**
     * Only call from main thread! 
     */
 
    public boolean execPendingActions() { 
        if (mExecutingActions) { 
            throw new IllegalStateException("Recursive entry to executePendingTransactions"); 
        } 
 
        if (Looper.myLooper() != mActivity.mHandler.getLooper()) { 
            throw new IllegalStateException("Must be called from main thread of process"); 
        } 
 
        boolean didSomething = false
 
        while (true) { 
            int numActions; 
 
            synchronized (this) { 
                if (mPendingActions == null || mPendingActions.size() == 0) { 
                    break
                } 
 
                numActions = mPendingActions.size(); 
                if (mTmpActions == null || mTmpActions.length < numActions) { 
                    mTmpActions = new Runnable[numActions]; 
                } 
                mPendingActions.toArray(mTmpActions); 
                mPendingActions.clear(); 
                mActivity.mHandler.removeCallbacks(mExecCommit); 
            } 
 
            mExecutingActions = true
            for (int i=0; i<numActions; i++) { 
                mTmpActions[i].run(); 
                mTmpActions[i] = null
            } 
            mExecutingActions = false
            didSomething = true
        } 
 
        if (mHavePendingDeferredStart) { 
            boolean loadersRunning = false
            for (int i=0; i<mActive.size(); i++) { 
                Fragment f = mActive.get(i); 
                if (f != null && f.mLoaderManager != null) { 
                    loadersRunning |= f.mLoaderManager.hasRunningLoaders(); 
                } 
            } 
            if (!loadersRunning) { 
                mHavePendingDeferredStart = false
                startPendingDeferredFragments(); 
            } 
        } 
        return didSomething; 
    } 
 
    void reportBackStackChanged() { 
        if (mBackStackChangeListeners != null) { 
            for (int i=0; i<mBackStackChangeListeners.size(); i++) { 
                mBackStackChangeListeners.get(i).onBackStackChanged(); 
            } 
        } 
    } 
 
    void addBackStackState(BackStackRecord state) { 
        if (mBackStack == null) { 
            mBackStack = new ArrayList<BackStackRecord>(); 
        } 
        mBackStack.add(state); 
        reportBackStackChanged(); 
    } 
 
    boolean popBackStackState(Handler handler, String name, int id, int flags) { 
        if (mBackStack == null) { 
            return false
        } 
        if (name == null && id < 0 && (flags&POP_BACK_STACK_INCLUSIVE) == 0) { 
            int last = mBackStack.size()-1
            if (last < 0) { 
                return false
            } 
            final BackStackRecord bss = mBackStack.remove(last); 
            bss.popFromBackStack(true); 
            reportBackStackChanged(); 
        } else { 
            int index = -1
            if (name != null || id >= 0) { 
                // If a name or ID is specified, look for that place in 
                // the stack. 
                index = mBackStack.size()-1
                while (index >= 0) { 
                    BackStackRecord bss = mBackStack.get(index); 
                    if (name != null && name.equals(bss.getName())) { 
                        break
                    } 
                    if (id >= 0 && id == bss.mIndex) { 
                        break
                    } 
                    index--; 
                } 
                if (index < 0) { 
                    return false
                } 
                if ((flags&POP_BACK_STACK_INCLUSIVE) != 0) { 
                    index--; 
                    // Consume all following entries that match. 
                    while (index >= 0) { 
                        BackStackRecord bss = mBackStack.get(index); 
                        if ((name != null && name.equals(bss.getName())) 
                                || (id >= 0 && id == bss.mIndex)) { 
                            index--; 
                            continue
                        } 
                        break
                    } 
                } 
            } 
            if (index == mBackStack.size()-1) { 
                return false
            } 
            final ArrayList<BackStackRecord> states 
                    = new ArrayList<BackStackRecord>(); 
            for (int i=mBackStack.size()-1; i>index; i--) { 
                states.add(mBackStack.remove(i)); 
            } 
            final int LAST = states.size()-1
            for (int i=0; i<=LAST; i++) { 
                if (DEBUG) Log.v(TAG, "Popping back stack state: " + states.get(i)); 
                states.get(i).popFromBackStack(i == LAST); 
            } 
            reportBackStackChanged(); 
        } 
        return true
    } 
 
    ArrayList<Fragment> retainNonConfig() { 
        ArrayList<Fragment> fragments = null
        if (mActive != null) { 
            for (int i=0; i<mActive.size(); i++) { 
                Fragment f = mActive.get(i); 
                if (f != null && f.mRetainInstance) { 
                    if (fragments == null) { 
                        fragments = new ArrayList<Fragment>(); 
                    } 
                    fragments.add(f); 
                    f.mRetaining = true
                    f.mTargetIndex = f.mTarget != null ? f.mTarget.mIndex : -1
                } 
            } 
        } 
        return fragments; 
    } 
 
    void saveFragmentViewState(Fragment f) { 
        if (f.mInnerView == null) { 
            return
        } 
        if (mStateArray == null) { 
            mStateArray = new SparseArray<Parcelable>(); 
        } else { 
            mStateArray.clear(); 
        } 
        f.mInnerView.saveHierarchyState(mStateArray); 
        if (mStateArray.size() > 0) { 
            f.mSavedViewState = mStateArray; 
            mStateArray = null
        } 
    } 
 
    Bundle saveFragmentBasicState(Fragment f) { 
        Bundle result = null
 
        if (mStateBundle == null) { 
            mStateBundle = new Bundle(); 
        } 
        f.onSaveInstanceState(mStateBundle); 
        if (!mStateBundle.isEmpty()) { 
            result = mStateBundle; 
            mStateBundle = null
        } 
 
        if (f.mView != null) { 
            saveFragmentViewState(f); 
        } 
        if (f.mSavedViewState != null) { 
            if (result == null) { 
                result = new Bundle(); 
            } 
            result.putSparseParcelableArray( 
                    FragmentManagerImpl.VIEW_STATE_TAG, f.mSavedViewState); 
        } 
        if (!f.mUserVisibleHint) { 
            if (result == null) { 
                result = new Bundle(); 
            } 
            // Only add this if it's not the default value 
            result.putBoolean(FragmentManagerImpl.USER_VISIBLE_HINT_TAG, f.mUserVisibleHint); 
        } 
 
        return result; 
    } 
 
    Parcelable saveAllState() { 
        // Make sure all pending operations have now been executed to get 
        // our state update-to-date. 
        execPendingActions(); 
 
        if (HONEYCOMB) { 
            // As of Honeycomb, we save state after pausing.  Prior to that 
            // it is before pausing.  With fragments this is an issue, since 
            // there are many things you may do after pausing but before 
            // stopping that change the fragment state.  For those older 
            // devices, we will not at this point say that we have saved 
            // the state, so we will allow them to continue doing fragment 
            // transactions.  This retains the same semantics as Honeycomb, 
            // though you do have the risk of losing the very most recent state 
            // if the process is killed...  we'll live with that. 
            mStateSaved = true
        } 
 
        if (mActive == null || mActive.size() <= 0) { 
            return null
        } 
 
        // First collect all active fragments. 
        int N = mActive.size(); 
        FragmentState[] active = new FragmentState[N]; 
        boolean haveFragments = false
        for (int i=0; i<N; i++) { 
            Fragment f = mActive.get(i); 
            if (f != null) { 
                haveFragments = true
 
                FragmentState fs = new FragmentState(f); 
                active[i] = fs; 
 
                if (f.mState > Fragment.INITIALIZING && fs.mSavedFragmentState == null) { 
                    fs.mSavedFragmentState = saveFragmentBasicState(f); 
 
                    if (f.mTarget != null) { 
                        if (f.mTarget.mIndex < 0) { 
                            String msg = "Failure saving state: " + f 
                                + " has target not in fragment manager: " + f.mTarget; 
                            Log.e(TAG, msg); 
                            dump("  "nullnew PrintWriter(new LogWriter(TAG)), new String[] { }); 
                            throw new IllegalStateException(msg); 
                        } 
                        if (fs.mSavedFragmentState == null) { 
                            fs.mSavedFragmentState = new Bundle(); 
                        } 
                        putFragment(fs.mSavedFragmentState, 
                                FragmentManagerImpl.TARGET_STATE_TAG, f.mTarget); 
                        if (f.mTargetRequestCode != 0) { 
                            fs.mSavedFragmentState.putInt( 
                                    FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 
                                    f.mTargetRequestCode); 
                        } 
                    } 
 
                } else { 
                    fs.mSavedFragmentState = f.mSavedFragmentState; 
                } 
 
                if (DEBUG) Log.v(TAG, "Saved state of " + f + ": " 
                        + fs.mSavedFragmentState); 
            } 
        } 
 
        if (!haveFragments) { 
            if (DEBUG) Log.v(TAG, "saveAllState: no fragments!"); 
            return null
        } 
 
        int[] added = null
        BackStackState[] backStack = null
 
        // Build list of currently added fragments. 
        if (mAdded != null) { 
            N = mAdded.size(); 
            if (N > 0) { 
                added = new int[N]; 
                for (int i=0; i<N; i++) { 
                    added[i] = mAdded.get(i).mIndex; 
                    if (DEBUG) Log.v(TAG, "saveAllState: adding fragment #" + i 
                            + ": " + mAdded.get(i)); 
                } 
            } 
        } 
 
        // Now save back stack. 
        if (mBackStack != null) { 
            N = mBackStack.size(); 
            if (N > 0) { 
                backStack = new BackStackState[N]; 
                for (int i=0; i<N; i++) { 
                    backStack[i] = new BackStackState(this, mBackStack.get(i)); 
                    if (DEBUG) Log.v(TAG, "saveAllState: adding back stack #" + i 
                            + ": " + mBackStack.get(i)); 
                } 
            } 
        } 
 
        FragmentManagerState fms = new FragmentManagerState(); 
        fms.mActive = active; 
        fms.mAdded = added; 
        fms.mBackStack = backStack; 
        return fms; 
    } 
 
    void restoreAllState(Parcelable state, ArrayList<Fragment> nonConfig) { 
        // If there is no saved state at all, then there can not be 
        // any nonConfig fragments either, so that is that. 
        if (state == nullreturn
        FragmentManagerState fms = (FragmentManagerState)state; 
        if (fms.mActive == nullreturn
 
        // First re-attach any non-config instances we are retaining back 
        // to their saved state, so we don't try to instantiate them again. 
        if (nonConfig != null) { 
            for (int i=0; i<nonConfig.size(); i++) { 
                Fragment f = nonConfig.get(i); 
                if (DEBUG) Log.v(TAG, "restoreAllState: re-attaching retained " + f); 
                FragmentState fs = fms.mActive[f.mIndex]; 
                fs.mInstance = f; 
                f.mSavedViewState = null
                f.mBackStackNesting = 0
                f.mInLayout = false
                f.mAdded = false
                f.mTarget = null
                if (fs.mSavedFragmentState != null) { 
                    fs.mSavedFragmentState.setClassLoader(mActivity.getClassLoader()); 
                    f.mSavedViewState = fs.mSavedFragmentState.getSparseParcelableArray( 
                            FragmentManagerImpl.VIEW_STATE_TAG); 
                } 
            } 
        } 
 
        // Build the full list of active fragments, instantiating them from 
        // their saved state. 
        mActive = new ArrayList<Fragment>(fms.mActive.length); 
        if (mAvailIndices != null) { 
            mAvailIndices.clear(); 
        } 
        for (int i=0; i<fms.mActive.length; i++) { 
            FragmentState fs = fms.mActive[i]; 
            if (fs != null) { 
                Fragment f = fs.instantiate(mActivity); 
                if (DEBUG) Log.v(TAG, "restoreAllState: adding #" + i + ": " + f); 
                mActive.add(f); 
                // Now that the fragment is instantiated (or came from being 
                // retained above), clear mInstance in case we end up re-restoring 
                // from this FragmentState again. 
                fs.mInstance = null
            } else { 
                if (DEBUG) Log.v(TAG, "restoreAllState: adding #" + i + ": (null)"); 
                mActive.add(null); 
                if (mAvailIndices == null) { 
                    mAvailIndices = new ArrayList<Integer>(); 
                } 
                if (DEBUG) Log.v(TAG, "restoreAllState: adding avail #" + i); 
                mAvailIndices.add(i); 
            } 
        } 
 
        // Update the target of all retained fragments. 
        if (nonConfig != null) { 
            for (int i=0; i<nonConfig.size(); i++) { 
                Fragment f = nonConfig.get(i); 
                if (f.mTargetIndex >= 0) { 
                    if (f.mTargetIndex < mActive.size()) { 
                        f.mTarget = mActive.get(f.mTargetIndex); 
                    } else { 
                        Log.w(TAG, "Re-attaching retained fragment " + f 
                                + " target no longer exists: " + f.mTargetIndex); 
                        f.mTarget = null
                    } 
                } 
            } 
        } 
 
        // Build the list of currently added fragments. 
        if (fms.mAdded != null) { 
            mAdded = new ArrayList<Fragment>(fms.mAdded.length); 
            for (int i=0; i<fms.mAdded.length; i++) { 
                Fragment f = mActive.get(fms.mAdded[i]); 
                if (f == null) { 
                    throw new IllegalStateException( 
                            "No instantiated fragment for index #" + fms.mAdded[i]); 
                } 
                f.mAdded = true
                if (DEBUG) Log.v(TAG, "restoreAllState: making added #" + i + ": " + f); 
                mAdded.add(f); 
            } 
        } else { 
            mAdded = null
        } 
 
        // Build the back stack. 
        if (fms.mBackStack != null) { 
            mBackStack = new ArrayList<BackStackRecord>(fms.mBackStack.length); 
            for (int i=0; i<fms.mBackStack.length; i++) { 
                BackStackRecord bse = fms.mBackStack[i].instantiate(this); 
                if (DEBUG) Log.v(TAG, "restoreAllState: adding bse #" + i 
                        + " (index " + bse.mIndex + "): " + bse); 
                mBackStack.add(bse); 
                if (bse.mIndex >= 0) { 
                    setBackStackIndex(bse.mIndex, bse); 
                } 
            } 
        } else { 
            mBackStack = null
        } 
    } 
 
    public void attachActivity(FragmentActivity activity) { 
        if (mActivity != nullthrow new IllegalStateException(); 
        mActivity = activity; 
    } 
 
    public void noteStateNotSaved() { 
        mStateSaved = false
    } 
 
    public void dispatchCreate() { 
        mStateSaved = false
        moveToState(Fragment.CREATED, false); 
    } 
 
    public void dispatchActivityCreated() { 
        mStateSaved = false
        moveToState(Fragment.ACTIVITY_CREATED, false); 
    } 
 
    public void dispatchStart() { 
        mStateSaved = false
        moveToState(Fragment.STARTED, false); 
    } 
 
    public void dispatchResume() { 
        mStateSaved = false
        moveToState(Fragment.RESUMED, false); 
    } 
 
    public void dispatchPause() { 
        moveToState(Fragment.STARTED, false); 
    } 
 
    public void dispatchStop() { 
        // See saveAllState() for the explanation of this.  We do this for 
        // all platform versions, to keep our behavior more consistent between 
        // them. 
        mStateSaved = true
 
        moveToState(Fragment.STOPPED, false); 
    } 
 
    public void dispatchReallyStop() { 
        moveToState(Fragment.ACTIVITY_CREATED, false); 
    } 
 
    public void dispatchDestroy() { 
        mDestroyed = true
        execPendingActions(); 
        moveToState(Fragment.INITIALIZING, false); 
        mActivity = null
    } 
 
    public void dispatchConfigurationChanged(Configuration newConfig) { 
        if (mActive != null) { 
            for (int i=0; i<mAdded.size(); i++) { 
                Fragment f = mAdded.get(i); 
                if (f != null) { 
                    f.onConfigurationChanged(newConfig); 
                } 
            } 
        } 
    } 
 
    public void dispatchLowMemory() { 
        if (mActive != null) { 
            for (int i=0; i<mAdded.size(); i++) { 
                Fragment f = mAdded.get(i); 
                if (f != null) { 
                    f.onLowMemory(); 
                } 
            } 
        } 
    } 
 
    public boolean dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater) { 
        boolean show = false
        ArrayList<Fragment> newMenus = null
        if (mActive != null) { 
            for (int i=0; i<mAdded.size(); i++) { 
                Fragment f = mAdded.get(i); 
                if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) { 
                    show = true
                    f.onCreateOptionsMenu(menu, inflater); 
                    if (newMenus == null) { 
                        newMenus = new ArrayList<Fragment>(); 
                    } 
                    newMenus.add(f); 
                } 
            } 
        } 
 
        if (mCreatedMenus != null) { 
            for (int i=0; i<mCreatedMenus.size(); i++) { 
                Fragment f = mCreatedMenus.get(i); 
                if (newMenus == null || !newMenus.contains(f)) { 
                    f.onDestroyOptionsMenu(); 
                } 
            } 
        } 
 
        mCreatedMenus = newMenus; 
 
        return show; 
    } 
 
    public boolean dispatchPrepareOptionsMenu(Menu menu) { 
        boolean show = false
        if (mActive != null) { 
            for (int i=0; i<mAdded.size(); i++) { 
                Fragment f = mAdded.get(i); 
                if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) { 
                    show = true
                    f.onPrepareOptionsMenu(menu); 
                } 
            } 
        } 
        return show; 
    } 
 
    public boolean dispatchOptionsItemSelected(MenuItem item) { 
        if (mActive != null) { 
            for (int i=0; i<mAdded.size(); i++) { 
                Fragment f = mAdded.get(i); 
                if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) { 
                    if (f.onOptionsItemSelected(item)) { 
                        return true
                    } 
                } 
            } 
        } 
        return false
    } 
 
    public boolean dispatchContextItemSelected(android.view.MenuItem item) { 
        if (mActive != null) { 
            for (int i=0; i<mAdded.size(); i++) { 
                Fragment f = mAdded.get(i); 
                if (f != null && !f.mHidden) { 
                    if (f.onContextItemSelected(item)) { 
                        return true
                    } 
                } 
            } 
        } 
        return false
    } 
 
    public void dispatchOptionsMenuClosed(Menu menu) { 
        if (mActive != null) { 
            for (int i=0; i<mAdded.size(); i++) { 
                Fragment f = mAdded.get(i); 
                if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) { 
                    f.onOptionsMenuClosed(menu); 
                } 
            } 
        } 
    } 
 
    public static int reverseTransit(int transit) { 
        int rev = 0
        switch (transit) { 
            case FragmentTransaction.TRANSIT_FRAGMENT_OPEN: 
                rev = FragmentTransaction.TRANSIT_FRAGMENT_CLOSE; 
                break
            case FragmentTransaction.TRANSIT_FRAGMENT_CLOSE: 
                rev = FragmentTransaction.TRANSIT_FRAGMENT_OPEN; 
                break
            case FragmentTransaction.TRANSIT_FRAGMENT_FADE: 
                rev = FragmentTransaction.TRANSIT_FRAGMENT_FADE; 
                break
        } 
        return rev; 
 
    } 
 
    public static final int ANIM_STYLE_OPEN_ENTER = 1
    public static final int ANIM_STYLE_OPEN_EXIT = 2
    public static final int ANIM_STYLE_CLOSE_ENTER = 3
    public static final int ANIM_STYLE_CLOSE_EXIT = 4
    public static final int ANIM_STYLE_FADE_ENTER = 5
    public static final int ANIM_STYLE_FADE_EXIT = 6
 
    public static int transitToStyleIndex(int transit, boolean enter) { 
        int animAttr = -1
        switch (transit) { 
            case FragmentTransaction.TRANSIT_FRAGMENT_OPEN: 
                animAttr = enter ? ANIM_STYLE_OPEN_ENTER : ANIM_STYLE_OPEN_EXIT; 
                break
            case FragmentTransaction.TRANSIT_FRAGMENT_CLOSE: 
                animAttr = enter ? ANIM_STYLE_CLOSE_ENTER : ANIM_STYLE_CLOSE_EXIT; 
                break
            case FragmentTransaction.TRANSIT_FRAGMENT_FADE: 
                animAttr = enter ? ANIM_STYLE_FADE_ENTER : ANIM_STYLE_FADE_EXIT; 
                break
        } 
        return animAttr; 
    } 
}