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
199f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.animation.LayoutTransition;
209f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.content.Context;
213c728fe61dcf49354ea761a3e4ef6032ec271630Jim Millerimport android.content.res.Configuration;
229f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.database.DataSetObserver;
233cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurkaimport android.graphics.Canvas;
249f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.util.AttributeSet;
2599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurkaimport android.util.DisplayMetrics;
2699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurkaimport android.util.FloatMath;
279f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.util.Log;
289f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.view.MotionEvent;
299f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.view.View;
3099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurkaimport android.view.ViewConfiguration;
3199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurkaimport android.view.ViewTreeObserver;
3299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurkaimport android.view.ViewTreeObserver.OnGlobalLayoutListener;
339f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.widget.HorizontalScrollView;
349f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.widget.LinearLayout;
359f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
369f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport com.android.systemui.R;
3707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport com.android.systemui.SwipeHelper;
38ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport com.android.systemui.recent.RecentsPanelView.TaskDescriptionAdapter;
399f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
40d1a040c3e1dc30b26f4dfee8c9de2c802ac134b8Michael Jurkaimport java.util.HashSet;
41d1a040c3e1dc30b26f4dfee8c9de2c802ac134b8Michael Jurkaimport java.util.Iterator;
4299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka
4307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkapublic class RecentsHorizontalScrollView extends HorizontalScrollView
444eaa983f253d0215d4de777edd8616318610ea22Michael Jurka        implements SwipeHelper.Callback, RecentsPanelView.RecentsScrollView {
453c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller    private static final String TAG = RecentsPanelView.TAG;
463c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller    private static final boolean DEBUG = RecentsPanelView.DEBUG;
479f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    private LinearLayout mLinearLayout;
48ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka    private TaskDescriptionAdapter mAdapter;
499f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    private RecentsCallback mCallback;
509f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    protected int mLastScrollPosition;
5107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    private SwipeHelper mSwipeHelper;
524a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka    private FadedEdgeDrawHelper mFadedEdgeDrawHelper;
53d1a040c3e1dc30b26f4dfee8c9de2c802ac134b8Michael Jurka    private HashSet<View> mRecycledViews;
5499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka    private int mNumItemsInOneScreenful;
554a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka    private Runnable mOnScrollListener;
563cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
579f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    public RecentsHorizontalScrollView(Context context, AttributeSet attrs) {
589f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        super(context, attrs, 0);
5907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        float densityScale = getResources().getDisplayMetrics().density;
6007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
6107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        mSwipeHelper = new SwipeHelper(SwipeHelper.Y, this, densityScale, pagingTouchSlop);
624a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka        mFadedEdgeDrawHelper = FadedEdgeDrawHelper.create(context, attrs, this, false);
63d1a040c3e1dc30b26f4dfee8c9de2c802ac134b8Michael Jurka        mRecycledViews = new HashSet<View>();
649f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
659f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
664eaa983f253d0215d4de777edd8616318610ea22Michael Jurka    public void setMinSwipeAlpha(float minAlpha) {
674eaa983f253d0215d4de777edd8616318610ea22Michael Jurka        mSwipeHelper.setMinAlpha(minAlpha);
684eaa983f253d0215d4de777edd8616318610ea22Michael Jurka    }
694eaa983f253d0215d4de777edd8616318610ea22Michael Jurka
709f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    private int scrollPositionOfMostRecent() {
719f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        return mLinearLayout.getWidth() - getWidth();
729f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
739f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
74261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka    private void addToRecycledViews(View v) {
75261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka        if (mRecycledViews.size() < mNumItemsInOneScreenful) {
76261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka            mRecycledViews.add(v);
77261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka        }
78261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka    }
79261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka
80e5923631f06406f5f5e23a3a2ab4b24bb53a9094Michael Jurka    public View findViewForTask(int persistentTaskId) {
81cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
82cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka            View v = mLinearLayout.getChildAt(i);
83cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka            RecentsPanelView.ViewHolder holder = (RecentsPanelView.ViewHolder) v.getTag();
84e5923631f06406f5f5e23a3a2ab4b24bb53a9094Michael Jurka            if (holder.taskDescription.persistentTaskId == persistentTaskId) {
85cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                return v;
86cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka            }
87cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        }
88cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        return null;
89cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka    }
90cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka
91c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller    private void update() {
9299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
9399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            View v = mLinearLayout.getChildAt(i);
94261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka            addToRecycledViews(v);
9599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            mAdapter.recycleView(v);
9699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        }
9799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        LayoutTransition transitioner = getLayoutTransition();
9899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        setLayoutTransition(null);
9999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka
1009f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        mLinearLayout.removeAllViews();
101d1a040c3e1dc30b26f4dfee8c9de2c802ac134b8Michael Jurka        Iterator<View> recycledViews = mRecycledViews.iterator();
1029f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        for (int i = 0; i < mAdapter.getCount(); i++) {
10399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            View old = null;
104d1a040c3e1dc30b26f4dfee8c9de2c802ac134b8Michael Jurka            if (recycledViews.hasNext()) {
105d1a040c3e1dc30b26f4dfee8c9de2c802ac134b8Michael Jurka                old = recycledViews.next();
106d1a040c3e1dc30b26f4dfee8c9de2c802ac134b8Michael Jurka                recycledViews.remove();
10799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                old.setVisibility(VISIBLE);
10899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            }
10999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka
11099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            final View view = mAdapter.getView(i, old, mLinearLayout);
11107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
1124a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka            if (mFadedEdgeDrawHelper != null) {
1134a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka                mFadedEdgeDrawHelper.addViewCallback(view);
1143cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            }
1153cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
1167daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka            OnTouchListener noOpListener = new OnTouchListener() {
1177daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka                @Override
1187daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka                public boolean onTouch(View v, MotionEvent event) {
1197daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka                    return true;
1207daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka                }
1217daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka            };
1227daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka
1237725a4e3071c6450deb89dcb1e234ed96142edc9Michael Jurka            view.setOnClickListener(new OnClickListener() {
12407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                public void onClick(View v) {
1257725a4e3071c6450deb89dcb1e234ed96142edc9Michael Jurka                    mCallback.dismiss();
12607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                }
12707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            });
1280e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka            // We don't want a click sound when we dimiss recents
1290e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka            view.setSoundEffectsEnabled(false);
1307725a4e3071c6450deb89dcb1e234ed96142edc9Michael Jurka
1317725a4e3071c6450deb89dcb1e234ed96142edc9Michael Jurka            OnClickListener launchAppListener = new OnClickListener() {
1327725a4e3071c6450deb89dcb1e234ed96142edc9Michael Jurka                public void onClick(View v) {
1337725a4e3071c6450deb89dcb1e234ed96142edc9Michael Jurka                    mCallback.handleOnClick(view);
1347725a4e3071c6450deb89dcb1e234ed96142edc9Michael Jurka                }
1357725a4e3071c6450deb89dcb1e234ed96142edc9Michael Jurka            };
1367daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka
13799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            RecentsPanelView.ViewHolder holder = (RecentsPanelView.ViewHolder) view.getTag();
13899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            final View thumbnailView = holder.thumbnailView;
1390e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka            OnLongClickListener longClickListener = new OnLongClickListener() {
1400e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka                public boolean onLongClick(View v) {
1410e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka                    final View anchorView = view.findViewById(R.id.app_description);
1420e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka                    mCallback.handleLongPress(view, anchorView, thumbnailView);
1430e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka                    return true;
1440e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka                }
1450e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka            };
1467daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka            thumbnailView.setClickable(true);
1477daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka            thumbnailView.setOnClickListener(launchAppListener);
1487daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka            thumbnailView.setOnLongClickListener(longClickListener);
1497daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka
1507daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka            // We don't want to dismiss recents if a user clicks on the app title
1517daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka            // (we also don't want to launch the app either, though, because the
1527daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka            // app title is a small target and doesn't have great click feedback)
1537725a4e3071c6450deb89dcb1e234ed96142edc9Michael Jurka            final View appTitle = view.findViewById(R.id.app_label);
1547daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka            appTitle.setContentDescription(" ");
1557daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka            appTitle.setOnTouchListener(noOpListener);
1569f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            mLinearLayout.addView(view);
1579f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        }
15899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        setLayoutTransition(transitioner);
15999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka
160841594b2dbb4445ea84d9c9d617d5db3a28bb04bMichael Jurka        // Scroll to end after initial layout.
16199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka
16299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        final OnGlobalLayoutListener updateScroll = new OnGlobalLayoutListener() {
16399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                public void onGlobalLayout() {
16499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                    mLastScrollPosition = scrollPositionOfMostRecent();
16599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                    scrollTo(mLastScrollPosition, 0);
166841594b2dbb4445ea84d9c9d617d5db3a28bb04bMichael Jurka                    final ViewTreeObserver observer = getViewTreeObserver();
16799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                    if (observer.isAlive()) {
16899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                        observer.removeOnGlobalLayoutListener(this);
16999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                    }
17099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                }
17199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            };
172841594b2dbb4445ea84d9c9d617d5db3a28bb04bMichael Jurka        getViewTreeObserver().addOnGlobalLayoutListener(updateScroll);
1739f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
1749f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
1759f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    @Override
176c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller    public void removeViewInLayout(final View view) {
17707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        dismissChild(view);
178c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller    }
179c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller
1809f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    public boolean onInterceptTouchEvent(MotionEvent ev) {
181c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller        if (DEBUG) Log.v(TAG, "onInterceptTouchEvent()");
18207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        return mSwipeHelper.onInterceptTouchEvent(ev) ||
18307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            super.onInterceptTouchEvent(ev);
1849f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
1859f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
1869f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    @Override
1879f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    public boolean onTouchEvent(MotionEvent ev) {
18807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        return mSwipeHelper.onTouchEvent(ev) ||
18907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            super.onTouchEvent(ev);
19007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
1919f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
19207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    public boolean canChildBeDismissed(View v) {
19307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        return true;
19407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
1959f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
19607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    public void dismissChild(View v) {
19707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        mSwipeHelper.dismissChild(v, 0);
19807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
1999f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
20007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    public void onChildDismissed(View v) {
201261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka        addToRecycledViews(v);
20207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        mLinearLayout.removeView(v);
20307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        mCallback.handleSwipe(v);
2042db72fce6cfc0081583b9726ad80a7d95e064891Michael Jurka        // Restore the alpha/translation parameters to what they were before swiping
2052db72fce6cfc0081583b9726ad80a7d95e064891Michael Jurka        // (for when these items are recycled)
2062db72fce6cfc0081583b9726ad80a7d95e064891Michael Jurka        View contentView = getChildContentView(v);
2072db72fce6cfc0081583b9726ad80a7d95e064891Michael Jurka        contentView.setAlpha(1f);
2082db72fce6cfc0081583b9726ad80a7d95e064891Michael Jurka        contentView.setTranslationY(0);
2099f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
2109f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
21107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    public void onBeginDrag(View v) {
21213451a476a1951a19d3cb531c47bf5a51587800aMichael Jurka        // We do this so the underlying ScrollView knows that it won't get
21313451a476a1951a19d3cb531c47bf5a51587800aMichael Jurka        // the chance to intercept events anymore
21413451a476a1951a19d3cb531c47bf5a51587800aMichael Jurka        requestDisallowInterceptTouchEvent(true);
215622a97646d316ca753c577752ac9010415e9a472Peter Ng    }
216622a97646d316ca753c577752ac9010415e9a472Peter Ng
217622a97646d316ca753c577752ac9010415e9a472Peter Ng    public void onDragCancelled(View v) {
218c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller    }
219c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller
22007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    public View getChildAtPosition(MotionEvent ev) {
22107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        final float x = ev.getX() + getScrollX();
22207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        final float y = ev.getY() + getScrollY();
22307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
22407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            View item = mLinearLayout.getChildAt(i);
22507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            if (x >= item.getLeft() && x < item.getRight()
22607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                && y >= item.getTop() && y < item.getBottom()) {
22707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                return item;
2289f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            }
2299f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        }
23007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        return null;
23107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
23207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
23307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    public View getChildContentView(View v) {
2343cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        return v.findViewById(R.id.recent_item);
2353cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    }
2363cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
2373cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    @Override
2384a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka    public void drawFadedEdges(Canvas canvas, int left, int right, int top, int bottom) {
2394a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka        if (mFadedEdgeDrawHelper != null) {
2403cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
2414a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka            mFadedEdgeDrawHelper.drawCallback(canvas,
2423cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                    left, right, top, bottom, mScrollX, mScrollY,
2433cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                    0, 0,
24431a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                    getLeftFadingEdgeStrength(), getRightFadingEdgeStrength(), mPaddingTop);
2453cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        }
2463cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    }
2473cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
2483cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    @Override
2494a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
2504a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka       super.onScrollChanged(l, t, oldl, oldt);
2514a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka       if (mOnScrollListener != null) {
2524a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka           mOnScrollListener.run();
2534a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka       }
2544a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka    }
2554a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka
2564a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka    public void setOnScrollListener(Runnable listener) {
2574a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka        mOnScrollListener = listener;
2584a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka    }
2594a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka
2604a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka    @Override
2613cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    public int getVerticalFadingEdgeLength() {
2624a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka        if (mFadedEdgeDrawHelper != null) {
2634a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka            return mFadedEdgeDrawHelper.getVerticalFadingEdgeLength();
2643cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        } else {
2653cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            return super.getVerticalFadingEdgeLength();
2663cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        }
2673cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    }
2683cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
2693cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    @Override
2703cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    public int getHorizontalFadingEdgeLength() {
2714a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka        if (mFadedEdgeDrawHelper != null) {
2724a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka            return mFadedEdgeDrawHelper.getHorizontalFadingEdgeLength();
2733cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        } else {
2743cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            return super.getHorizontalFadingEdgeLength();
2753cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        }
2769f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
2779f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
2789f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    @Override
2799f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    protected void onFinishInflate() {
2809f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        super.onFinishInflate();
2819f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        setScrollbarFadingEnabled(true);
2829f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        mLinearLayout = (LinearLayout) findViewById(R.id.recents_linear_layout);
2839f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        final int leftPadding = mContext.getResources()
2849f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            .getDimensionPixelOffset(R.dimen.status_bar_recents_thumbnail_left_margin);
2859f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        setOverScrollEffectPadding(leftPadding, 0);
2869f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
2879f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
2883c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller    @Override
2893cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    public void onAttachedToWindow() {
2904a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka        if (mFadedEdgeDrawHelper != null) {
2914a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka            mFadedEdgeDrawHelper.onAttachedToWindowCallback(mLinearLayout, isHardwareAccelerated());
2923cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        }
2933cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    }
2943cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
2953cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    @Override
2963c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller    protected void onConfigurationChanged(Configuration newConfig) {
2973c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller        super.onConfigurationChanged(newConfig);
29807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        float densityScale = getResources().getDisplayMetrics().density;
29907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        mSwipeHelper.setDensityScale(densityScale);
30007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
30107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        mSwipeHelper.setPagingTouchSlop(pagingTouchSlop);
3023c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller    }
3033c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller
3049f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    private void setOverScrollEffectPadding(int leftPadding, int i) {
3053c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller        // TODO Add to (Vertical)ScrollView
3069f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
3079f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
3089f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    @Override
3099f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
3109f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        super.onSizeChanged(w, h, oldw, oldh);
31181abe87dcc829c4c01473126c8664aa03385dc7cChet Haase
31281abe87dcc829c4c01473126c8664aa03385dc7cChet Haase        // Skip this work if a transition is running; it sets the scroll values independently
31381abe87dcc829c4c01473126c8664aa03385dc7cChet Haase        // and should not have those animated values clobbered by this logic
31481abe87dcc829c4c01473126c8664aa03385dc7cChet Haase        LayoutTransition transition = mLinearLayout.getLayoutTransition();
31581abe87dcc829c4c01473126c8664aa03385dc7cChet Haase        if (transition != null && transition.isRunning()) {
31681abe87dcc829c4c01473126c8664aa03385dc7cChet Haase            return;
31781abe87dcc829c4c01473126c8664aa03385dc7cChet Haase        }
3189f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        // Keep track of the last visible item in the list so we can restore it
3199f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        // to the bottom when the orientation changes.
3209f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        mLastScrollPosition = scrollPositionOfMostRecent();
3219f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
3229f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        // This has to happen post-layout, so run it "in the future"
3239f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        post(new Runnable() {
3249f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            public void run() {
32581abe87dcc829c4c01473126c8664aa03385dc7cChet Haase                // Make sure we're still not clobbering the transition-set values, since this
32681abe87dcc829c4c01473126c8664aa03385dc7cChet Haase                // runnable launches asynchronously
32781abe87dcc829c4c01473126c8664aa03385dc7cChet Haase                LayoutTransition transition = mLinearLayout.getLayoutTransition();
32881abe87dcc829c4c01473126c8664aa03385dc7cChet Haase                if (transition == null || !transition.isRunning()) {
32981abe87dcc829c4c01473126c8664aa03385dc7cChet Haase                    scrollTo(mLastScrollPosition, 0);
33081abe87dcc829c4c01473126c8664aa03385dc7cChet Haase                }
3319f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            }
3329f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        });
3339f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
3349f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
335ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka    public void setAdapter(TaskDescriptionAdapter adapter) {
3369f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        mAdapter = adapter;
3379f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        mAdapter.registerDataSetObserver(new DataSetObserver() {
3389f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            public void onChanged() {
3399f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                update();
3409f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            }
3419f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
3429f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            public void onInvalidated() {
3439f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                update();
3449f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            }
3459f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        });
34699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        DisplayMetrics dm = getResources().getDisplayMetrics();
34799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        int childWidthMeasureSpec =
34899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                MeasureSpec.makeMeasureSpec(dm.widthPixels, MeasureSpec.AT_MOST);
34999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        int childheightMeasureSpec =
35099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                MeasureSpec.makeMeasureSpec(dm.heightPixels, MeasureSpec.AT_MOST);
35199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        View child = mAdapter.createView(mLinearLayout);
35299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        child.measure(childWidthMeasureSpec, childheightMeasureSpec);
35399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        mNumItemsInOneScreenful =
35499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                (int) FloatMath.ceil(dm.widthPixels / (float) child.getMeasuredWidth());
355261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka        addToRecycledViews(child);
35699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka
35799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        for (int i = 0; i < mNumItemsInOneScreenful - 1; i++) {
358261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka            addToRecycledViews(mAdapter.createView(mLinearLayout));
35999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        }
36099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka    }
36199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka
36299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka    public int numItemsInOneScreenful() {
36399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        return mNumItemsInOneScreenful;
3649f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
3659f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
3669f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    @Override
3679f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    public void setLayoutTransition(LayoutTransition transition) {
3689f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        // The layout transition applies to our embedded LinearLayout
3699f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        mLinearLayout.setLayoutTransition(transition);
3709f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
3719f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
3729f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    public void setCallback(RecentsCallback callback) {
3739f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        mCallback = callback;
3749f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
3759f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller}
376