Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5ae74d6e authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

More fragment work.

Clean up FragmentTransaction API, add more animation control, add new
Fragment APIs for hiding and showing.

Change-Id: Iffe31351024a7a63d164270b8a955a499076600e
parent 6cf8b9a3
Loading
Loading
Loading
Loading
+123 −0
Original line number Diff line number Diff line
@@ -25538,6 +25538,39 @@
 visibility="public"
>
</method>
<method name="isAdded"
 return="boolean"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="isHidden"
 return="boolean"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="isVisible"
 return="boolean"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="onActivityResult"
 return="void"
 abstract="false"
@@ -25608,6 +25641,8 @@
</parameter>
<parameter name="enter" type="boolean">
</parameter>
<parameter name="nextAnim" type="int">
</parameter>
</method>
<method name="onCreateView"
 return="android.view.View"
@@ -25648,6 +25683,19 @@
 visibility="public"
>
</method>
<method name="onHiddenChanged"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="hidden" type="boolean">
</parameter>
</method>
<method name="onInflate"
 return="void"
 abstract="false"
@@ -25820,10 +25868,27 @@
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="containerViewId" type="int">
</parameter>
<parameter name="fragment" type="android.app.Fragment">
</parameter>
</method>
<method name="add"
 return="android.app.FragmentTransaction"
 abstract="true"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="containerViewId" type="int">
</parameter>
<parameter name="fragment" type="android.app.Fragment">
</parameter>
<parameter name="tag" type="java.lang.String">
</parameter>
</method>
<method name="addToBackStack"
 return="android.app.FragmentTransaction"
@@ -25849,6 +25914,19 @@
 visibility="public"
>
</method>
<method name="hide"
 return="android.app.FragmentTransaction"
 abstract="true"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="fragment" type="android.app.Fragment">
</parameter>
</method>
<method name="remove"
 return="android.app.FragmentTransaction"
 abstract="true"
@@ -25872,10 +25950,42 @@
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="containerViewId" type="int">
</parameter>
<parameter name="fragment" type="android.app.Fragment">
</parameter>
</method>
<method name="replace"
 return="android.app.FragmentTransaction"
 abstract="true"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="containerViewId" type="int">
</parameter>
<parameter name="fragment" type="android.app.Fragment">
</parameter>
<parameter name="tag" type="java.lang.String">
</parameter>
</method>
<method name="setCustomAnimations"
 return="android.app.FragmentTransaction"
 abstract="true"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="enter" type="int">
</parameter>
<parameter name="exit" type="int">
</parameter>
</method>
<method name="setTransition"
 return="android.app.FragmentTransaction"
@@ -25903,6 +26013,19 @@
<parameter name="styleRes" type="int">
</parameter>
</method>
<method name="show"
 return="android.app.FragmentTransaction"
 abstract="true"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="fragment" type="android.app.Fragment">
</parameter>
</method>
<field name="TRANSIT_ACTIVITY_CLOSE"
 type="int"
 transient="false"
+3 −0
Original line number Diff line number Diff line
@@ -3877,6 +3877,9 @@ public class Activity extends ContextThemeWrapper
            // instantiated this fragment from the state and should use
            // that instance instead of making a new one.
            Fragment fragment = mFragments.findFragmentById(id);
            if (FragmentManager.DEBUG) Log.v(TAG, "onCreateView: id=0x"
                    + Integer.toHexString(id) + " fname=" + fname
                    + " existing=" + fragment);
            if (fragment == null) {
                fragment = Fragment.instantiate(this, fname);
                fragment.mFromLayout = true;
+379 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2010 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.app;

import android.os.Parcel;
import android.os.Parcelable;

import java.util.ArrayList;

final class BackStackState implements Parcelable {
    final int[] mOps;
    final int mTransition;
    final int mTransitionStyle;
    final String mName;
    
    public BackStackState(FragmentManager fm, BackStackEntry bse) {
        mOps = new int[bse.mNumOp*4];
        BackStackEntry.Op op = bse.mHead;
        int pos = 0;
        while (op != null) {
            mOps[pos++] = op.cmd;
            mOps[pos++] = op.fragment.mIndex;
            mOps[pos++] = op.enterAnim;
            mOps[pos++] = op.exitAnim;
            op = op.next;
        }
        mTransition = bse.mTransition;
        mTransitionStyle = bse.mTransitionStyle;
        mName = bse.mName;
    }
    
    public BackStackState(Parcel in) {
        mOps = in.createIntArray();
        mTransition = in.readInt();
        mTransitionStyle = in.readInt();
        mName = in.readString();
    }
    
    public BackStackEntry instantiate(FragmentManager fm) {
        BackStackEntry bse = new BackStackEntry(fm);
        int pos = 0;
        while (pos < mOps.length) {
            BackStackEntry.Op op = new BackStackEntry.Op();
            op.cmd = mOps[pos++];
            Fragment f = fm.mActive.get(mOps[pos++]);
            f.mBackStackNesting++;
            op.fragment = f;
            op.enterAnim = mOps[pos++];
            op.exitAnim = mOps[pos++];
            bse.addOp(op);
        }
        bse.mTransition = mTransition;
        bse.mTransitionStyle = mTransitionStyle;
        bse.mName = mName;
        return bse;
    }
    
    public int describeContents() {
        return 0;
    }

    public void writeToParcel(Parcel dest, int flags) {
        dest.writeIntArray(mOps);
        dest.writeInt(mTransition);
        dest.writeInt(mTransitionStyle);
        dest.writeString(mName);
    }
    
    public static final Parcelable.Creator<BackStackState> CREATOR
            = new Parcelable.Creator<BackStackState>() {
        public BackStackState createFromParcel(Parcel in) {
            return new BackStackState(in);
        }
        
        public BackStackState[] newArray(int size) {
            return new BackStackState[size];
        }
    };
}

/**
 * @hide Entry of an operation on the fragment back stack.
 */
final class BackStackEntry implements FragmentTransaction, Runnable {
    final FragmentManager mManager;
    
    static final int OP_NULL = 0;
    static final int OP_ADD = 1;
    static final int OP_REMOVE = 2;
    static final int OP_HIDE = 3;
    static final int OP_SHOW = 4;
    
    static final class Op {
        Op next;
        Op prev;
        int cmd;
        Fragment fragment;
        int enterAnim;
        int exitAnim;
    }
    
    Op mHead;
    Op mTail;
    int mNumOp;
    int mEnterAnim;
    int mExitAnim;
    int mTransition;
    int mTransitionStyle;
    boolean mAddToBackStack;
    String mName;
    boolean mCommitted;
    
    public BackStackEntry(FragmentManager manager) {
        mManager = manager;
    }
    
    void addOp(Op op) {
        if (mHead == null) {
            mHead = mTail = op;
        } else {
            op.prev = mTail;
            mTail.next = op;
            mTail = op;
        }
        op.enterAnim = mEnterAnim;
        op.exitAnim = mExitAnim;
        mNumOp++;
    }
        
    public FragmentTransaction add(Fragment fragment, String tag) {
        return add(0, fragment, tag);
    }

    public FragmentTransaction add(int containerViewId, Fragment fragment) {
        return add(containerViewId, fragment, null);
    }

    public FragmentTransaction add(int containerViewId, Fragment fragment, String tag) {
        if (fragment.mActivity != null) {
            throw new IllegalStateException("Fragment already added: " + fragment);
        }
        
        if (tag != null) {
            if (fragment.mTag != null && !tag.equals(fragment.mTag)) {
                throw new IllegalStateException("Can't change tag of fragment "
                        + fragment + ": was " + fragment.mTag
                        + " now " + tag);
            }
            fragment.mTag = tag;
        }
        
        if (containerViewId != 0) {
            if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {
                throw new IllegalStateException("Can't change container ID of fragment "
                        + fragment + ": was " + fragment.mFragmentId
                        + " now " + containerViewId);
            }
            fragment.mContainerId = fragment.mFragmentId = containerViewId;
        }
        
        Op op = new Op();
        op.cmd = OP_ADD;
        op.fragment = fragment;
        addOp(op);
        
        return this;
    }

    public FragmentTransaction replace(int containerViewId, Fragment fragment) {
        return replace(containerViewId, fragment, null);
    }
    
    public FragmentTransaction replace(int containerViewId, Fragment fragment, String tag) {
        if (containerViewId == 0) {
            throw new IllegalArgumentException("Must use non-zero containerViewId");
        }
        if (mManager.mAdded != null) {
            for (int i=0; i<mManager.mAdded.size(); i++) {
                Fragment old = mManager.mAdded.get(i);
                if (old.mContainerId == containerViewId) {
                    remove(old);
                }
            }
        }
        return add(containerViewId, fragment, tag);
    }
    
    public FragmentTransaction remove(Fragment fragment) {
        if (fragment.mActivity == null) {
            throw new IllegalStateException("Fragment not added: " + fragment);
        }
        
        Op op = new Op();
        op.cmd = OP_REMOVE;
        op.fragment = fragment;
        addOp(op);
        
        return this;
    }

    public FragmentTransaction hide(Fragment fragment) {
        if (fragment.mActivity == null) {
            throw new IllegalStateException("Fragment not added: " + fragment);
        }
        
        Op op = new Op();
        op.cmd = OP_HIDE;
        op.fragment = fragment;
        addOp(op);
        
        return this;
    }
    
    public FragmentTransaction show(Fragment fragment) {
        if (fragment.mActivity == null) {
            throw new IllegalStateException("Fragment not added: " + fragment);
        }
        
        Op op = new Op();
        op.cmd = OP_SHOW;
        op.fragment = fragment;
        addOp(op);
        
        return this;
    }
    
    public FragmentTransaction setCustomAnimations(int enter, int exit) {
        mEnterAnim = enter;
        mExitAnim = exit;
        return this;
    }
    
    public FragmentTransaction setTransition(int transition) {
        mTransition = transition;
        return this;
    }
    
    public FragmentTransaction setTransitionStyle(int styleRes) {
        mTransitionStyle = styleRes;
        return this;
    }
    
    public FragmentTransaction addToBackStack(String name) {
        mAddToBackStack = true;
        mName = name;
        return this;
    }

    public void commit() {
        if (mCommitted) throw new IllegalStateException("commit already called");
        mCommitted = true;
        mManager.mActivity.mHandler.post(this);
    }
    
    public void run() {
        Op op = mHead;
        while (op != null) {
            switch (op.cmd) {
                case OP_ADD: {
                    Fragment f = op.fragment;
                    if (mAddToBackStack) {
                        f.mBackStackNesting++;
                    }
                    f.mNextAnim = op.enterAnim;
                    mManager.addFragment(f, false);
                } break;
                case OP_REMOVE: {
                    Fragment f = op.fragment;
                    if (mAddToBackStack) {
                        f.mBackStackNesting++;
                    }
                    f.mNextAnim = op.exitAnim;
                    mManager.removeFragment(f, mTransition, mTransitionStyle);
                } break;
                case OP_HIDE: {
                    Fragment f = op.fragment;
                    if (mAddToBackStack) {
                        f.mBackStackNesting++;
                    }
                    f.mNextAnim = op.exitAnim;
                    mManager.hideFragment(f, mTransition, mTransitionStyle);
                } break;
                case OP_SHOW: {
                    Fragment f = op.fragment;
                    if (mAddToBackStack) {
                        f.mBackStackNesting++;
                    }
                    f.mNextAnim = op.enterAnim;
                    mManager.showFragment(f, mTransition, mTransitionStyle);
                } break;
                default: {
                    throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
                }
            }
            
            op = op.next;
        }
        
        mManager.moveToState(mManager.mCurState, mTransition,
                mTransitionStyle, true);
        if (mAddToBackStack) {
            mManager.addBackStackState(this);
        }
    }
    
    public void popFromBackStack() {
        Op op = mTail;
        while (op != null) {
            switch (op.cmd) {
                case OP_ADD: {
                    Fragment f = op.fragment;
                    if (mAddToBackStack) {
                        f.mBackStackNesting--;
                    }
                    mManager.removeFragment(f,
                            FragmentManager.reverseTransit(mTransition),
                            mTransitionStyle);
                } break;
                case OP_REMOVE: {
                    Fragment f = op.fragment;
                    if (mAddToBackStack) {
                        f.mBackStackNesting--;
                    }
                    mManager.addFragment(f, false);
                } break;
                case OP_HIDE: {
                    Fragment f = op.fragment;
                    if (mAddToBackStack) {
                        f.mBackStackNesting--;
                    }
                    mManager.showFragment(f,
                            FragmentManager.reverseTransit(mTransition), mTransitionStyle);
                } break;
                case OP_SHOW: {
                    Fragment f = op.fragment;
                    if (mAddToBackStack) {
                        f.mBackStackNesting--;
                    }
                    mManager.hideFragment(f,
                            FragmentManager.reverseTransit(mTransition), mTransitionStyle);
                } break;
                default: {
                    throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
                }
            }
            
            op = op.prev;
        }
        
        mManager.moveToState(mManager.mCurState,
                FragmentManager.reverseTransit(mTransition), mTransitionStyle, true);
    }
    
    public String getName() {
        return mName;
    }
    
    public int getTransition() {
        return mTransition;
    }
    
    public int getTransitionStyle() {
        return mTransitionStyle;
    }
}
+74 −15
Original line number Diff line number Diff line
@@ -29,7 +29,6 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;

@@ -128,12 +127,8 @@ final class FragmentState implements Parcelable {
 * that can be placed in an {@link Activity}.
 */
public class Fragment implements ComponentCallbacks {
    private static final Object[] sConstructorArgs = new Object[0];

    private static final Class[] sConstructorSignature = new Class[] { };

    private static final HashMap<String, Constructor> sConstructorMap =
            new HashMap<String, Constructor>();
    private static final HashMap<String, Class> sClassMap =
            new HashMap<String, Class>();
    
    static final int INITIALIZING = 0;  // Not yet created.
    static final int CREATED = 1;       // Created.
@@ -178,6 +173,10 @@ public class Fragment implements ComponentCallbacks {
    // fragments that are not part of the layout.
    String mTag;
    
    // Set to true when the app has requested that this fragment be hidden
    // from the user.
    boolean mHidden;
    
    // If set this fragment would like its instance retained across
    // configuration changes.
    boolean mRetainInstance;
@@ -188,6 +187,9 @@ public class Fragment implements ComponentCallbacks {
    // Used to verify that subclasses call through to super class.
    boolean mCalled;
    
    // If app has requested a specific animation, this is the one to use.
    int mNextAnim;
    
    // The parent container of the fragment after dynamically added to UI.
    ViewGroup mContainer;
    
@@ -201,16 +203,14 @@ public class Fragment implements ComponentCallbacks {
            throws NoSuchMethodException, ClassNotFoundException,
            IllegalArgumentException, InstantiationException,
            IllegalAccessException, InvocationTargetException {
        Constructor constructor = sConstructorMap.get(fname);
        Class clazz = null;
        Class clazz = sClassMap.get(fname);

        if (constructor == null) {
        if (clazz == null) {
            // Class not found in the cache, see if it's real, and try to add it
            clazz = activity.getClassLoader().loadClass(fname);
            constructor = clazz.getConstructor(sConstructorSignature);
            sConstructorMap.put(fname, constructor);
            sClassMap.put(fname, clazz);
        }
        return (Fragment)constructor.newInstance(sConstructorArgs);
        return (Fragment)clazz.newInstance();
    }
    
    void restoreViewState() {
@@ -244,6 +244,27 @@ public class Fragment implements ComponentCallbacks {
        return super.hashCode();
    }
    
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder(128);
        sb.append("Fragment{");
        sb.append(Integer.toHexString(System.identityHashCode(this)));
        if (mIndex >= 0) {
            sb.append(" #");
            sb.append(mIndex);
        }
        if (mFragmentId != 0) {
            sb.append(" id=0x");
            sb.append(Integer.toHexString(mFragmentId));
        }
        if (mTag != null) {
            sb.append(" ");
            sb.append(mTag);
        }
        sb.append('}');
        return sb.toString();
    }
    
    /**
     * Return the identifier this fragment is known by.  This is either
     * the android:id value supplied in a layout or the container view ID
@@ -267,6 +288,44 @@ public class Fragment implements ComponentCallbacks {
        return mActivity;
    }
    
    /**
     * Return true if the fragment is currently added to its activity.
     */
    public boolean isAdded() {
        return mActivity != null && mActivity.mFragments.mAdded.contains(this);
    }
    
    /**
     * Return true if the fragment is currently visible to the user.  This means
     * it: (1) has been added, (2) has its view attached to the window, and 
     * (3) is not hidden.
     */
    public boolean isVisible() {
        return isAdded() && !isHidden() && mView != null
                && mView.getWindowToken() != null && mView.getVisibility() == View.VISIBLE;
    }
    
    /**
     * Return true if the fragment has been hidden.  By default fragments
     * are shown.  You can find out about changes to this state with
     * {@link #onHiddenChanged()}.  Note that the hidden state is orthogonal
     * to other states -- that is, to be visible to the user, a fragment
     * must be both started and not hidden.
     */
    public boolean isHidden() {
        return mHidden;
    }
    
    /**
     * Called when the hidden state (as returned by {@link #isHidden()} of
     * the fragment has changed.  Fragments start out not hidden; this will
     * be called whenever the fragment changes state from that.
     * @param hidden True if the fragment is now hidden, false if it is not
     * visible.
     */
    public void onHiddenChanged(boolean hidden) {
    }
    
    /**
     * Control whether a fragment instance is retained across Activity
     * re-creation (such as from a configuration change).  This can only
@@ -351,7 +410,7 @@ public class Fragment implements ComponentCallbacks {
        mCalled = true;
    }
    
    public Animation onCreateAnimation(int transit, boolean enter) {
    public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
        return null;
    }
    
+74 −228

File changed.

Preview size limit exceeded, changes collapsed.

Loading