RecentsHorizontalScrollView.java revision 3c728fe61dcf49354ea761a3e4ef6032ec271630
19f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller/*
29f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller * Copyright (C) 2011 The Android Open Source Project
39f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller *
49f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller * Licensed under the Apache License, Version 2.0 (the "License");
59f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller * you may not use this file except in compliance with the License.
69f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller * You may obtain a copy of the License at
79f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller *
89f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller *      http://www.apache.org/licenses/LICENSE-2.0
99f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller *
109f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller * Unless required by applicable law or agreed to in writing, software
119f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller * distributed under the License is distributed on an "AS IS" BASIS,
129f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller * See the License for the specific language governing permissions and
149f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller * limitations under the License.
159f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller */
169f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
179f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerpackage com.android.systemui.recent;
189f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
193b1fc47d004f6b29af8f40d181baa3460b1e3b15Michael Jurkaimport com.android.systemui.recent.RecentsPanelView.ActivityDescriptionAdapter;
209f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
219f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.animation.Animator;
229f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.animation.Animator.AnimatorListener;
239f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.animation.LayoutTransition;
249f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.animation.ObjectAnimator;
259f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.animation.ValueAnimator;
269f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.animation.ValueAnimator.AnimatorUpdateListener;
279f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.content.Context;
283c728fe61dcf49354ea761a3e4ef6032ec271630Jim Millerimport android.content.res.Configuration;
299f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.database.DataSetObserver;
309f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.graphics.RectF;
319f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.util.AttributeSet;
329f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.util.Log;
339f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.view.LayoutInflater;
349f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.view.MotionEvent;
359f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.view.VelocityTracker;
369f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.view.View;
373c728fe61dcf49354ea761a3e4ef6032ec271630Jim Millerimport android.view.ViewConfiguration;
389f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.view.animation.DecelerateInterpolator;
399f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.view.animation.LinearInterpolator;
409f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.widget.HorizontalScrollView;
419f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.widget.LinearLayout;
429f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
439f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport com.android.systemui.R;
449f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
459f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerpublic class RecentsHorizontalScrollView extends HorizontalScrollView
469f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        implements View.OnClickListener, View.OnTouchListener {
479f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    private static final boolean DEBUG_INVALIDATE = false;
483c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller    private static final String TAG = RecentsPanelView.TAG;
493c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller    private static final boolean DEBUG = RecentsPanelView.DEBUG;
509f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    private LinearLayout mLinearLayout;
513b1fc47d004f6b29af8f40d181baa3460b1e3b15Michael Jurka    private ActivityDescriptionAdapter mAdapter;
529f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    private RecentsCallback mCallback;
539f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    protected int mLastScrollPosition;
549f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    private View mCurrentView;
559f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    private float mLastY;
569f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    private boolean mDragging;
579f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    private VelocityTracker mVelocityTracker;
583c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller    private float mDensityScale;
593c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller    private float mPagingTouchSlop;
609f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
619f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    public RecentsHorizontalScrollView(Context context) {
629f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        this(context, null);
639f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
649f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
659f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    public RecentsHorizontalScrollView(Context context, AttributeSet attrs) {
669f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        super(context, attrs, 0);
673c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller        mDensityScale = getResources().getDisplayMetrics().density;
683c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller        mPagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
699f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
709f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
719f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    private int scrollPositionOfMostRecent() {
729f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        return mLinearLayout.getWidth() - getWidth();
739f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
749f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
759f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    public void update() {
769f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        mLinearLayout.removeAllViews();
779f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        for (int i = 0; i < mAdapter.getCount(); i++) {
789f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            View view = mAdapter.getView(i, null, mLinearLayout);
799f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            view.setClickable(true);
809f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            view.setOnClickListener(this);
819f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            view.setOnTouchListener(this);
829f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            mLinearLayout.addView(view);
839f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        }
849f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        // Scroll to end after layout.
859f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        post(new Runnable() {
869f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            public void run() {
879f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                mLastScrollPosition = scrollPositionOfMostRecent();
889f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                scrollTo(mLastScrollPosition, 0);
899f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            }
909f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        });
919f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
929f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
939f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    @Override
949f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    public boolean onInterceptTouchEvent(MotionEvent ev) {
959f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        if (mVelocityTracker == null) {
969f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            mVelocityTracker = VelocityTracker.obtain();
979f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        }
989f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        mVelocityTracker.addMovement(ev);
999f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        switch (ev.getAction()) {
1009f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            case MotionEvent.ACTION_DOWN:
1019f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                mDragging = false;
1029f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                mLastY = ev.getY();
1039f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                break;
1049f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
1059f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            case MotionEvent.ACTION_MOVE:
1069f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                float delta = ev.getY() - mLastY;
1073c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller                if (DEBUG) Log.v(TAG, "ACTION_MOVE : " + delta);
1083c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller                if (Math.abs(delta) > mPagingTouchSlop) {
1099f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                    mDragging = true;
1109f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                }
1119f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                break;
1129f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
1139f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            case MotionEvent.ACTION_UP:
1149f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                mDragging = false;
1159f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                break;
1169f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        }
1179f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        return mDragging ? true : super.onInterceptTouchEvent(ev);
1189f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
1199f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
1209f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    private float getAlphaForOffset(View view, float thumbHeight) {
1213c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller        final float fadeHeight = Constants.FADE_CONSTANT * thumbHeight;
1229f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        float result = 1.0f;
1239f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        if (view.getY() >= thumbHeight) {
1249f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            result = 1.0f - (view.getY() - thumbHeight) / fadeHeight;
1259f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        } else if (view.getY() < 0.0f) {
1269f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            result = 1.0f + (thumbHeight + view.getY()) / fadeHeight;
1279f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        }
1283c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller        if (DEBUG) Log.v(TAG, "FADE AMOUNT: " + result);
1299f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        return result;
1309f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
1319f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
1329f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    @Override
1339f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    public boolean onTouchEvent(MotionEvent ev) {
1349f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        if (!mDragging) {
1359f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            return super.onTouchEvent(ev);
1369f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        }
1379f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
1389f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        mVelocityTracker.addMovement(ev);
1399f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
1409f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        final View animView = mCurrentView;
1419f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        // TODO: Cache thumbnail
1429f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        final View thumb = animView.findViewById(R.id.app_thumbnail);
1439f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        switch (ev.getAction()) {
1449f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            case MotionEvent.ACTION_MOVE:
1459f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                if (animView != null) {
1469f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                    final float delta = ev.getY() - mLastY;
1479f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                    animView.setY(animView.getY() + delta);
1489f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                    animView.setAlpha(getAlphaForOffset(animView, thumb.getHeight()));
1499f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                    invalidateGlobalRegion(animView);
1509f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                }
1519f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                mLastY = ev.getY();
1529f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                break;
1539f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
1549f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            case MotionEvent.ACTION_UP:
1559f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                final ObjectAnimator anim;
1569f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                if (animView != null) {
1579f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                    final VelocityTracker velocityTracker = mVelocityTracker;
1589f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                    velocityTracker.computeCurrentVelocity(1000, 10000);
1599f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                    final float velocityX = velocityTracker.getXVelocity();
1609f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                    final float velocityY = velocityTracker.getYVelocity();
1619f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                    final float curY = animView.getY();
1629f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                    final float newY = (velocityY >= 0.0f ? 1 : -1) * animView.getHeight();
1633c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller                    final float maxVelocity = Constants.ESCAPE_VELOCITY * mDensityScale;
1649f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                    if (Math.abs(velocityY) > Math.abs(velocityX)
1653c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller                            && Math.abs(velocityY) > maxVelocity
1669f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                            && (velocityY >= 0.0f) == (animView.getY() >= 0)) {
1673c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller                        long duration =
1689f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                            (long) (Math.abs(newY - curY) * 1000.0f / Math.abs(velocityY));
1693c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller                        duration = Math.min(duration, Constants.MAX_ESCAPE_ANIMATION_DURATION);
1709f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                        anim = ObjectAnimator.ofFloat(animView, "y", curY, newY);
1719f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                        anim.setInterpolator(new LinearInterpolator());
1729f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                        final int swipeDirection = animView.getY() >= 0.0f ?
1739f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                                RecentsCallback.SWIPE_RIGHT : RecentsCallback.SWIPE_LEFT;
1749f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                        anim.addListener(new AnimatorListener() {
1759f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                            public void onAnimationStart(Animator animation) {
1769f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                            }
1779f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                            public void onAnimationRepeat(Animator animation) {
1789f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                            }
1799f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                            public void onAnimationEnd(Animator animation) {
1809f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                                mLinearLayout.removeView(mCurrentView);
1819f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                                mCallback.handleSwipe(animView, swipeDirection);
1829f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                            }
1839f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                            public void onAnimationCancel(Animator animation) {
1849f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                                mLinearLayout.removeView(mCurrentView);
1859f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                                mCallback.handleSwipe(animView, swipeDirection);
1869f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                            }
1879f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                        });
1889f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                        anim.setDuration(duration);
1899f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                    } else { // Animate back to position
1903c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller                        long duration = Math.abs(velocityY) > 0.0f ?
1919f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                                (long) (Math.abs(newY - curY) * 1000.0f / Math.abs(velocityY))
1923c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller                                : Constants.SNAP_BACK_DURATION;
1933c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller                        duration = Math.min(duration, Constants.SNAP_BACK_DURATION);
1949f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                        anim = ObjectAnimator.ofFloat(animView, "y", animView.getY(), 0.0f);
1959f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                        anim.setInterpolator(new DecelerateInterpolator(2.0f));
1969f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                        anim.setDuration(duration);
1979f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                    }
1989f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
1999f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                    anim.addUpdateListener(new AnimatorUpdateListener() {
2009f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                        public void onAnimationUpdate(ValueAnimator animation) {
2019f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                            animView.setAlpha(getAlphaForOffset(animView, thumb.getHeight()));
2029f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                            invalidateGlobalRegion(animView);
2039f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                        }
2049f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                    });
2059f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                    anim.start();
2069f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                }
2079f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
2089f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                mVelocityTracker.recycle();
2099f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                mVelocityTracker = null;
2109f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                break;
2119f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        }
2129f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        return true;
2139f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
2149f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
2159f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    void invalidateGlobalRegion(View view) {
2169f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        RectF childBounds
2179f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                = new RectF(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
2189f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        childBounds.offset(view.getX(), view.getY());
2199f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        if (DEBUG_INVALIDATE) Log.v(TAG, "-------------");
2209f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        while (view.getParent() != null && view.getParent() instanceof View) {
2219f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            view = (View) view.getParent();
2229f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            view.getMatrix().mapRect(childBounds);
2239f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            view.invalidate((int) Math.floor(childBounds.left),
2249f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                    (int) Math.floor(childBounds.top),
2259f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                    (int) Math.ceil(childBounds.right),
2269f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                    (int) Math.ceil(childBounds.bottom));
2279f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            if (DEBUG_INVALIDATE) {
2289f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                Log.v(TAG, "INVALIDATE(" + (int) Math.floor(childBounds.left)
2299f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                        + "," + (int) Math.floor(childBounds.top)
2309f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                        + "," + (int) Math.ceil(childBounds.right)
2319f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                        + "," + (int) Math.ceil(childBounds.bottom));
2329f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            }
2339f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        }
2349f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
2359f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
2369f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    @Override
2379f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    protected void onFinishInflate() {
2389f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        super.onFinishInflate();
2399f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        LayoutInflater inflater = (LayoutInflater)
2409f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
2419f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
2429f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        setScrollbarFadingEnabled(true);
2439f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
2449f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        mLinearLayout = (LinearLayout) findViewById(R.id.recents_linear_layout);
2459f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
2469f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        final int leftPadding = mContext.getResources()
2479f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            .getDimensionPixelOffset(R.dimen.status_bar_recents_thumbnail_left_margin);
2489f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        setOverScrollEffectPadding(leftPadding, 0);
2499f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
2509f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
2513c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller    @Override
2523c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller    protected void onConfigurationChanged(Configuration newConfig) {
2533c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller        super.onConfigurationChanged(newConfig);
2543c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller        mDensityScale = getResources().getDisplayMetrics().density;
2553c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller        mPagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
2563c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller    }
2573c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller
2589f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    private void setOverScrollEffectPadding(int leftPadding, int i) {
2593c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller        // TODO Add to (Vertical)ScrollView
2609f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
2619f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
2629f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    @Override
2639f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
2649f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        super.onSizeChanged(w, h, oldw, oldh);
2659f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        // Keep track of the last visible item in the list so we can restore it
2669f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        // to the bottom when the orientation changes.
2679f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        mLastScrollPosition = scrollPositionOfMostRecent();
2689f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
2699f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        // This has to happen post-layout, so run it "in the future"
2709f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        post(new Runnable() {
2719f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            public void run() {
2729f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                scrollTo(0, mLastScrollPosition);
2739f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            }
2749f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        });
2759f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
2769f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
2779f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    @Override
2789f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    protected void onVisibilityChanged(View changedView, int visibility) {
2799f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        super.onVisibilityChanged(changedView, visibility);
2809f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        // scroll to bottom after reloading
2819f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        if (visibility == View.VISIBLE && changedView == this) {
2829f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            post(new Runnable() {
2839f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                public void run() {
2849f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                    update();
2859f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                }
2869f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            });
2879f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        }
2889f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
2899f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
2903b1fc47d004f6b29af8f40d181baa3460b1e3b15Michael Jurka    public void setAdapter(ActivityDescriptionAdapter adapter) {
2919f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        mAdapter = adapter;
2929f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        mAdapter.registerDataSetObserver(new DataSetObserver() {
2939f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            public void onChanged() {
2949f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                update();
2959f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            }
2969f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
2979f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            public void onInvalidated() {
2989f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                update();
2999f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            }
3009f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        });
3019f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
3029f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
3039f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    @Override
3049f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    public void setLayoutTransition(LayoutTransition transition) {
3059f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        // The layout transition applies to our embedded LinearLayout
3069f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        mLinearLayout.setLayoutTransition(transition);
3079f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
3089f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
3099f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    public void onClick(View view) {
3109f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        mCallback.handleOnClick(view);
3119f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
3129f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
3139f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    public void setCallback(RecentsCallback callback) {
3149f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        mCallback = callback;
3159f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
3169f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
3179f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    public boolean onTouch(View v, MotionEvent event) {
3189f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        mCurrentView = v;
3199f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        return false;
3209f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
3219f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller}
322