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; 523cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka private RecentsScrollViewPerformanceHelper mPerformanceHelper; 53d1a040c3e1dc30b26f4dfee8c9de2c802ac134b8Michael Jurka private HashSet<View> mRecycledViews; 5499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka private int mNumItemsInOneScreenful; 553cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka 569f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller public RecentsHorizontalScrollView(Context context, AttributeSet attrs) { 579f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller super(context, attrs, 0); 5807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka float densityScale = getResources().getDisplayMetrics().density; 5907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop(); 6007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mSwipeHelper = new SwipeHelper(SwipeHelper.Y, this, densityScale, pagingTouchSlop); 613cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka mPerformanceHelper = RecentsScrollViewPerformanceHelper.create(context, attrs, this, false); 62d1a040c3e1dc30b26f4dfee8c9de2c802ac134b8Michael Jurka mRecycledViews = new HashSet<View>(); 639f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 649f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 654eaa983f253d0215d4de777edd8616318610ea22Michael Jurka public void setMinSwipeAlpha(float minAlpha) { 664eaa983f253d0215d4de777edd8616318610ea22Michael Jurka mSwipeHelper.setMinAlpha(minAlpha); 674eaa983f253d0215d4de777edd8616318610ea22Michael Jurka } 684eaa983f253d0215d4de777edd8616318610ea22Michael Jurka 699f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller private int scrollPositionOfMostRecent() { 709f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller return mLinearLayout.getWidth() - getWidth(); 719f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 729f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 73261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka private void addToRecycledViews(View v) { 74261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka if (mRecycledViews.size() < mNumItemsInOneScreenful) { 75261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka mRecycledViews.add(v); 76261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka } 77261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka } 78261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka 79e5923631f06406f5f5e23a3a2ab4b24bb53a9094Michael Jurka public View findViewForTask(int persistentTaskId) { 80cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka for (int i = 0; i < mLinearLayout.getChildCount(); i++) { 81cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka View v = mLinearLayout.getChildAt(i); 82cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka RecentsPanelView.ViewHolder holder = (RecentsPanelView.ViewHolder) v.getTag(); 83e5923631f06406f5f5e23a3a2ab4b24bb53a9094Michael Jurka if (holder.taskDescription.persistentTaskId == persistentTaskId) { 84cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka return v; 85cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 86cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 87cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka return null; 88cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 89cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 90c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller private void update() { 9199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka for (int i = 0; i < mLinearLayout.getChildCount(); i++) { 9299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka View v = mLinearLayout.getChildAt(i); 93261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka addToRecycledViews(v); 9499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka mAdapter.recycleView(v); 9599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 9699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka LayoutTransition transitioner = getLayoutTransition(); 9799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka setLayoutTransition(null); 9899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka 999f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller mLinearLayout.removeAllViews(); 100d1a040c3e1dc30b26f4dfee8c9de2c802ac134b8Michael Jurka Iterator<View> recycledViews = mRecycledViews.iterator(); 1019f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller for (int i = 0; i < mAdapter.getCount(); i++) { 10299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka View old = null; 103d1a040c3e1dc30b26f4dfee8c9de2c802ac134b8Michael Jurka if (recycledViews.hasNext()) { 104d1a040c3e1dc30b26f4dfee8c9de2c802ac134b8Michael Jurka old = recycledViews.next(); 105d1a040c3e1dc30b26f4dfee8c9de2c802ac134b8Michael Jurka recycledViews.remove(); 10699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka old.setVisibility(VISIBLE); 10799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 10899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka 10999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka final View view = mAdapter.getView(i, old, mLinearLayout); 11007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 1113cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka if (mPerformanceHelper != null) { 1123cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka mPerformanceHelper.addViewCallback(view); 1133cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka } 1143cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka 1157daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka OnTouchListener noOpListener = new OnTouchListener() { 1167daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka @Override 1177daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka public boolean onTouch(View v, MotionEvent event) { 1187daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka return true; 1197daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka } 1207daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka }; 1217daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka 1227725a4e3071c6450deb89dcb1e234ed96142edc9Michael Jurka view.setOnClickListener(new OnClickListener() { 12307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public void onClick(View v) { 1247725a4e3071c6450deb89dcb1e234ed96142edc9Michael Jurka mCallback.dismiss(); 12507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 12607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka }); 1270e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka // We don't want a click sound when we dimiss recents 1280e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka view.setSoundEffectsEnabled(false); 1297725a4e3071c6450deb89dcb1e234ed96142edc9Michael Jurka 1307725a4e3071c6450deb89dcb1e234ed96142edc9Michael Jurka OnClickListener launchAppListener = new OnClickListener() { 1317725a4e3071c6450deb89dcb1e234ed96142edc9Michael Jurka public void onClick(View v) { 1327725a4e3071c6450deb89dcb1e234ed96142edc9Michael Jurka mCallback.handleOnClick(view); 1337725a4e3071c6450deb89dcb1e234ed96142edc9Michael Jurka } 1347725a4e3071c6450deb89dcb1e234ed96142edc9Michael Jurka }; 1357daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka 13699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka RecentsPanelView.ViewHolder holder = (RecentsPanelView.ViewHolder) view.getTag(); 13799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka final View thumbnailView = holder.thumbnailView; 1380e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka OnLongClickListener longClickListener = new OnLongClickListener() { 1390e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka public boolean onLongClick(View v) { 1400e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka final View anchorView = view.findViewById(R.id.app_description); 1410e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka mCallback.handleLongPress(view, anchorView, thumbnailView); 1420e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka return true; 1430e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka } 1440e8063a3b447e1aa5cc3171db42f735b3b6ae78eMichael Jurka }; 1457daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka thumbnailView.setClickable(true); 1467daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka thumbnailView.setOnClickListener(launchAppListener); 1477daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka thumbnailView.setOnLongClickListener(longClickListener); 1487daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka 1497daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka // We don't want to dismiss recents if a user clicks on the app title 1507daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka // (we also don't want to launch the app either, though, because the 1517daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka // app title is a small target and doesn't have great click feedback) 1527725a4e3071c6450deb89dcb1e234ed96142edc9Michael Jurka final View appTitle = view.findViewById(R.id.app_label); 1537daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka appTitle.setContentDescription(" "); 1547daf95d5526e3b60f5db29cbacd9a4852d99a6f4Michael Jurka appTitle.setOnTouchListener(noOpListener); 1559f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller mLinearLayout.addView(view); 1569f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 15799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka setLayoutTransition(transitioner); 15899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka 159841594b2dbb4445ea84d9c9d617d5db3a28bb04bMichael Jurka // Scroll to end after initial layout. 16099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka 16199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka final OnGlobalLayoutListener updateScroll = new OnGlobalLayoutListener() { 16299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka public void onGlobalLayout() { 16399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka mLastScrollPosition = scrollPositionOfMostRecent(); 16499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka scrollTo(mLastScrollPosition, 0); 165841594b2dbb4445ea84d9c9d617d5db3a28bb04bMichael Jurka final ViewTreeObserver observer = getViewTreeObserver(); 16699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka if (observer.isAlive()) { 16799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka observer.removeOnGlobalLayoutListener(this); 16899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 16999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 17099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka }; 171841594b2dbb4445ea84d9c9d617d5db3a28bb04bMichael Jurka getViewTreeObserver().addOnGlobalLayoutListener(updateScroll); 1729f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 1739f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 1749f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller @Override 175c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller public void removeViewInLayout(final View view) { 17607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka dismissChild(view); 177c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller } 178c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller 1799f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller public boolean onInterceptTouchEvent(MotionEvent ev) { 180c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller if (DEBUG) Log.v(TAG, "onInterceptTouchEvent()"); 18107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka return mSwipeHelper.onInterceptTouchEvent(ev) || 18207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka super.onInterceptTouchEvent(ev); 1839f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 1849f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 1859f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller @Override 1869f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller public boolean onTouchEvent(MotionEvent ev) { 18707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka return mSwipeHelper.onTouchEvent(ev) || 18807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka super.onTouchEvent(ev); 18907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 1909f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 19107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public boolean canChildBeDismissed(View v) { 19207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka return true; 19307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 1949f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 19507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public void dismissChild(View v) { 19607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mSwipeHelper.dismissChild(v, 0); 19707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 1989f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 19907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public void onChildDismissed(View v) { 200261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka addToRecycledViews(v); 20107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mLinearLayout.removeView(v); 20207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mCallback.handleSwipe(v); 2032db72fce6cfc0081583b9726ad80a7d95e064891Michael Jurka // Restore the alpha/translation parameters to what they were before swiping 2042db72fce6cfc0081583b9726ad80a7d95e064891Michael Jurka // (for when these items are recycled) 2052db72fce6cfc0081583b9726ad80a7d95e064891Michael Jurka View contentView = getChildContentView(v); 2062db72fce6cfc0081583b9726ad80a7d95e064891Michael Jurka contentView.setAlpha(1f); 2072db72fce6cfc0081583b9726ad80a7d95e064891Michael Jurka contentView.setTranslationY(0); 2089f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 2099f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 21007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public void onBeginDrag(View v) { 21113451a476a1951a19d3cb531c47bf5a51587800aMichael Jurka // We do this so the underlying ScrollView knows that it won't get 21213451a476a1951a19d3cb531c47bf5a51587800aMichael Jurka // the chance to intercept events anymore 21313451a476a1951a19d3cb531c47bf5a51587800aMichael Jurka requestDisallowInterceptTouchEvent(true); 214622a97646d316ca753c577752ac9010415e9a472Peter Ng } 215622a97646d316ca753c577752ac9010415e9a472Peter Ng 216622a97646d316ca753c577752ac9010415e9a472Peter Ng public void onDragCancelled(View v) { 217c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller } 218c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller 21907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public View getChildAtPosition(MotionEvent ev) { 22007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka final float x = ev.getX() + getScrollX(); 22107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka final float y = ev.getY() + getScrollY(); 22207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka for (int i = 0; i < mLinearLayout.getChildCount(); i++) { 22307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka View item = mLinearLayout.getChildAt(i); 22407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka if (x >= item.getLeft() && x < item.getRight() 22507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka && y >= item.getTop() && y < item.getBottom()) { 22607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka return item; 2279f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 2289f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 22907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka return null; 23007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 23107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 23207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public View getChildContentView(View v) { 2333cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka return v.findViewById(R.id.recent_item); 2343cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka } 2353cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka 2363cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka @Override 2373cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka public void draw(Canvas canvas) { 2383cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka super.draw(canvas); 2393cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka 2403cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka if (mPerformanceHelper != null) { 2413cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka int paddingLeft = mPaddingLeft; 2423cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka final boolean offsetRequired = isPaddingOffsetRequired(); 2433cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka if (offsetRequired) { 2443cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka paddingLeft += getLeftPaddingOffset(); 2453cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka } 2463cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka 2473cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka int left = mScrollX + paddingLeft; 2483cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka int right = left + mRight - mLeft - mPaddingRight - paddingLeft; 2493cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka int top = mScrollY + getFadeTop(offsetRequired); 2503cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka int bottom = top + getFadeHeight(offsetRequired); 2513cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka 2523cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka if (offsetRequired) { 2533cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka right += getRightPaddingOffset(); 2543cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka bottom += getBottomPaddingOffset(); 2553cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka } 2563cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka mPerformanceHelper.drawCallback(canvas, 2573cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka left, right, top, bottom, mScrollX, mScrollY, 2583cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka 0, 0, 25931a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka getLeftFadingEdgeStrength(), getRightFadingEdgeStrength(), mPaddingTop); 2603cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka } 2613cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka } 2623cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka 2633cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka @Override 2643cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka public int getVerticalFadingEdgeLength() { 2653cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka if (mPerformanceHelper != null) { 2663cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka return mPerformanceHelper.getVerticalFadingEdgeLengthCallback(); 2673cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka } else { 2683cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka return super.getVerticalFadingEdgeLength(); 2693cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka } 2703cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka } 2713cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka 2723cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka @Override 2733cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka public int getHorizontalFadingEdgeLength() { 2743cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka if (mPerformanceHelper != null) { 2753cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka return mPerformanceHelper.getHorizontalFadingEdgeLengthCallback(); 2763cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka } else { 2773cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka return super.getHorizontalFadingEdgeLength(); 2783cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka } 2799f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 2809f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 2819f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller @Override 2829f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller protected void onFinishInflate() { 2839f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller super.onFinishInflate(); 2849f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller setScrollbarFadingEnabled(true); 2859f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller mLinearLayout = (LinearLayout) findViewById(R.id.recents_linear_layout); 2869f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller final int leftPadding = mContext.getResources() 2879f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller .getDimensionPixelOffset(R.dimen.status_bar_recents_thumbnail_left_margin); 2889f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller setOverScrollEffectPadding(leftPadding, 0); 2899f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 2909f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 2913c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller @Override 2923cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka public void onAttachedToWindow() { 2933cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka if (mPerformanceHelper != null) { 2943cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka mPerformanceHelper.onAttachedToWindowCallback( 2953cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka mCallback, mLinearLayout, isHardwareAccelerated()); 2963cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka } 2973cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka } 2983cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka 2993cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka @Override 3003c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller protected void onConfigurationChanged(Configuration newConfig) { 3013c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller super.onConfigurationChanged(newConfig); 30207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka float densityScale = getResources().getDisplayMetrics().density; 30307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mSwipeHelper.setDensityScale(densityScale); 30407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop(); 30507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mSwipeHelper.setPagingTouchSlop(pagingTouchSlop); 3063c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller } 3073c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller 3089f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller private void setOverScrollEffectPadding(int leftPadding, int i) { 3093c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller // TODO Add to (Vertical)ScrollView 3109f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 3119f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 3129f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller @Override 3139f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller protected void onSizeChanged(int w, int h, int oldw, int oldh) { 3149f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller super.onSizeChanged(w, h, oldw, oldh); 31581abe87dcc829c4c01473126c8664aa03385dc7cChet Haase 31681abe87dcc829c4c01473126c8664aa03385dc7cChet Haase // Skip this work if a transition is running; it sets the scroll values independently 31781abe87dcc829c4c01473126c8664aa03385dc7cChet Haase // and should not have those animated values clobbered by this logic 31881abe87dcc829c4c01473126c8664aa03385dc7cChet Haase LayoutTransition transition = mLinearLayout.getLayoutTransition(); 31981abe87dcc829c4c01473126c8664aa03385dc7cChet Haase if (transition != null && transition.isRunning()) { 32081abe87dcc829c4c01473126c8664aa03385dc7cChet Haase return; 32181abe87dcc829c4c01473126c8664aa03385dc7cChet Haase } 3229f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller // Keep track of the last visible item in the list so we can restore it 3239f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller // to the bottom when the orientation changes. 3249f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller mLastScrollPosition = scrollPositionOfMostRecent(); 3259f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 3269f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller // This has to happen post-layout, so run it "in the future" 3279f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller post(new Runnable() { 3289f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller public void run() { 32981abe87dcc829c4c01473126c8664aa03385dc7cChet Haase // Make sure we're still not clobbering the transition-set values, since this 33081abe87dcc829c4c01473126c8664aa03385dc7cChet Haase // runnable launches asynchronously 33181abe87dcc829c4c01473126c8664aa03385dc7cChet Haase LayoutTransition transition = mLinearLayout.getLayoutTransition(); 33281abe87dcc829c4c01473126c8664aa03385dc7cChet Haase if (transition == null || !transition.isRunning()) { 33381abe87dcc829c4c01473126c8664aa03385dc7cChet Haase scrollTo(mLastScrollPosition, 0); 33481abe87dcc829c4c01473126c8664aa03385dc7cChet Haase } 3359f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 3369f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller }); 3379f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 3389f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 339ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka public void setAdapter(TaskDescriptionAdapter adapter) { 3409f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller mAdapter = adapter; 3419f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller mAdapter.registerDataSetObserver(new DataSetObserver() { 3429f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller public void onChanged() { 3439f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller update(); 3449f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 3459f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 3469f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller public void onInvalidated() { 3479f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller update(); 3489f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 3499f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller }); 35099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka DisplayMetrics dm = getResources().getDisplayMetrics(); 35199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka int childWidthMeasureSpec = 35299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka MeasureSpec.makeMeasureSpec(dm.widthPixels, MeasureSpec.AT_MOST); 35399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka int childheightMeasureSpec = 35499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka MeasureSpec.makeMeasureSpec(dm.heightPixels, MeasureSpec.AT_MOST); 35599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka View child = mAdapter.createView(mLinearLayout); 35699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka child.measure(childWidthMeasureSpec, childheightMeasureSpec); 35799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka mNumItemsInOneScreenful = 35899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka (int) FloatMath.ceil(dm.widthPixels / (float) child.getMeasuredWidth()); 359261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka addToRecycledViews(child); 36099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka 36199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka for (int i = 0; i < mNumItemsInOneScreenful - 1; i++) { 362261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka addToRecycledViews(mAdapter.createView(mLinearLayout)); 36399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 36499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 36599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka 36699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka public int numItemsInOneScreenful() { 36799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka return mNumItemsInOneScreenful; 3689f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 3699f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 3709f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller @Override 3719f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller public void setLayoutTransition(LayoutTransition transition) { 3729f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller // The layout transition applies to our embedded LinearLayout 3739f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller mLinearLayout.setLayoutTransition(transition); 3749f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 3759f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 3769f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller public void setCallback(RecentsCallback callback) { 3779f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller mCallback = callback; 3789f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 3799f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller} 380