RecentsHorizontalScrollView.java revision 07d4046ea914c999b7aaa587b7bfe81d548121f7
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; 239f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.util.AttributeSet; 249f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.util.Log; 259f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.view.MotionEvent; 269f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.view.View; 273c728fe61dcf49354ea761a3e4ef6032ec271630Jim Millerimport android.view.ViewConfiguration; 289f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.widget.HorizontalScrollView; 299f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport android.widget.LinearLayout; 309f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 319f0f0e0e3100caec459a5b5ef836317844c83b3fJim Millerimport com.android.systemui.R; 3207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport com.android.systemui.SwipeHelper; 3307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport com.android.systemui.recent.RecentsPanelView.ActivityDescriptionAdapter; 349f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 3507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkapublic class RecentsHorizontalScrollView extends HorizontalScrollView 3607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka implements SwipeHelper.Callback { 373c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller private static final String TAG = RecentsPanelView.TAG; 383c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller private static final boolean DEBUG = RecentsPanelView.DEBUG; 399f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller private LinearLayout mLinearLayout; 403b1fc47d004f6b29af8f40d181baa3460b1e3b15Michael Jurka private ActivityDescriptionAdapter mAdapter; 419f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller private RecentsCallback mCallback; 429f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller protected int mLastScrollPosition; 4307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private SwipeHelper mSwipeHelper; 44c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller private OnLongClickListener mOnLongClick = new OnLongClickListener() { 45c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller public boolean onLongClick(View v) { 46c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller final View anchorView = v.findViewById(R.id.app_description); 47c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller mCallback.handleLongPress(v, anchorView); 48c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller return true; 49c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller } 50c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller }; 519f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 529f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller public RecentsHorizontalScrollView(Context context) { 539f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller this(context, null); 549f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 559f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 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); 619f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 629f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 639f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller private int scrollPositionOfMostRecent() { 649f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller return mLinearLayout.getWidth() - getWidth(); 659f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 669f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 67c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller private void update() { 689f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller mLinearLayout.removeAllViews(); 699f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller for (int i = 0; i < mAdapter.getCount(); i++) { 70c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller final View view = mAdapter.getView(i, null, mLinearLayout); 7107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka view.setLongClickable(true); 72c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller view.setOnLongClickListener(mOnLongClick); 7307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 7407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka final View thumbnail = getChildContentView(view); 7507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka // thumbnail is set to clickable in the layout file 7607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka thumbnail.setOnClickListener(new OnClickListener() { 7707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public void onClick(View v) { 7807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mCallback.handleOnClick(view); 7907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 8007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka }); 819f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller mLinearLayout.addView(view); 829f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 839f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller // Scroll to end after layout. 849f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller post(new Runnable() { 859f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller public void run() { 869f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller mLastScrollPosition = scrollPositionOfMostRecent(); 879f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller scrollTo(mLastScrollPosition, 0); 889f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 899f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller }); 909f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 919f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 929f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller @Override 93c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller public void removeViewInLayout(final View view) { 9407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka dismissChild(view); 95c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller } 96c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller 979f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller public boolean onInterceptTouchEvent(MotionEvent ev) { 98c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller if (DEBUG) Log.v(TAG, "onInterceptTouchEvent()"); 9907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka return mSwipeHelper.onInterceptTouchEvent(ev) || 10007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka super.onInterceptTouchEvent(ev); 1019f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 1029f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 1039f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller @Override 1049f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller public boolean onTouchEvent(MotionEvent ev) { 10507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka return mSwipeHelper.onTouchEvent(ev) || 10607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka super.onTouchEvent(ev); 10707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 1089f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 10907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public boolean canChildBeDismissed(View v) { 11007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka return true; 11107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 1129f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 11307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public void dismissChild(View v) { 11407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mSwipeHelper.dismissChild(v, 0); 11507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 1169f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 11707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public void onChildDismissed(View v) { 11807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mLinearLayout.removeView(v); 11907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mCallback.handleSwipe(v); 1209f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 1219f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 12207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public void onBeginDrag(View v) { 123c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller } 124c0d2731047e2da4eff84a40615e29e08dcb708c5Jim Miller 12507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public View getChildAtPosition(MotionEvent ev) { 12607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka final float x = ev.getX() + getScrollX(); 12707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka final float y = ev.getY() + getScrollY(); 12807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka for (int i = 0; i < mLinearLayout.getChildCount(); i++) { 12907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka View item = mLinearLayout.getChildAt(i); 13007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka if (x >= item.getLeft() && x < item.getRight() 13107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka && y >= item.getTop() && y < item.getBottom()) { 13207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka return item; 1339f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 1349f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 13507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka return null; 13607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 13707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 13807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public View getChildContentView(View v) { 13907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka return v.findViewById(R.id.app_thumbnail); 1409f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 1419f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 1429f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller @Override 1439f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller protected void onFinishInflate() { 1449f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller super.onFinishInflate(); 1459f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller setScrollbarFadingEnabled(true); 1469f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller mLinearLayout = (LinearLayout) findViewById(R.id.recents_linear_layout); 1479f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller final int leftPadding = mContext.getResources() 1489f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller .getDimensionPixelOffset(R.dimen.status_bar_recents_thumbnail_left_margin); 1499f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller setOverScrollEffectPadding(leftPadding, 0); 1509f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 1519f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 1523c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller @Override 1533c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller protected void onConfigurationChanged(Configuration newConfig) { 1543c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller super.onConfigurationChanged(newConfig); 15507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka float densityScale = getResources().getDisplayMetrics().density; 15607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mSwipeHelper.setDensityScale(densityScale); 15707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop(); 15807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mSwipeHelper.setPagingTouchSlop(pagingTouchSlop); 1593c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller } 1603c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller 1619f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller private void setOverScrollEffectPadding(int leftPadding, int i) { 1623c728fe61dcf49354ea761a3e4ef6032ec271630Jim Miller // TODO Add to (Vertical)ScrollView 1639f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 1649f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 1659f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller @Override 1669f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller protected void onSizeChanged(int w, int h, int oldw, int oldh) { 1679f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller super.onSizeChanged(w, h, oldw, oldh); 1689f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller // Keep track of the last visible item in the list so we can restore it 1699f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller // to the bottom when the orientation changes. 1709f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller mLastScrollPosition = scrollPositionOfMostRecent(); 1719f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 1729f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller // This has to happen post-layout, so run it "in the future" 1739f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller post(new Runnable() { 1749f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller public void run() { 17517dfec7111fcc53a4f6ae6e92b4a7f85a278fe71Jim Miller scrollTo(mLastScrollPosition, 0); 1769f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 1779f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller }); 1789f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 1799f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 1809f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller @Override 1819f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller protected void onVisibilityChanged(View changedView, int visibility) { 1829f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller super.onVisibilityChanged(changedView, visibility); 1839f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller // scroll to bottom after reloading 1849f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller if (visibility == View.VISIBLE && changedView == this) { 1859f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller post(new Runnable() { 1869f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller public void run() { 1879f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller update(); 1889f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 1899f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller }); 1909f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 1919f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 1929f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 1933b1fc47d004f6b29af8f40d181baa3460b1e3b15Michael Jurka public void setAdapter(ActivityDescriptionAdapter adapter) { 1949f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller mAdapter = adapter; 1959f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller mAdapter.registerDataSetObserver(new DataSetObserver() { 1969f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller public void onChanged() { 1979f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller update(); 1989f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 1999f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 2009f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller public void onInvalidated() { 2019f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller update(); 2029f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 2039f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller }); 2049f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 2059f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 2069f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller @Override 2079f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller public void setLayoutTransition(LayoutTransition transition) { 2089f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller // The layout transition applies to our embedded LinearLayout 2099f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller mLinearLayout.setLayoutTransition(transition); 2109f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 2119f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller 2129f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller public void setCallback(RecentsCallback callback) { 2139f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller mCallback = callback; 2149f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller } 2159f0f0e0e3100caec459a5b5ef836317844c83b3fJim Miller} 216