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

Commit 3db40678 authored by Adam Cohen's avatar Adam Cohen
Browse files

Added AdapterViewAnimator and AdapterViewFlipper which are versions of ViewAnimator and ViewFlipper

whos views are defined by adapters.

Change-Id: I6ca1681b4820e6a1b6b69fc6d92c11c9f969bb88
parent 950d6a98
Loading
Loading
Loading
Loading
+389 −0
Original line number Original line Diff line number Diff line
@@ -208824,6 +208824,395 @@
</parameter>
</parameter>
</method>
</method>
</interface>
</interface>
<class name="AdapterViewAnimator"
 extends="android.widget.AdapterView"
 abstract="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<constructor name="AdapterViewAnimator"
 type="android.widget.AdapterViewAnimator"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="context" type="android.content.Context">
</parameter>
</constructor>
<constructor name="AdapterViewAnimator"
 type="android.widget.AdapterViewAnimator"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="context" type="android.content.Context">
</parameter>
<parameter name="attrs" type="android.util.AttributeSet">
</parameter>
</constructor>
<method name="getAdapter"
 return="android.widget.Adapter"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="getCurrentView"
 return="android.view.View"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="getDisplayedChild"
 return="int"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="getInAnimation"
 return="android.view.animation.Animation"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="getOutAnimation"
 return="android.view.animation.Animation"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="getSelectedView"
 return="android.view.View"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="initViewAnimator"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="protected"
>
<parameter name="context" type="android.content.Context">
</parameter>
<parameter name="attrs" type="android.util.AttributeSet">
</parameter>
</method>
<method name="onRemoteAdapterConnected"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="onRemoteAdapterDisconnected"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="setAdapter"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="adapter" type="android.widget.Adapter">
</parameter>
</method>
<method name="setAnimateFirstView"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="animate" type="boolean">
</parameter>
</method>
<method name="setDisplayedChild"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="whichChild" type="int">
</parameter>
</method>
<method name="setInAnimation"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="inAnimation" type="android.view.animation.Animation">
</parameter>
</method>
<method name="setInAnimation"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="context" type="android.content.Context">
</parameter>
<parameter name="resourceID" type="int">
</parameter>
</method>
<method name="setOutAnimation"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="outAnimation" type="android.view.animation.Animation">
</parameter>
</method>
<method name="setOutAnimation"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="context" type="android.content.Context">
</parameter>
<parameter name="resourceID" type="int">
</parameter>
</method>
<method name="setRemoteViewsAdapter"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="intent" type="android.content.Intent">
</parameter>
</method>
<method name="setSelection"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="position" type="int">
</parameter>
</method>
<method name="showNext"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="showPrevious"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
</class>
<class name="AdapterViewFlipper"
 extends="android.widget.AdapterViewAnimator"
 abstract="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<constructor name="AdapterViewFlipper"
 type="android.widget.AdapterViewFlipper"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="context" type="android.content.Context">
</parameter>
</constructor>
<constructor name="AdapterViewFlipper"
 type="android.widget.AdapterViewFlipper"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="context" type="android.content.Context">
</parameter>
<parameter name="attrs" type="android.util.AttributeSet">
</parameter>
</constructor>
<method name="initDefaultAnimations"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="protected"
>
</method>
<method name="isAutoStart"
 return="boolean"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="isFlipping"
 return="boolean"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="setAutoStart"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="autoStart" type="boolean">
</parameter>
</method>
<method name="setFlipInterval"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="milliseconds" type="int">
</parameter>
</method>
<method name="startFlipping"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="stopFlipping"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
</class>
<class name="Adapters"
<class name="Adapters"
 extends="java.lang.Object"
 extends="java.lang.Object"
 abstract="false"
 abstract="false"
+455 −0
Original line number Original line 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.widget;

import android.content.Context;
import android.content.Intent;
import android.content.res.TypedArray;
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;

/**
 * Base class for a {@link AdapterView} that will perform animations
 * when switching between its views.
 *
 * @attr ref android.R.styleable#AdapterViewAnimator_inAnimation
 * @attr ref android.R.styleable#AdapterViewAnimator_outAnimation
 * @attr ref android.R.styleable#AdapterViewAnimator_animateFirstView
 */
public class AdapterViewAnimator extends AdapterView<Adapter> implements RemoteViewsAdapter.RemoteAdapterConnectionCallback{
    private static final String TAG = "RemoteViewAnimator";

    int mWhichChild = 0;
    boolean mFirstTime = true;
    boolean mAnimateFirstTime = true;

    AdapterDataSetObserver mDataSetObserver;

    View mPreviousView;
    View mCurrentView;

    Animation mInAnimation;
    Animation mOutAnimation;
    Adapter mAdapter;
    RemoteViewsAdapter mRemoteViewsAdapter;
    private Handler mMainQueue;

    public AdapterViewAnimator(Context context) {
        super(context);
        initViewAnimator(context, null);
    }

    public AdapterViewAnimator(Context context, AttributeSet attrs) {
        super(context, attrs);

        TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.ViewAnimator);
        int resource = a.getResourceId(com.android.internal.R.styleable.ViewAnimator_inAnimation, 0);
        if (resource > 0) {
            setInAnimation(context, resource);
        }

        resource = a.getResourceId(com.android.internal.R.styleable.ViewAnimator_outAnimation, 0);
        if (resource > 0) {
            setOutAnimation(context, resource);
        }

        boolean flag = a.getBoolean(com.android.internal.R.styleable.ViewAnimator_animateFirstView, true);
        setAnimateFirstView(flag);

        a.recycle();

        initViewAnimator(context, attrs);
    }

    /**
     * Initialize this {@link AdapterViewAnimator}
     */
    private void initViewAnimator(Context context, AttributeSet attrs) {
        mMainQueue = new Handler(Looper.myLooper());
    }

    /**
     * Sets which child view will be displayed.
     *
     * @param whichChild the index of the child view to display
     */
    public void setDisplayedChild(int whichChild) {
        if (mAdapter != null) {
            mWhichChild = whichChild;
            if (whichChild >= mAdapter.getCount()) {
                mWhichChild = 0;
            } else if (whichChild < 0) {
                mWhichChild = mAdapter.getCount() - 1;
            }

            boolean hasFocus = getFocusedChild() != null;
            // This will clear old focus if we had it
            showOnly(mWhichChild);
            if (hasFocus) {
                // Try to retake focus if we had it
                requestFocus(FOCUS_FORWARD);
            }
        }
    }

    /**
     * Return default inAnimation. To be overriden by subclasses.
     */
    public Animation getDefaultInAnimation() {
        return null;
    }

    /**
     * Return default outAnimation. To be overriden by subclasses.
     */
    public Animation getDefaultOutAnimation() {
        return null;
    }

    /**
     * Returns the index of the currently displayed child view.
     */
    public int getDisplayedChild() {
        return mWhichChild;
    }

    /**
     * Manually shows the next child.
     */
    public void showNext() {
        setDisplayedChild(mWhichChild + 1);
    }

    /**
     * Manually shows the previous child.
     */
    public void showPrevious() {
        setDisplayedChild(mWhichChild - 1);
    }

    /**
     * Shows only the specified child. The other displays Views exit the screen,
     * optionally with the with the {@link #getOutAnimation() out animation} and
     * the specified child enters the screen, optionally with the
     * {@link #getInAnimation() in animation}.
     *
     * @param childIndex The index of the child to be shown.
     * @param animate Whether or not to use the in and out animations, defaults
     *            to true.
     */
    void showOnly(int childIndex, boolean animate) {
        showOnly(childIndex, animate, false);
    }

    private LayoutParams makeLayoutParams() {
        int width = mMeasuredWidth - mPaddingLeft - mPaddingRight;
        int height = mMeasuredHeight - mPaddingTop - mPaddingBottom;
        return new LayoutParams(width, height);
    }

    protected void showOnly(int childIndex, boolean animate, boolean onLayout) {
        if (mAdapter != null) {
            // The previous view should be removed from the ViewGroup
            if (mPreviousView != null) {
                mPreviousView.clearAnimation();

                // TODO: this is where we would store the the view for
                // recycling
                removeViewInLayout(mPreviousView);
            }

            // If the current view is still being animated, we should
            // force the animation to end
            if (mCurrentView != null) {
                mCurrentView.clearAnimation();
            }

            // load the new mCurrentView from our adapter
            mPreviousView = mCurrentView;
            mCurrentView = mAdapter.getView(childIndex, null, this);
            if (mPreviousView != mCurrentView) {
                addViewInLayout(mCurrentView, 0, makeLayoutParams(), true);
                mCurrentView.bringToFront();
            }



            // Animate as necessary
            if (mPreviousView != null && mPreviousView != mCurrentView) {
                if (animate && mOutAnimation != null) {
                    mPreviousView.startAnimation(mOutAnimation);
                }
                // This line results in the view becoming invisible *after*
                // the above animation is complete, or, if there is no animation
                // then it becomes invisble immediately
                mPreviousView.setVisibility(View.GONE);
            }

            if (mCurrentView != null && animate && mInAnimation != null) {
                mCurrentView.startAnimation(mInAnimation);
            }

            mFirstTime = false;
            if (!onLayout) {
                requestLayout();
                invalidate();
            } else {
                // If the Adapter tries to layout the current view when we get it using getView above
                // the layout will end up being ignored since we are currently laying out, so
                // we post a delayed requestLayout and invalidate
                mMainQueue.post(new Runnable() {
                    @Override
                    public void run() {
                        mCurrentView.requestLayout();
                        mCurrentView.invalidate();
                    }
                });
            }
        }
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        boolean dataChanged = mDataChanged;
        if (dataChanged) {
            handleDataChanged();

            // if the data changes, mWhichChild might be out of the bounds of the adapter
            // in this case, we reset mWhichChild to the beginning
            if (mWhichChild >= mAdapter.getCount())
                mWhichChild = 0;

            showOnly(mWhichChild, true, true);
        }

        final int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = getChildAt(i);

            int childRight = mPaddingLeft + child.getMeasuredWidth();
            int childBottom = mPaddingTop + child.getMeasuredHeight();

            child.layout(mPaddingLeft, mPaddingTop, childRight, childBottom);
        }

        mDataChanged = false;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        final int count = getChildCount();

        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);

        Log.v(TAG, "onMeasure");

        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);

            final LayoutParams lp = (LayoutParams) child.getLayoutParams();

            lp.width = widthSpecSize - mPaddingLeft - mPaddingRight;
            lp.height = heightSpecSize - mPaddingTop - mPaddingBottom;

            int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width,
                    MeasureSpec.EXACTLY);
            int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height,
                    MeasureSpec.EXACTLY);

            child.measure(childWidthMeasureSpec, childheightMeasureSpec);
        }

        setMeasuredDimension(widthSpecSize, heightSpecSize);
    }

    /**
     * Shows only the specified child. The other displays Views exit the screen
     * with the {@link #getOutAnimation() out animation} and the specified child
     * enters the screen with the {@link #getInAnimation() in animation}.
     *
     * @param childIndex The index of the child to be shown.
     */
    void showOnly(int childIndex) {
        final boolean animate = (!mFirstTime || mAnimateFirstTime);
        showOnly(childIndex, animate);
    }

    /**
     * Returns the View corresponding to the currently displayed child.
     *
     * @return The View currently displayed.
     *
     * @see #getDisplayedChild()
     */
    public View getCurrentView() {
        return mCurrentView;
    }

    /**
     * Returns the current animation used to animate a View that enters the screen.
     *
     * @return An Animation or null if none is set.
     *
     * @see #setInAnimation(android.view.animation.Animation)
     * @see #setInAnimation(android.content.Context, int)
     */
    public Animation getInAnimation() {
        return mInAnimation;
    }

    /**
     * Specifies the animation used to animate a View that enters the screen.
     *
     * @param inAnimation The animation started when a View enters the screen.
     *
     * @see #getInAnimation()
     * @see #setInAnimation(android.content.Context, int)
     */
    public void setInAnimation(Animation inAnimation) {
        mInAnimation = inAnimation;
    }

    /**
     * Returns the current animation used to animate a View that exits the screen.
     *
     * @return An Animation or null if none is set.
     *
     * @see #setOutAnimation(android.view.animation.Animation)
     * @see #setOutAnimation(android.content.Context, int)
     */
    public Animation getOutAnimation() {
        return mOutAnimation;
    }

    /**
     * Specifies the animation used to animate a View that exit the screen.
     *
     * @param outAnimation The animation started when a View exit the screen.
     *
     * @see #getOutAnimation()
     * @see #setOutAnimation(android.content.Context, int)
     */
    public void setOutAnimation(Animation outAnimation) {
        mOutAnimation = outAnimation;
    }

    /**
     * Specifies the animation used to animate a View that enters the screen.
     *
     * @param context The application's environment.
     * @param resourceID The resource id of the animation.
     *
     * @see #getInAnimation()
     * @see #setInAnimation(android.view.animation.Animation)
     */
    public void setInAnimation(Context context, int resourceID) {
        setInAnimation(AnimationUtils.loadAnimation(context, resourceID));
    }

    /**
     * Specifies the animation used to animate a View that exit the screen.
     *
     * @param context The application's environment.
     * @param resourceID The resource id of the animation.
     *
     * @see #getOutAnimation()
     * @see #setOutAnimation(android.view.animation.Animation)
     */
    public void setOutAnimation(Context context, int resourceID) {
        setOutAnimation(AnimationUtils.loadAnimation(context, resourceID));
    }

    /**
     * Indicates whether the current View should be animated the first time
     * the ViewAnimation is displayed.
     *
     * @param animate True to animate the current View the first time it is displayed,
     *                false otherwise.
     */
    public void setAnimateFirstView(boolean animate) {
        mAnimateFirstTime = animate;
    }

    @Override
    public int getBaseline() {
        return (getCurrentView() != null) ? getCurrentView().getBaseline() : super.getBaseline();
    }

    @Override
    public Adapter getAdapter() {
        return mAdapter;
    }

    @Override
    public void setAdapter(Adapter adapter) {
        mAdapter = adapter;

        if (mAdapter != null) {
            if (mDataSetObserver != null) {
                mAdapter.unregisterDataSetObserver(mDataSetObserver);
            }

            mDataSetObserver = new AdapterDataSetObserver();
            mAdapter.registerDataSetObserver(mDataSetObserver);
        }
    }

    /**
     * Sets up this AdapterViewAnimator to use a remote views adapter which connects to a RemoteViewsService
     * through the specified intent.
     * @param intent the intent used to identify the RemoteViewsService for the adapter to connect to.
     */
    @android.view.RemotableViewMethod
    public void setRemoteViewsAdapter(Intent intent) {
        mRemoteViewsAdapter = new RemoteViewsAdapter(getContext(), intent, this);
    }

    @Override
    public void setSelection(int position) {
        setDisplayedChild(position);
    }

    @Override
    public View getSelectedView() {
        return mCurrentView;
    }

    /**
     * Called back when the adapter connects to the RemoteViewsService.
     */
    public void onRemoteAdapterConnected() {
        if (mRemoteViewsAdapter != mAdapter) {
            setAdapter(mRemoteViewsAdapter);
        }
    }

    /**
     * Called back when the adapter disconnects from the RemoteViewsService.
     */
    public void onRemoteAdapterDisconnected() {
        if (mRemoteViewsAdapter != mAdapter) {
            mRemoteViewsAdapter = null;
            setAdapter(mRemoteViewsAdapter);
        }
    }
}
+238 −0

File added.

Preview size limit exceeded, changes collapsed.

+1 −0
Original line number Original line Diff line number Diff line
@@ -467,6 +467,7 @@ public class RemoteViewsAdapter extends BaseAdapter {
                        flipper.invalidate();
                        flipper.invalidate();
                    } else {
                    } else {
                        // hide the loading view and show the item view
                        // hide the loading view and show the item view
                        flipper.setVisibility(View.VISIBLE);
                        for (int i = 0; i < flipper.getChildCount() - 1; ++i) {
                        for (int i = 0; i < flipper.getChildCount() - 1; ++i) {
                            flipper.getChildAt(i).setVisibility(View.GONE);
                            flipper.getChildAt(i).setVisibility(View.GONE);
                        }
                        }
+14 −0
Original line number Original line Diff line number Diff line
@@ -2229,6 +2229,20 @@
        <!-- When true, automatically start animating -->
        <!-- When true, automatically start animating -->
        <attr name="autoStart" format="boolean" />
        <attr name="autoStart" format="boolean" />
    </declare-styleable>
    </declare-styleable>
    <declare-styleable name="AdapterViewAnimator">
        <!-- Identifier for the animation to use when a view is shown. -->
        <attr name="inAnimation" />
        <!-- Identifier for the animation to use when a view is hidden. -->
        <attr name="outAnimation" />
        <!-- Defines whether to animate the current View when the ViewAnimation
             is first displayed. -->
        <attr name="animateFirstView" />
    </declare-styleable>
    <declare-styleable name="AdapterViewFlipper">
        <attr name="flipInterval" />
        <!-- When true, automatically start animating -->
        <attr name="autoStart" />
    </declare-styleable>
    <declare-styleable name="ViewSwitcher">
    <declare-styleable name="ViewSwitcher">
    </declare-styleable>
    </declare-styleable>
    <declare-styleable name="ScrollView">
    <declare-styleable name="ScrollView">