RecentsVerticalScrollView.java revision 07d4046ea914c999b7aaa587b7bfe81d548121f7
1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.systemui.recent; 18 19import android.animation.LayoutTransition; 20import android.content.Context; 21import android.content.res.Configuration; 22import android.database.DataSetObserver; 23import android.util.AttributeSet; 24import android.util.Log; 25import android.view.MotionEvent; 26import android.view.View; 27import android.view.ViewConfiguration; 28import android.widget.LinearLayout; 29import android.widget.ScrollView; 30 31import com.android.systemui.R; 32import com.android.systemui.SwipeHelper; 33import com.android.systemui.recent.RecentsPanelView.ActivityDescriptionAdapter; 34 35public class RecentsVerticalScrollView extends ScrollView implements SwipeHelper.Callback { 36 private static final String TAG = RecentsPanelView.TAG; 37 private static final boolean DEBUG = RecentsPanelView.DEBUG; 38 private LinearLayout mLinearLayout; 39 private ActivityDescriptionAdapter mAdapter; 40 private RecentsCallback mCallback; 41 protected int mLastScrollPosition; 42 private SwipeHelper mSwipeHelper; 43 44 private OnLongClickListener mOnLongClick = new OnLongClickListener() { 45 public boolean onLongClick(View v) { 46 final View anchorView = v.findViewById(R.id.app_description); 47 mCallback.handleLongPress(v, anchorView); 48 return true; 49 } 50 }; 51 52 public RecentsVerticalScrollView(Context context) { 53 this(context, null); 54 } 55 56 public RecentsVerticalScrollView(Context context, AttributeSet attrs) { 57 super(context, attrs, 0); 58 float densityScale = getResources().getDisplayMetrics().density; 59 float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop(); 60 mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop); 61 } 62 63 private int scrollPositionOfMostRecent() { 64 return mLinearLayout.getHeight() - getHeight(); 65 } 66 67 private void update() { 68 mLinearLayout.removeAllViews(); 69 for (int i = 0; i < mAdapter.getCount(); i++) { 70 final View view = mAdapter.getView(i, null, mLinearLayout); 71 view.setClickable(true); 72 view.setOnLongClickListener(mOnLongClick); 73 74 final View thumbnail = getChildContentView(view); 75 // thumbnail is set to clickable in the layout file 76 thumbnail.setOnClickListener(new OnClickListener() { 77 public void onClick(View v) { 78 mCallback.handleOnClick(view); 79 } 80 }); 81 82 mLinearLayout.addView(view); 83 } 84 // Scroll to end after layout. 85 post(new Runnable() { 86 public void run() { 87 mLastScrollPosition = scrollPositionOfMostRecent(); 88 scrollTo(0, mLastScrollPosition); 89 } 90 }); 91 } 92 93 @Override 94 public void removeViewInLayout(final View view) { 95 dismissChild(view); 96 } 97 98 public boolean onInterceptTouchEvent(MotionEvent ev) { 99 if (DEBUG) Log.v(TAG, "onInterceptTouchEvent()"); 100 return mSwipeHelper.onInterceptTouchEvent(ev) || 101 super.onInterceptTouchEvent(ev); 102 } 103 104 @Override 105 public boolean onTouchEvent(MotionEvent ev) { 106 return mSwipeHelper.onTouchEvent(ev) || 107 super.onTouchEvent(ev); 108 } 109 110 public boolean canChildBeDismissed(View v) { 111 return true; 112 } 113 114 public void dismissChild(View v) { 115 mSwipeHelper.dismissChild(v, 0); 116 } 117 118 public void onChildDismissed(View v) { 119 mLinearLayout.removeView(v); 120 mCallback.handleSwipe(v); 121 } 122 123 public void onBeginDrag(View v) { 124 } 125 126 public View getChildAtPosition(MotionEvent ev) { 127 final float x = ev.getX() + getScrollX(); 128 final float y = ev.getY() + getScrollY(); 129 for (int i = 0; i < mLinearLayout.getChildCount(); i++) { 130 View item = mLinearLayout.getChildAt(i); 131 if (x >= item.getLeft() && x < item.getRight() 132 && y >= item.getTop() && y < item.getBottom()) { 133 return item; 134 } 135 } 136 return null; 137 } 138 139 public View getChildContentView(View v) { 140 return v.findViewById(R.id.app_thumbnail); 141 } 142 143 @Override 144 protected void onFinishInflate() { 145 super.onFinishInflate(); 146 setScrollbarFadingEnabled(true); 147 mLinearLayout = (LinearLayout) findViewById(R.id.recents_linear_layout); 148 final int leftPadding = mContext.getResources() 149 .getDimensionPixelOffset(R.dimen.status_bar_recents_thumbnail_left_margin); 150 setOverScrollEffectPadding(leftPadding, 0); 151 } 152 153 @Override 154 protected void onConfigurationChanged(Configuration newConfig) { 155 super.onConfigurationChanged(newConfig); 156 float densityScale = getResources().getDisplayMetrics().density; 157 mSwipeHelper.setDensityScale(densityScale); 158 float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop(); 159 mSwipeHelper.setPagingTouchSlop(pagingTouchSlop); 160 } 161 162 private void setOverScrollEffectPadding(int leftPadding, int i) { 163 // TODO Add to (Vertical)ScrollView 164 } 165 166 @Override 167 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 168 super.onSizeChanged(w, h, oldw, oldh); 169 // Keep track of the last visible item in the list so we can restore it 170 // to the bottom when the orientation changes. 171 mLastScrollPosition = scrollPositionOfMostRecent(); 172 173 // This has to happen post-layout, so run it "in the future" 174 post(new Runnable() { 175 public void run() { 176 scrollTo(0, mLastScrollPosition); 177 } 178 }); 179 } 180 181 @Override 182 protected void onVisibilityChanged(View changedView, int visibility) { 183 super.onVisibilityChanged(changedView, visibility); 184 // scroll to bottom after reloading 185 if (visibility == View.VISIBLE && changedView == this) { 186 post(new Runnable() { 187 public void run() { 188 update(); 189 } 190 }); 191 } 192 } 193 194 public void setAdapter(ActivityDescriptionAdapter adapter) { 195 mAdapter = adapter; 196 mAdapter.registerDataSetObserver(new DataSetObserver() { 197 public void onChanged() { 198 update(); 199 } 200 201 public void onInvalidated() { 202 update(); 203 } 204 }); 205 } 206 207 @Override 208 public void setLayoutTransition(LayoutTransition transition) { 209 // The layout transition applies to our embedded LinearLayout 210 mLinearLayout.setLayoutTransition(transition); 211 } 212 213 public void setCallback(RecentsCallback callback) { 214 mCallback = callback; 215 } 216} 217