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);
59eceda3d83814e20cabddc4f0755d475fa2f3d8ffDan Sandler        mSwipeHelper = new SwipeHelper(SwipeHelper.Y, this, context);
604a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka        mFadedEdgeDrawHelper = FadedEdgeDrawHelper.create(context, attrs, this, false);
61d1a040c3e1dc30b26f4dfee8c9de2c802ac134b8Michael Jurka        mRecycledViews = new HashSet<View>();
629f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
639f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
644eaa983f253d0215d4de777edd8616318610ea22Michael Jurka    public void setMinSwipeAlpha(float minAlpha) {
655d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos        mSwipeHelper.setMinSwipeProgress(minAlpha);
664eaa983f253d0215d4de777edd8616318610ea22Michael Jurka    }
674eaa983f253d0215d4de777edd8616318610ea22Michael Jurka
689f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    private int scrollPositionOfMostRecent() {
699f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        return mLinearLayout.getWidth() - getWidth();
709f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
719f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
72261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka    private void addToRecycledViews(View v) {
73261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka        if (mRecycledViews.size() < mNumItemsInOneScreenful) {
74261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka            mRecycledViews.add(v);
75261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka        }
76261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka    }
77261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka
78e5923631f06406f5f5e23a3a2ab4b24bb53a9094Michael Jurka    public View findViewForTask(int persistentTaskId) {
79cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
80cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka            View v = mLinearLayout.getChildAt(i);
81cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka            RecentsPanelView.ViewHolder holder = (RecentsPanelView.ViewHolder) v.getTag();
82e5923631f06406f5f5e23a3a2ab4b24bb53a9094Michael Jurka            if (holder.taskDescription.persistentTaskId == persistentTaskId) {
83cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                return v;
84cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka            }
85cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        }
86cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        return null;
87cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka    }
88cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka
89c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller    private void update() {
9099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
9199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            View v = mLinearLayout.getChildAt(i);
92261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka            addToRecycledViews(v);
9399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            mAdapter.recycleView(v);
9499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        }
9599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        LayoutTransition transitioner = getLayoutTransition();
9699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        setLayoutTransition(null);
9799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka
989f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        mLinearLayout.removeAllViews();
99d1a040c3e1dc30b26f4dfee8c9de2c802ac134b8Michael Jurka        Iterator<View> recycledViews = mRecycledViews.iterator();
1009f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        for (int i = 0; i < mAdapter.getCount(); i++) {
10199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            View old = null;
102d1a040c3e1dc30b26f4dfee8c9de2c802ac134b8Michael Jurka            if (recycledViews.hasNext()) {
103d1a040c3e1dc30b26f4dfee8c9de2c802ac134b8Michael Jurka                old = recycledViews.next();
104d1a040c3e1dc30b26f4dfee8c9de2c802ac134b8Michael Jurka                recycledViews.remove();
10599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                old.setVisibility(VISIBLE);
10699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            }
10799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka
10899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            final View view = mAdapter.getView(i, old, mLinearLayout);
10907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
1104a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka            if (mFadedEdgeDrawHelper != null) {
1114a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka                mFadedEdgeDrawHelper.addViewCallback(view);
1123cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            }
1133cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
1147daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka            OnTouchListener noOpListener = new OnTouchListener() {
1157daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka                @Override
1167daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka                public boolean onTouch(View v, MotionEvent event) {
1177daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka                    return true;
1187daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka                }
1197daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka            };
1207daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka
1217725a4e3071c6450deb89dcb1e234ed96142edc9Michael Jurka            view.setOnClickListener(new OnClickListener() {
12207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                public void onClick(View v) {
1237725a4e3071c6450deb89dcb1e234ed96142edc9Michael Jurka                    mCallback.dismiss();
12407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                }
12507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            });
1260e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka            // We don't want a click sound when we dimiss recents
1270e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka            view.setSoundEffectsEnabled(false);
1287725a4e3071c6450deb89dcb1e234ed96142edc9Michael Jurka
1297725a4e3071c6450deb89dcb1e234ed96142edc9Michael Jurka            OnClickListener launchAppListener = new OnClickListener() {
1307725a4e3071c6450deb89dcb1e234ed96142edc9Michael Jurka                public void onClick(View v) {
1317725a4e3071c6450deb89dcb1e234ed96142edc9Michael Jurka                    mCallback.handleOnClick(view);
1327725a4e3071c6450deb89dcb1e234ed96142edc9Michael Jurka                }
1337725a4e3071c6450deb89dcb1e234ed96142edc9Michael Jurka            };
1347daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka
13599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            RecentsPanelView.ViewHolder holder = (RecentsPanelView.ViewHolder) view.getTag();
13699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            final View thumbnailView = holder.thumbnailView;
1370e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka            OnLongClickListener longClickListener = new OnLongClickListener() {
1380e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka                public boolean onLongClick(View v) {
1390e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka                    final View anchorView = view.findViewById(R.id.app_description);
1400e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka                    mCallback.handleLongPress(view, anchorView, thumbnailView);
1410e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka                    return true;
1420e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka                }
1430e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka            };
1447daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka            thumbnailView.setClickable(true);
1457daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka            thumbnailView.setOnClickListener(launchAppListener);
1467daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka            thumbnailView.setOnLongClickListener(longClickListener);
1477daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka
1487daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka            // We don't want to dismiss recents if a user clicks on the app title
1497daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka            // (we also don't want to launch the app either, though, because the
1507daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka            // app title is a small target and doesn't have great click feedback)
1517725a4e3071c6450deb89dcb1e234ed96142edc9Michael Jurka            final View appTitle = view.findViewById(R.id.app_label);
1527daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka            appTitle.setContentDescription(" ");
1537daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka            appTitle.setOnTouchListener(noOpListener);
1549f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            mLinearLayout.addView(view);
1559f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        }
15699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        setLayoutTransition(transitioner);
15799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka
158841594b2dbb4445ea84d9c9d617d5db3a28bb04bMichael Jurka        // Scroll to end after initial layout.
15999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka
16099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        final OnGlobalLayoutListener updateScroll = new OnGlobalLayoutListener() {
16199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                public void onGlobalLayout() {
16299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                    mLastScrollPosition = scrollPositionOfMostRecent();
16399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                    scrollTo(mLastScrollPosition, 0);
164841594b2dbb4445ea84d9c9d617d5db3a28bb04bMichael Jurka                    final ViewTreeObserver observer = getViewTreeObserver();
16599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                    if (observer.isAlive()) {
16699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                        observer.removeOnGlobalLayoutListener(this);
16799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                    }
16899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                }
16999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            };
170841594b2dbb4445ea84d9c9d617d5db3a28bb04bMichael Jurka        getViewTreeObserver().addOnGlobalLayoutListener(updateScroll);
1719f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
1729f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
1739f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    @Override
174c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller    public void removeViewInLayout(final View view) {
17507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        dismissChild(view);
176c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller    }
177c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller
1789f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    public boolean onInterceptTouchEvent(MotionEvent ev) {
179c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller        if (DEBUG) Log.v(TAG, "onInterceptTouchEvent()");
18007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        return mSwipeHelper.onInterceptTouchEvent(ev) ||
18107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            super.onInterceptTouchEvent(ev);
1829f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
1839f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
1849f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    @Override
1859f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    public boolean onTouchEvent(MotionEvent ev) {
18607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        return mSwipeHelper.onTouchEvent(ev) ||
18707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            super.onTouchEvent(ev);
18807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
1899f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
19007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    public boolean canChildBeDismissed(View v) {
19107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        return true;
19207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
1939f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
19419c8c708f16546fc75ae12659aa190f5e3dfbb52Selim Cinek    @Override
19519c8c708f16546fc75ae12659aa190f5e3dfbb52Selim Cinek    public boolean isAntiFalsingNeeded() {
19619c8c708f16546fc75ae12659aa190f5e3dfbb52Selim Cinek        return false;
19719c8c708f16546fc75ae12659aa190f5e3dfbb52Selim Cinek    }
19819c8c708f16546fc75ae12659aa190f5e3dfbb52Selim Cinek
19934cf5c4bfc7c4918b8155c47eb905782902016d6Selim Cinek    @Override
20034cf5c4bfc7c4918b8155c47eb905782902016d6Selim Cinek    public float getFalsingThresholdFactor() {
20134cf5c4bfc7c4918b8155c47eb905782902016d6Selim Cinek        return 1.0f;
20234cf5c4bfc7c4918b8155c47eb905782902016d6Selim Cinek    }
20334cf5c4bfc7c4918b8155c47eb905782902016d6Selim Cinek
20407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    public void dismissChild(View v) {
20507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        mSwipeHelper.dismissChild(v, 0);
20607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
2079f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
20807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    public void onChildDismissed(View v) {
209261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka        addToRecycledViews(v);
21007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        mLinearLayout.removeView(v);
21107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        mCallback.handleSwipe(v);
2122db72fce6cfc0081583b9726ad80a7d95e064891Michael Jurka        // Restore the alpha/translation parameters to what they were before swiping
2132db72fce6cfc0081583b9726ad80a7d95e064891Michael Jurka        // (for when these items are recycled)
2142db72fce6cfc0081583b9726ad80a7d95e064891Michael Jurka        View contentView = getChildContentView(v);
2152db72fce6cfc0081583b9726ad80a7d95e064891Michael Jurka        contentView.setAlpha(1f);
2162db72fce6cfc0081583b9726ad80a7d95e064891Michael Jurka        contentView.setTranslationY(0);
2179f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
2189f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
21907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    public void onBeginDrag(View v) {
22013451a476a1951a19d3cb531c47bf5a51587800aMichael Jurka        // We do this so the underlying ScrollView knows that it won't get
22113451a476a1951a19d3cb531c47bf5a51587800aMichael Jurka        // the chance to intercept events anymore
22213451a476a1951a19d3cb531c47bf5a51587800aMichael Jurka        requestDisallowInterceptTouchEvent(true);
223622a97646d316ca753c577752ac9010415e9a472Peter Ng    }
224622a97646d316ca753c577752ac9010415e9a472Peter Ng
225622a97646d316ca753c577752ac9010415e9a472Peter Ng    public void onDragCancelled(View v) {
226c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller    }
227c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller
228eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek    @Override
229eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek    public void onChildSnappedBack(View animView) {
230eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek    }
231eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek
2325d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos    @Override
2335d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos    public boolean updateSwipeProgress(View animView, boolean dismissable, float swipeProgress) {
2345d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos        return false;
2355d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos    }
2365d9cc668e16abf1306d82218cd3da29e28a454aeAdrian Roos
23707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    public View getChildAtPosition(MotionEvent ev) {
23807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        final float x = ev.getX() + getScrollX();
23907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        final float y = ev.getY() + getScrollY();
24007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
24107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            View item = mLinearLayout.getChildAt(i);
24207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka            if (x >= item.getLeft() && x < item.getRight()
24307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                && y >= item.getTop() && y < item.getBottom()) {
24407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka                return item;
2459f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            }
2469f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        }
24707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        return null;
24807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    }
24907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka
25007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka    public View getChildContentView(View v) {
2513cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        return v.findViewById(R.id.recent_item);
2523cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    }
2533cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
2543cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    @Override
2554a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka    public void drawFadedEdges(Canvas canvas, int left, int right, int top, int bottom) {
2564a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka        if (mFadedEdgeDrawHelper != null) {
2573cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
2584a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka            mFadedEdgeDrawHelper.drawCallback(canvas,
25901534780dfaf81c9f89a6e19fe2fe42cfdd01ff7John Spurlock                    left, right, top, bottom, getScrollX(), getScrollY(),
2603cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                    0, 0,
26101534780dfaf81c9f89a6e19fe2fe42cfdd01ff7John Spurlock                    getLeftFadingEdgeStrength(), getRightFadingEdgeStrength(), getPaddingTop());
2623cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        }
2633cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    }
2643cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
2653cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    @Override
2664a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
2674a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka       super.onScrollChanged(l, t, oldl, oldt);
2684a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka       if (mOnScrollListener != null) {
2694a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka           mOnScrollListener.run();
2704a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka       }
2714a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka    }
2724a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka
2734a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka    public void setOnScrollListener(Runnable listener) {
2744a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka        mOnScrollListener = listener;
2754a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka    }
2764a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka
2774a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka    @Override
2783cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    public int getVerticalFadingEdgeLength() {
2794a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka        if (mFadedEdgeDrawHelper != null) {
2804a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka            return mFadedEdgeDrawHelper.getVerticalFadingEdgeLength();
2813cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        } else {
2823cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            return super.getVerticalFadingEdgeLength();
2833cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        }
2843cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    }
2853cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
2863cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    @Override
2873cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    public int getHorizontalFadingEdgeLength() {
2884a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka        if (mFadedEdgeDrawHelper != null) {
2894a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka            return mFadedEdgeDrawHelper.getHorizontalFadingEdgeLength();
2903cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        } else {
2913cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            return super.getHorizontalFadingEdgeLength();
2923cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        }
2939f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
2949f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
2959f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    @Override
2969f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    protected void onFinishInflate() {
2979f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        super.onFinishInflate();
2989f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        setScrollbarFadingEnabled(true);
2999f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        mLinearLayout = (LinearLayout) findViewById(R.id.recents_linear_layout);
30001534780dfaf81c9f89a6e19fe2fe42cfdd01ff7John Spurlock        final int leftPadding = getContext().getResources()
3019f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            .getDimensionPixelOffset(R.dimen.status_bar_recents_thumbnail_left_margin);
3029f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        setOverScrollEffectPadding(leftPadding, 0);
3039f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
3049f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
3053c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller    @Override
3063cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    public void onAttachedToWindow() {
3074a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka        if (mFadedEdgeDrawHelper != null) {
3084a6bc55cd5b2e1fdd04347813842d5bce64ee3feMichael Jurka            mFadedEdgeDrawHelper.onAttachedToWindowCallback(mLinearLayout, isHardwareAccelerated());
3093cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        }
3103cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    }
3113cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
3123cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    @Override
3133c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller    protected void onConfigurationChanged(Configuration newConfig) {
3143c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller        super.onConfigurationChanged(newConfig);
31507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        float densityScale = getResources().getDisplayMetrics().density;
31607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        mSwipeHelper.setDensityScale(densityScale);
31701534780dfaf81c9f89a6e19fe2fe42cfdd01ff7John Spurlock        float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
31807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka        mSwipeHelper.setPagingTouchSlop(pagingTouchSlop);
3193c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller    }
3203c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller
3219f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    private void setOverScrollEffectPadding(int leftPadding, int i) {
3223c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller        // TODO Add to (Vertical)ScrollView
3239f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
3249f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
3259f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    @Override
3269f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
3279f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        super.onSizeChanged(w, h, oldw, oldh);
32881abe87dcc829c4c01473126c8664aa03385dc7cChet Haase
32981abe87dcc829c4c01473126c8664aa03385dc7cChet Haase        // Skip this work if a transition is running; it sets the scroll values independently
33081abe87dcc829c4c01473126c8664aa03385dc7cChet Haase        // and should not have those animated values clobbered by this logic
33181abe87dcc829c4c01473126c8664aa03385dc7cChet Haase        LayoutTransition transition = mLinearLayout.getLayoutTransition();
33281abe87dcc829c4c01473126c8664aa03385dc7cChet Haase        if (transition != null && transition.isRunning()) {
33381abe87dcc829c4c01473126c8664aa03385dc7cChet Haase            return;
33481abe87dcc829c4c01473126c8664aa03385dc7cChet Haase        }
3359f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        // Keep track of the last visible item in the list so we can restore it
3369f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        // to the bottom when the orientation changes.
3379f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        mLastScrollPosition = scrollPositionOfMostRecent();
3389f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
3399f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        // This has to happen post-layout, so run it "in the future"
3409f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        post(new Runnable() {
3419f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            public void run() {
34281abe87dcc829c4c01473126c8664aa03385dc7cChet Haase                // Make sure we're still not clobbering the transition-set values, since this
34381abe87dcc829c4c01473126c8664aa03385dc7cChet Haase                // runnable launches asynchronously
34481abe87dcc829c4c01473126c8664aa03385dc7cChet Haase                LayoutTransition transition = mLinearLayout.getLayoutTransition();
34581abe87dcc829c4c01473126c8664aa03385dc7cChet Haase                if (transition == null || !transition.isRunning()) {
34681abe87dcc829c4c01473126c8664aa03385dc7cChet Haase                    scrollTo(mLastScrollPosition, 0);
34781abe87dcc829c4c01473126c8664aa03385dc7cChet Haase                }
3489f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            }
3499f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        });
3509f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
3519f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
352ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka    public void setAdapter(TaskDescriptionAdapter adapter) {
3539f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        mAdapter = adapter;
3549f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        mAdapter.registerDataSetObserver(new DataSetObserver() {
3559f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            public void onChanged() {
3569f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                update();
3579f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            }
3589f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
3599f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            public void onInvalidated() {
3609f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller                update();
3619f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller            }
3629f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        });
36399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        DisplayMetrics dm = getResources().getDisplayMetrics();
36499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        int childWidthMeasureSpec =
36599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                MeasureSpec.makeMeasureSpec(dm.widthPixels, MeasureSpec.AT_MOST);
36699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        int childheightMeasureSpec =
36799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                MeasureSpec.makeMeasureSpec(dm.heightPixels, MeasureSpec.AT_MOST);
36899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        View child = mAdapter.createView(mLinearLayout);
36999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        child.measure(childWidthMeasureSpec, childheightMeasureSpec);
37099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        mNumItemsInOneScreenful =
37199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                (int) FloatMath.ceil(dm.widthPixels / (float) child.getMeasuredWidth());
372261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka        addToRecycledViews(child);
37399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka
37499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        for (int i = 0; i < mNumItemsInOneScreenful - 1; i++) {
375261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka            addToRecycledViews(mAdapter.createView(mLinearLayout));
37699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        }
37799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka    }
37899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka
37999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka    public int numItemsInOneScreenful() {
38099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        return mNumItemsInOneScreenful;
3819f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
3829f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
3839f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    @Override
3849f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    public void setLayoutTransition(LayoutTransition transition) {
3859f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        // The layout transition applies to our embedded LinearLayout
3869f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        mLinearLayout.setLayoutTransition(transition);
3879f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
3889f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller
3899f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    public void setCallback(RecentsCallback callback) {
3909f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller        mCallback = callback;
3919f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller    }
3929f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller}
393