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