ExpandHelper.java revision 8fd12657e353a4a6f6d875a0d86850426fec00e8
16a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler/*
26a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler * Copyright (C) 2012 The Android Open Source Project
36a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler *
46a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler * Licensed under the Apache License, Version 2.0 (the "License");
56a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler * you may not use this file except in compliance with the License.
66a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler * You may obtain a copy of the License at
76a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler *
86a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler *      http://www.apache.org/licenses/LICENSE-2.0
96a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler *
106a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler * Unless required by applicable law or agreed to in writing, software
116a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler * distributed under the License is distributed on an "AS IS" BASIS,
126a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler * See the License for the specific language governing permissions and
146a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler * limitations under the License.
156a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler */
166a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler
176a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler
186a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandlerpackage com.android.systemui;
196a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler
20ba925e8ecd9decff5701001a0190042d6797942dChris Wrenimport android.animation.AnimatorSet;
216a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandlerimport android.animation.ObjectAnimator;
226a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandlerimport android.content.Context;
236a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandlerimport android.graphics.RectF;
246a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandlerimport android.util.Log;
256a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandlerimport android.view.MotionEvent;
266a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandlerimport android.view.ScaleGestureDetector;
276a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandlerimport android.view.View;
286a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandlerimport android.view.ViewGroup;
296a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandlerimport android.view.View.OnClickListener;
306a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandlerimport com.android.internal.widget.SizeAdaptiveLayout;
316a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler
326a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandlerpublic class ExpandHelper implements Gefingerpoken, OnClickListener {
336a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    public interface Callback {
346a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        View getChildAtPosition(MotionEvent ev);
356a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        View getChildAtPosition(float x, float y);
3680a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren        boolean canChildBeExpanded(View v);
378fd12657e353a4a6f6d875a0d86850426fec00e8Chris Wren        boolean setUserExpandedChild(View v, boolean userxpanded);
386a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    }
396a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler
406a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    private static final String TAG = "ExpandHelper";
416a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    protected static final boolean DEBUG = false;
426a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    private static final long EXPAND_DURATION = 250;
43ba925e8ecd9decff5701001a0190042d6797942dChris Wren    private static final long GLOW_DURATION = 150;
44ba925e8ecd9decff5701001a0190042d6797942dChris Wren
4589139d74b27305a29ca082c75d94dcbed5f84625Chris Wren    // Set to false to disable focus-based gestures (two-finger pull).
4689139d74b27305a29ca082c75d94dcbed5f84625Chris Wren    private static final boolean USE_DRAG = true;
4789139d74b27305a29ca082c75d94dcbed5f84625Chris Wren    // Set to false to disable scale-based gestures (both horizontal and vertical).
4889139d74b27305a29ca082c75d94dcbed5f84625Chris Wren    private static final boolean USE_SPAN = true;
4989139d74b27305a29ca082c75d94dcbed5f84625Chris Wren    // Both gestures types may be active at the same time.
5089139d74b27305a29ca082c75d94dcbed5f84625Chris Wren    // At least one gesture type should be active.
5189139d74b27305a29ca082c75d94dcbed5f84625Chris Wren    // A variant of the screwdriver gesture will emerge from either gesture type.
526a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler
5380a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren    // amount of overstretch for maximum brightness expressed in U
5480a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren    // 2f: maximum brightness is stretching a 1U to 3U, or a 4U to 6U
5580a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren    private static final float STRETCH_INTERVAL = 2f;
5680a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren
5780a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren    // level of glow for a touch, without overstretch
5880a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren    // overstretch fills the range (GLOW_BASE, 1.0]
5980a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren    private static final float GLOW_BASE = 0.5f;
6080a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren
616a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    @SuppressWarnings("unused")
626a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    private Context mContext;
636a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler
646a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    private boolean mStretching;
656a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    private View mCurrView;
6680a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren    private View mCurrViewTopGlow;
6780a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren    private View mCurrViewBottomGlow;
686a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    private float mOldHeight;
696a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    private float mNaturalHeight;
7089139d74b27305a29ca082c75d94dcbed5f84625Chris Wren    private float mInitialTouchFocusY;
716a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    private float mInitialTouchSpan;
726a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    private Callback mCallback;
736a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    private ScaleGestureDetector mDetector;
746a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    private ViewScaler mScaler;
75ba925e8ecd9decff5701001a0190042d6797942dChris Wren    private ObjectAnimator mScaleAnimation;
76ba925e8ecd9decff5701001a0190042d6797942dChris Wren    private AnimatorSet mGlowAnimationSet;
77ba925e8ecd9decff5701001a0190042d6797942dChris Wren    private ObjectAnimator mGlowTopAnimation;
78ba925e8ecd9decff5701001a0190042d6797942dChris Wren    private ObjectAnimator mGlowBottomAnimation;
796a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler
806a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    private int mSmallSize;
816a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    private int mLargeSize;
8280a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren    private float mMaximumStretch;
836a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler
846a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    private class ViewScaler {
856a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        View mView;
866a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        public ViewScaler() {}
876a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        public void setView(View v) {
886a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            mView = v;
896a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        }
906a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        public void setHeight(float h) {
9180a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren            if (DEBUG) Log.v(TAG, "SetHeight: setting to " + h);
926a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            ViewGroup.LayoutParams lp = mView.getLayoutParams();
936a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            lp.height = (int)h;
946a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            mView.setLayoutParams(lp);
9589139d74b27305a29ca082c75d94dcbed5f84625Chris Wren            mView.requestLayout();
966a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        }
976a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        public float getHeight() {
986a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            int height = mView.getLayoutParams().height;
996a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            if (height < 0) {
1006a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler                height = mView.getMeasuredHeight();
1016a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            }
1026a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            return (float) height;
1036a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        }
1046a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        public int getNaturalHeight(int maximum) {
1056a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            ViewGroup.LayoutParams lp = mView.getLayoutParams();
10689139d74b27305a29ca082c75d94dcbed5f84625Chris Wren            if (DEBUG) Log.v(TAG, "Inspecting a child of type: " + mView.getClass().getName());
1076a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            int oldHeight = lp.height;
1086a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
1096a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            mView.setLayoutParams(lp);
1106a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            mView.measure(
1116a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler                    View.MeasureSpec.makeMeasureSpec(mView.getMeasuredWidth(),
11289139d74b27305a29ca082c75d94dcbed5f84625Chris Wren                                                     View.MeasureSpec.EXACTLY),
1136a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler                    View.MeasureSpec.makeMeasureSpec(maximum,
11489139d74b27305a29ca082c75d94dcbed5f84625Chris Wren                                                     View.MeasureSpec.AT_MOST));
1156a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            lp.height = oldHeight;
1166a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            mView.setLayoutParams(lp);
1176a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            return mView.getMeasuredHeight();
1186a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        }
1196a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    }
1206a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler
1216a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    public ExpandHelper(Context context, Callback callback, int small, int large) {
1226a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        mSmallSize = small;
12380a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren        mMaximumStretch = mSmallSize * STRETCH_INTERVAL;
1246a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        mLargeSize = large;
1256a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        mContext = context;
1266a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        mCallback = callback;
1276a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        mScaler = new ViewScaler();
128ba925e8ecd9decff5701001a0190042d6797942dChris Wren
129ba925e8ecd9decff5701001a0190042d6797942dChris Wren        mScaleAnimation = ObjectAnimator.ofFloat(mScaler, "height", 0f);
130ba925e8ecd9decff5701001a0190042d6797942dChris Wren        mScaleAnimation.setDuration(EXPAND_DURATION);
131ba925e8ecd9decff5701001a0190042d6797942dChris Wren
132ba925e8ecd9decff5701001a0190042d6797942dChris Wren        mGlowTopAnimation = ObjectAnimator.ofFloat(null, "alpha", 0f);
133ba925e8ecd9decff5701001a0190042d6797942dChris Wren        mGlowBottomAnimation = ObjectAnimator.ofFloat(null, "alpha", 0f);
134ba925e8ecd9decff5701001a0190042d6797942dChris Wren        mGlowAnimationSet = new AnimatorSet();
135ba925e8ecd9decff5701001a0190042d6797942dChris Wren        mGlowAnimationSet.play(mGlowTopAnimation).with(mGlowBottomAnimation);
136ba925e8ecd9decff5701001a0190042d6797942dChris Wren        mGlowAnimationSet.setDuration(GLOW_DURATION);
137ba925e8ecd9decff5701001a0190042d6797942dChris Wren
1386a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        mDetector =
1396a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler                new ScaleGestureDetector(context,
1406a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler                                         new ScaleGestureDetector.SimpleOnScaleGestureListener() {
1416a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            @Override
1426a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            public boolean onScaleBegin(ScaleGestureDetector detector) {
1436a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler                if (DEBUG) Log.v(TAG, "onscalebegin()");
1446a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler                View v = mCallback.getChildAtPosition(detector.getFocusX(), detector.getFocusY());
1456a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler
1466a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler                // your fingers have to be somewhat close to the bounds of the view in question
14789139d74b27305a29ca082c75d94dcbed5f84625Chris Wren                mInitialTouchFocusY = detector.getFocusY();
14889139d74b27305a29ca082c75d94dcbed5f84625Chris Wren                mInitialTouchSpan = Math.abs(detector.getCurrentSpan());
14989139d74b27305a29ca082c75d94dcbed5f84625Chris Wren                if (DEBUG) Log.d(TAG, "got mInitialTouchSpan: (" + mInitialTouchSpan + ")");
1506a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler
1516a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler                mStretching = initScale(v);
1526a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler                return mStretching;
1536a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            }
1546a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler
1556a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            @Override
1566a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            public boolean onScale(ScaleGestureDetector detector) {
1576a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler                if (DEBUG) Log.v(TAG, "onscale() on " + mCurrView);
15889139d74b27305a29ca082c75d94dcbed5f84625Chris Wren
15989139d74b27305a29ca082c75d94dcbed5f84625Chris Wren                // are we scaling or dragging?
16089139d74b27305a29ca082c75d94dcbed5f84625Chris Wren                float span = Math.abs(detector.getCurrentSpan()) - mInitialTouchSpan;
16189139d74b27305a29ca082c75d94dcbed5f84625Chris Wren                span *= USE_SPAN ? 1f : 0f;
16289139d74b27305a29ca082c75d94dcbed5f84625Chris Wren                float drag = detector.getFocusY() - mInitialTouchFocusY;
16389139d74b27305a29ca082c75d94dcbed5f84625Chris Wren                drag *= USE_DRAG ? 1f : 0f;
16489139d74b27305a29ca082c75d94dcbed5f84625Chris Wren                float pull = Math.abs(drag) + Math.abs(span) + 1f;
16589139d74b27305a29ca082c75d94dcbed5f84625Chris Wren                float hand = drag * Math.abs(drag) / pull + span * Math.abs(span) / pull;
16689139d74b27305a29ca082c75d94dcbed5f84625Chris Wren                if (DEBUG) Log.d(TAG, "current span handle is: " + hand);
16789139d74b27305a29ca082c75d94dcbed5f84625Chris Wren                hand = hand + mOldHeight;
16889139d74b27305a29ca082c75d94dcbed5f84625Chris Wren                float target = hand;
16980a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren                if (DEBUG) Log.d(TAG, "target is: " + target);
17089139d74b27305a29ca082c75d94dcbed5f84625Chris Wren                hand = hand < mSmallSize ? mSmallSize : (hand > mLargeSize ? mLargeSize : hand);
17189139d74b27305a29ca082c75d94dcbed5f84625Chris Wren                hand = hand > mNaturalHeight ? mNaturalHeight : hand;
17289139d74b27305a29ca082c75d94dcbed5f84625Chris Wren                if (DEBUG) Log.d(TAG, "scale continues: hand =" + hand);
17389139d74b27305a29ca082c75d94dcbed5f84625Chris Wren                mScaler.setHeight(hand);
17489139d74b27305a29ca082c75d94dcbed5f84625Chris Wren
17589139d74b27305a29ca082c75d94dcbed5f84625Chris Wren                // glow if overscale
17689139d74b27305a29ca082c75d94dcbed5f84625Chris Wren                float stretch = (float) Math.abs((target - hand) / mMaximumStretch);
17780a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren                float strength = 1f / (1f + (float) Math.pow(Math.E, -1 * ((8f * stretch) - 5f)));
17880a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren                if (DEBUG) Log.d(TAG, "stretch: " + stretch + " strength: " + strength);
17980a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren                setGlow(GLOW_BASE + strength * (1f - GLOW_BASE));
1806a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler                return true;
1816a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            }
1826a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler
1836a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            @Override
1846a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            public void onScaleEnd(ScaleGestureDetector detector) {
1856a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler                if (DEBUG) Log.v(TAG, "onscaleend()");
1866a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler                // I guess we're alone now
1876a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler                if (DEBUG) Log.d(TAG, "scale end");
1886a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler                finishScale(false);
1896a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            }
1906a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        });
1916a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    }
19280a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren    public void setGlow(float glow) {
19389139d74b27305a29ca082c75d94dcbed5f84625Chris Wren        if (!mGlowAnimationSet.isRunning() || glow == 0f) {
19489139d74b27305a29ca082c75d94dcbed5f84625Chris Wren            if (mGlowAnimationSet.isRunning()) {
19589139d74b27305a29ca082c75d94dcbed5f84625Chris Wren                mGlowAnimationSet.cancel();
19689139d74b27305a29ca082c75d94dcbed5f84625Chris Wren            }
197ba925e8ecd9decff5701001a0190042d6797942dChris Wren            if (mCurrViewTopGlow != null && mCurrViewBottomGlow != null) {
198ba925e8ecd9decff5701001a0190042d6797942dChris Wren                if (glow == 0f || mCurrViewTopGlow.getAlpha() == 0f) {
199ba925e8ecd9decff5701001a0190042d6797942dChris Wren                    // animate glow in and out
200ba925e8ecd9decff5701001a0190042d6797942dChris Wren                    mGlowTopAnimation.setTarget(mCurrViewTopGlow);
201ba925e8ecd9decff5701001a0190042d6797942dChris Wren                    mGlowBottomAnimation.setTarget(mCurrViewBottomGlow);
202ba925e8ecd9decff5701001a0190042d6797942dChris Wren                    mGlowTopAnimation.setFloatValues(glow);
203ba925e8ecd9decff5701001a0190042d6797942dChris Wren                    mGlowBottomAnimation.setFloatValues(glow);
204ba925e8ecd9decff5701001a0190042d6797942dChris Wren                    mGlowAnimationSet.setupStartValues();
205ba925e8ecd9decff5701001a0190042d6797942dChris Wren                    mGlowAnimationSet.start();
206ba925e8ecd9decff5701001a0190042d6797942dChris Wren                } else {
207ba925e8ecd9decff5701001a0190042d6797942dChris Wren                    // set it explicitly in reponse to touches.
208ba925e8ecd9decff5701001a0190042d6797942dChris Wren                    mCurrViewTopGlow.setAlpha(glow);
209ba925e8ecd9decff5701001a0190042d6797942dChris Wren                    mCurrViewBottomGlow.setAlpha(glow);
210ba925e8ecd9decff5701001a0190042d6797942dChris Wren                }
211ba925e8ecd9decff5701001a0190042d6797942dChris Wren            }
21280a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren        }
21380a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren    }
2146a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler
2156a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    public boolean onInterceptTouchEvent(MotionEvent ev) {
2166a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        if (DEBUG) Log.d(TAG, "interceptTouch: act=" + (ev.getAction()) +
2176a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler                         " stretching=" + mStretching);
2186a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        mDetector.onTouchEvent(ev);
2196a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        return mStretching;
2206a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    }
2216a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler
2226a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    public boolean onTouchEvent(MotionEvent ev) {
2236a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        final int action = ev.getAction();
2246a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        if (DEBUG) Log.d(TAG, "touch: act=" + (action) + " stretching=" + mStretching);
2256a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        if (mStretching) {
2266a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            mDetector.onTouchEvent(ev);
2276a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        }
2286a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        switch (action) {
2296a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            case MotionEvent.ACTION_UP:
2306a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            case MotionEvent.ACTION_CANCEL:
2316a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler                mStretching = false;
23280a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren                clearView();
2336a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler                break;
2346a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        }
2356a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        return true;
2366a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    }
2376a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    private boolean initScale(View v) {
2386a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        if (v != null) {
2396a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            if (DEBUG) Log.d(TAG, "scale begins on view: " + v);
2406a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            mStretching = true;
24180a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren            setView(v);
24280a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren            setGlow(GLOW_BASE);
2436a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            mScaler.setView(v);
2446a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            mOldHeight = mScaler.getHeight();
24580a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren            if (mCallback.canChildBeExpanded(v)) {
24680a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren                if (DEBUG) Log.d(TAG, "working on an expandable child");
24780a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren                mNaturalHeight = mScaler.getNaturalHeight(mLargeSize);
24880a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren            } else {
24980a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren                if (DEBUG) Log.d(TAG, "working on a non-expandable child");
25080a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren                mNaturalHeight = mOldHeight;
25180a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren            }
2526a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            if (DEBUG) Log.d(TAG, "got mOldHeight: " + mOldHeight +
2536a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler                        " mNaturalHeight: " + mNaturalHeight);
2546a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            v.getParent().requestDisallowInterceptTouchEvent(true);
2556a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        }
2566a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        return mStretching;
2576a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    }
2586a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler
2596a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    private void finishScale(boolean force) {
2606a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        float h = mScaler.getHeight();
2616a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        final boolean wasClosed = (mOldHeight == mSmallSize);
2626a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        if (wasClosed) {
2636a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            h = (force || h > mSmallSize) ? mNaturalHeight : mSmallSize;
2646a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        } else {
2656a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler            h = (force || h < mNaturalHeight) ? mSmallSize : mNaturalHeight;
2666a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        }
26780a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren        if (DEBUG && mCurrView != null) mCurrView.setBackgroundColor(0);
268ba925e8ecd9decff5701001a0190042d6797942dChris Wren        if (mScaleAnimation.isRunning()) {
269ba925e8ecd9decff5701001a0190042d6797942dChris Wren            mScaleAnimation.cancel();
270ba925e8ecd9decff5701001a0190042d6797942dChris Wren        }
271ba925e8ecd9decff5701001a0190042d6797942dChris Wren        mScaleAnimation.setFloatValues(h);
272ba925e8ecd9decff5701001a0190042d6797942dChris Wren        mScaleAnimation.setupStartValues();
273ba925e8ecd9decff5701001a0190042d6797942dChris Wren        mScaleAnimation.start();
2746a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        mStretching = false;
27580a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren        setGlow(0f);
2768fd12657e353a4a6f6d875a0d86850426fec00e8Chris Wren        mCallback.setUserExpandedChild(mCurrView, h == mNaturalHeight);
27789139d74b27305a29ca082c75d94dcbed5f84625Chris Wren        if (DEBUG) Log.d(TAG, "scale was finished on view: " + mCurrView);
27880a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren        clearView();
27980a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren    }
28080a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren
28180a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren    private void clearView() {
2826a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        mCurrView = null;
28380a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren        mCurrViewTopGlow = null;
28480a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren        mCurrViewBottomGlow = null;
28580a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren    }
28680a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren
28780a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren    private void setView(View v) {
28889139d74b27305a29ca082c75d94dcbed5f84625Chris Wren        mCurrView = v;
28980a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren        if (v instanceof ViewGroup) {
29080a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren            ViewGroup g = (ViewGroup) v;
29180a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren            mCurrViewTopGlow = g.findViewById(R.id.top_glow);
29280a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren            mCurrViewBottomGlow = g.findViewById(R.id.bottom_glow);
29389139d74b27305a29ca082c75d94dcbed5f84625Chris Wren            if (DEBUG) {
29480a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren                String debugLog = "Looking for glows: " +
29580a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren                        (mCurrViewTopGlow != null ? "found top " : "didn't find top") +
29680a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren                        (mCurrViewBottomGlow != null ? "found bottom " : "didn't find bottom");
29780a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren                Log.v(TAG,  debugLog);
29880a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren            }
29980a76276dc9440ffad30dc4c820eb7d65f4df368Chris Wren        }
3006a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    }
3016a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler
3026a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    @Override
3036a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    public void onClick(View v) {
3046a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        initScale(v);
3056a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler        finishScale(true);
3066a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler
3076a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler    }
3086a858c347f4d4e5db4c8f00d5e285967631b71caDaniel Sandler}
309