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