blob: c64b9546fdaa70ead66372449e59e5b79e6bb117 [file] [log] [blame]
Jim Miller44c66fe2010-10-20 18:32:52 -07001/*
Jim Miller9f0f0e02011-05-17 20:06:29 -07002 * Copyright (C) 2011 The Android Open Source Project
Jim Miller44c66fe2010-10-20 18:32:52 -07003 *
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
Jim Miller9f0f0e02011-05-17 20:06:29 -070017package com.android.systemui.recent;
Jim Miller44c66fe2010-10-20 18:32:52 -070018
Michael Jurka3b1fc472011-06-13 10:54:40 -070019import android.animation.Animator;
Jim Miller9f0f0e02011-05-17 20:06:29 -070020import android.animation.LayoutTransition;
Michael Jurka9bdaada2012-10-01 13:58:29 +020021import android.animation.TimeInterpolator;
Jim Miller44c66fe2010-10-20 18:32:52 -070022import android.app.ActivityManager;
Michael Jurka56a57832012-05-14 13:24:43 -070023import android.app.ActivityManagerNative;
Dianne Hackborn8078d8c2012-03-20 11:11:26 -070024import android.app.ActivityOptions;
Adam Powell0fc5b2b2012-07-18 18:20:29 -070025import android.app.TaskStackBuilder;
Jim Miller44c66fe2010-10-20 18:32:52 -070026import android.content.Context;
27import android.content.Intent;
Michael Jurka9bdaada2012-10-01 13:58:29 +020028import android.content.res.Configuration;
Michael Jurkabfd24ac2011-11-13 13:50:38 -080029import android.content.res.Resources;
Daniel Sandler4a066c52012-04-20 14:49:13 -040030import android.content.res.TypedArray;
Jim Miller44c66fe2010-10-20 18:32:52 -070031import android.graphics.Bitmap;
Jim Millerfefef312010-11-09 14:08:39 -080032import android.graphics.Matrix;
Jim Millere5c16ab2010-12-03 19:18:38 -080033import android.graphics.Shader.TileMode;
34import android.graphics.drawable.BitmapDrawable;
Michael Jurka99a96552012-01-27 17:23:38 -080035import android.graphics.drawable.Drawable;
Jim Millerc0d27312011-07-14 18:54:01 -070036import android.net.Uri;
Michael Jurka482f1592012-09-13 11:05:59 -070037import android.os.Bundle;
Michael Jurka56a57832012-05-14 13:24:43 -070038import android.os.RemoteException;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070039import android.os.UserHandle;
Jim Millerc0d27312011-07-14 18:54:01 -070040import android.provider.Settings;
Jim Miller44c66fe2010-10-20 18:32:52 -070041import android.util.AttributeSet;
42import android.util.Log;
Jim Miller5fda69c2011-02-16 15:17:11 -080043import android.view.LayoutInflater;
Jim Millerc0d27312011-07-14 18:54:01 -070044import android.view.MenuItem;
Svetoslav Ganov6179ea32011-06-28 01:12:41 -070045import android.view.MotionEvent;
Jim Miller44c66fe2010-10-20 18:32:52 -070046import android.view.View;
Jim Miller5fda69c2011-02-16 15:17:11 -080047import android.view.ViewGroup;
Michael Jurkae0523f72013-04-08 15:44:00 -070048import android.view.ViewPropertyAnimator;
Michael Jurkaf42d90102013-05-08 18:00:04 +020049import android.view.ViewRootImpl;
Jim Miller17377762011-10-11 15:33:34 -070050import android.view.accessibility.AccessibilityEvent;
Dianne Hackbornfc8fa632011-08-17 16:20:47 -070051import android.view.animation.AnimationUtils;
Michael Jurka9bdaada2012-10-01 13:58:29 +020052import android.view.animation.DecelerateInterpolator;
Jim Miller5fda69c2011-02-16 15:17:11 -080053import android.widget.AdapterView;
Michael Jurkabfd24ac2011-11-13 13:50:38 -080054import android.widget.AdapterView.OnItemClickListener;
Jim Miller5fda69c2011-02-16 15:17:11 -080055import android.widget.BaseAdapter;
Michael Jurka99a96552012-01-27 17:23:38 -080056import android.widget.FrameLayout;
Jim Miller44c66fe2010-10-20 18:32:52 -070057import android.widget.ImageView;
Michael Jurkabfd24ac2011-11-13 13:50:38 -080058import android.widget.ImageView.ScaleType;
Jim Millerc0d27312011-07-14 18:54:01 -070059import android.widget.PopupMenu;
Jim Miller44c66fe2010-10-20 18:32:52 -070060import android.widget.TextView;
Jim Miller44c66fe2010-10-20 18:32:52 -070061
62import com.android.systemui.R;
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -050063import com.android.systemui.statusbar.BaseStatusBar;
Michael Jurka3b1fc472011-06-13 10:54:40 -070064import com.android.systemui.statusbar.phone.PhoneStatusBar;
Jim Miller9f0f0e02011-05-17 20:06:29 -070065import com.android.systemui.statusbar.tablet.StatusBarPanel;
66import com.android.systemui.statusbar.tablet.TabletStatusBar;
Jim Miller44c66fe2010-10-20 18:32:52 -070067
Michael Jurkabfd24ac2011-11-13 13:50:38 -080068import java.util.ArrayList;
69
Michael Jurka99a96552012-01-27 17:23:38 -080070public class RecentsPanelView extends FrameLayout implements OnItemClickListener, RecentsCallback,
Michael Jurka80343f62012-10-18 13:13:46 +020071 StatusBarPanel, Animator.AnimatorListener {
Michael Jurka3cd0a592011-08-16 12:40:30 -070072 static final String TAG = "RecentsPanelView";
Dianne Hackbornfc8fa632011-08-17 16:20:47 -070073 static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
Michael Jurkacb466432012-04-03 05:22:45 -070074 private PopupMenu mPopup;
Jim Miller85babff2011-01-11 14:26:03 -080075 private View mRecentsScrim;
Michael Jurka6d667082011-09-16 17:04:40 -070076 private View mRecentsNoApps;
Jim Millerc0d27312011-07-14 18:54:01 -070077 private ViewGroup mRecentsContainer;
Daniel Sandler328310c2011-09-23 15:56:52 -040078 private StatusBarTouchProxy mStatusBarTouchProxy;
Peter Ng622a9762011-08-29 10:56:53 -070079
Jim Miller85babff2011-01-11 14:26:03 -080080 private boolean mShowing;
Michael Jurka99a96552012-01-27 17:23:38 -080081 private boolean mWaitingToShow;
Michael Jurka9bdaada2012-10-01 13:58:29 +020082 private ViewHolder mItemToAnimateInWhenWindowAnimationIsFinished;
Michael Jurkad894c8c2012-11-20 16:46:09 -080083 private boolean mAnimateIconOfFirstTask;
Michael Jurka80343f62012-10-18 13:13:46 +020084 private boolean mWaitingForWindowAnimation;
Michael Jurkad894c8c2012-11-20 16:46:09 -080085 private long mWindowAnimationStartTime;
Michael Jurka0e7757b2013-03-04 16:18:51 +010086 private boolean mCallUiHiddenBeforeNextReload;
Michael Jurka21385cd2012-05-03 10:57:31 -070087
Michael Jurkaab48b682011-09-12 15:39:45 -070088 private RecentTasksLoader mRecentTasksLoader;
89 private ArrayList<TaskDescription> mRecentTaskDescriptions;
90 private TaskDescriptionAdapter mListAdapter;
91 private int mThumbnailWidth;
Michael Jurkabfd24ac2011-11-13 13:50:38 -080092 private boolean mFitThumbnailToXY;
Daniel Sandler4a066c52012-04-20 14:49:13 -040093 private int mRecentItemLayoutId;
Michael Jurkac016aaa2012-06-05 17:22:24 -070094 private boolean mHighEndGfx;
Dianne Hackborneeb1dca2011-09-08 13:30:11 -070095
Michael Jurka4eaa9832012-02-29 15:51:49 -080096 public static interface RecentsScrollView {
97 public int numItemsInOneScreenful();
98 public void setAdapter(TaskDescriptionAdapter adapter);
99 public void setCallback(RecentsCallback callback);
100 public void setMinSwipeAlpha(float minAlpha);
Michael Jurkae5923632012-10-03 15:29:36 +0200101 public View findViewForTask(int persistentTaskId);
Michael Jurka4eaa9832012-02-29 15:51:49 -0800102 }
103
Jim Millerc0d27312011-07-14 18:54:01 -0700104 private final class OnLongClickDelegate implements View.OnLongClickListener {
105 View mOtherView;
106 OnLongClickDelegate(View other) {
107 mOtherView = other;
108 }
109 public boolean onLongClick(View v) {
110 return mOtherView.performLongClick();
111 }
112 }
113
Jim Millerb5a2b292011-03-01 16:14:59 -0800114 /* package */ final static class ViewHolder {
Jim Millerc0d27312011-07-14 18:54:01 -0700115 View thumbnailView;
Dianne Hackbornfc8fa632011-08-17 16:20:47 -0700116 ImageView thumbnailViewImage;
Michael Jurka412cba82011-10-17 09:05:00 -0700117 Bitmap thumbnailViewImageBitmap;
Jim Miller9f0f0e02011-05-17 20:06:29 -0700118 ImageView iconView;
119 TextView labelView;
120 TextView descriptionView;
Michael Jurka9bdaada2012-10-01 13:58:29 +0200121 View calloutLine;
Michael Jurkaab48b682011-09-12 15:39:45 -0700122 TaskDescription taskDescription;
Michael Jurka99a96552012-01-27 17:23:38 -0800123 boolean loadedThumbnailAndIcon;
Jim Miller5fda69c2011-02-16 15:17:11 -0800124 }
125
Michael Jurkaab48b682011-09-12 15:39:45 -0700126 /* package */ final class TaskDescriptionAdapter extends BaseAdapter {
Jim Miller5fda69c2011-02-16 15:17:11 -0800127 private LayoutInflater mInflater;
128
Michael Jurkaab48b682011-09-12 15:39:45 -0700129 public TaskDescriptionAdapter(Context context) {
Jim Miller5fda69c2011-02-16 15:17:11 -0800130 mInflater = LayoutInflater.from(context);
131 }
132
133 public int getCount() {
Michael Jurkaab48b682011-09-12 15:39:45 -0700134 return mRecentTaskDescriptions != null ? mRecentTaskDescriptions.size() : 0;
Jim Miller5fda69c2011-02-16 15:17:11 -0800135 }
136
137 public Object getItem(int position) {
138 return position; // we only need the index
139 }
140
141 public long getItemId(int position) {
142 return position; // we just need something unique for this position
143 }
144
Michael Jurka99a96552012-01-27 17:23:38 -0800145 public View createView(ViewGroup parent) {
Daniel Sandler4a066c52012-04-20 14:49:13 -0400146 View convertView = mInflater.inflate(mRecentItemLayoutId, parent, false);
Michael Jurka99a96552012-01-27 17:23:38 -0800147 ViewHolder holder = new ViewHolder();
148 holder.thumbnailView = convertView.findViewById(R.id.app_thumbnail);
149 holder.thumbnailViewImage =
150 (ImageView) convertView.findViewById(R.id.app_thumbnail_image);
151 // If we set the default thumbnail now, we avoid an onLayout when we update
152 // the thumbnail later (if they both have the same dimensions)
Michael Jurka80343f62012-10-18 13:13:46 +0200153 updateThumbnail(holder, mRecentTasksLoader.getDefaultThumbnail(), false, false);
Michael Jurka99a96552012-01-27 17:23:38 -0800154 holder.iconView = (ImageView) convertView.findViewById(R.id.app_icon);
Michael Jurka80343f62012-10-18 13:13:46 +0200155 holder.iconView.setImageBitmap(mRecentTasksLoader.getDefaultIcon());
Michael Jurka99a96552012-01-27 17:23:38 -0800156 holder.labelView = (TextView) convertView.findViewById(R.id.app_label);
Michael Jurka9bdaada2012-10-01 13:58:29 +0200157 holder.calloutLine = convertView.findViewById(R.id.recents_callout_line);
Michael Jurka99a96552012-01-27 17:23:38 -0800158 holder.descriptionView = (TextView) convertView.findViewById(R.id.app_description);
159
160 convertView.setTag(holder);
161 return convertView;
162 }
163
164 public View getView(int position, View convertView, ViewGroup parent) {
165 if (convertView == null) {
166 convertView = createView(parent);
167 }
Michael Jurka12cdec92013-02-07 17:51:09 +0100168 final ViewHolder holder = (ViewHolder) convertView.getTag();
Jim Miller5fda69c2011-02-16 15:17:11 -0800169
Michael Jurkaab48b682011-09-12 15:39:45 -0700170 // index is reverse since most recent appears at the bottom...
171 final int index = mRecentTaskDescriptions.size() - position - 1;
Jim Miller5fda69c2011-02-16 15:17:11 -0800172
Michael Jurka412cba82011-10-17 09:05:00 -0700173 final TaskDescription td = mRecentTaskDescriptions.get(index);
Michael Jurka99a96552012-01-27 17:23:38 -0800174
Michael Jurka412cba82011-10-17 09:05:00 -0700175 holder.labelView.setText(td.getLabel());
176 holder.thumbnailView.setContentDescription(td.getLabel());
Michael Jurka99a96552012-01-27 17:23:38 -0800177 holder.loadedThumbnailAndIcon = td.isLoaded();
178 if (td.isLoaded()) {
179 updateThumbnail(holder, td.getThumbnail(), true, false);
180 updateIcon(holder, td.getIcon(), true, false);
Michael Jurka99a96552012-01-27 17:23:38 -0800181 }
Michael Jurka9bdaada2012-10-01 13:58:29 +0200182 if (index == 0) {
Michael Jurkad894c8c2012-11-20 16:46:09 -0800183 if (mAnimateIconOfFirstTask) {
Michael Jurka0e7757b2013-03-04 16:18:51 +0100184 ViewHolder oldHolder = mItemToAnimateInWhenWindowAnimationIsFinished;
185 if (oldHolder != null) {
186 oldHolder.iconView.setAlpha(1f);
187 oldHolder.iconView.setTranslationX(0f);
188 oldHolder.iconView.setTranslationY(0f);
189 oldHolder.labelView.setAlpha(1f);
190 oldHolder.labelView.setTranslationX(0f);
191 oldHolder.labelView.setTranslationY(0f);
192 if (oldHolder.calloutLine != null) {
193 oldHolder.calloutLine.setAlpha(1f);
194 oldHolder.calloutLine.setTranslationX(0f);
195 oldHolder.calloutLine.setTranslationY(0f);
Michael Jurkaa9240762012-10-17 13:02:55 +0200196 }
197 }
Michael Jurkae0523f72013-04-08 15:44:00 -0700198 mItemToAnimateInWhenWindowAnimationIsFinished = holder;
199 int translation = -getResources().getDimensionPixelSize(
200 R.dimen.status_bar_recents_app_icon_translate_distance);
201 final Configuration config = getResources().getConfiguration();
202 if (config.orientation == Configuration.ORIENTATION_PORTRAIT) {
203 if (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
204 translation = -translation;
Michael Jurka12cdec92013-02-07 17:51:09 +0100205 }
Michael Jurkae0523f72013-04-08 15:44:00 -0700206 holder.iconView.setAlpha(0f);
207 holder.iconView.setTranslationX(translation);
208 holder.labelView.setAlpha(0f);
209 holder.labelView.setTranslationX(translation);
210 holder.calloutLine.setAlpha(0f);
211 holder.calloutLine.setTranslationX(translation);
212 } else {
213 holder.iconView.setAlpha(0f);
214 holder.iconView.setTranslationY(translation);
215 }
216 if (!mWaitingForWindowAnimation) {
217 animateInIconOfFirstTask();
218 }
Michael Jurka9bdaada2012-10-01 13:58:29 +0200219 }
220 }
Michael Jurkaab48b682011-09-12 15:39:45 -0700221
Michael Jurka412cba82011-10-17 09:05:00 -0700222 holder.thumbnailView.setTag(td);
Jim Millerc0d27312011-07-14 18:54:01 -0700223 holder.thumbnailView.setOnLongClickListener(new OnLongClickDelegate(convertView));
Michael Jurka412cba82011-10-17 09:05:00 -0700224 holder.taskDescription = td;
Jim Miller5fda69c2011-02-16 15:17:11 -0800225 return convertView;
226 }
Michael Jurka99a96552012-01-27 17:23:38 -0800227
228 public void recycleView(View v) {
229 ViewHolder holder = (ViewHolder) v.getTag();
230 updateThumbnail(holder, mRecentTasksLoader.getDefaultThumbnail(), false, false);
231 holder.iconView.setImageBitmap(mRecentTasksLoader.getDefaultIcon());
232 holder.iconView.setVisibility(INVISIBLE);
Michael Jurkad894c8c2012-11-20 16:46:09 -0800233 holder.iconView.animate().cancel();
Michael Jurka99a96552012-01-27 17:23:38 -0800234 holder.labelView.setText(null);
Michael Jurkad894c8c2012-11-20 16:46:09 -0800235 holder.labelView.animate().cancel();
Michael Jurka99a96552012-01-27 17:23:38 -0800236 holder.thumbnailView.setContentDescription(null);
237 holder.thumbnailView.setTag(null);
238 holder.thumbnailView.setOnLongClickListener(null);
239 holder.thumbnailView.setVisibility(INVISIBLE);
Michael Jurkafe09ad82012-10-22 13:58:38 -0700240 holder.iconView.setAlpha(1f);
241 holder.iconView.setTranslationX(0f);
242 holder.iconView.setTranslationY(0f);
243 holder.labelView.setAlpha(1f);
244 holder.labelView.setTranslationX(0f);
245 holder.labelView.setTranslationY(0f);
246 if (holder.calloutLine != null) {
247 holder.calloutLine.setAlpha(1f);
248 holder.calloutLine.setTranslationX(0f);
249 holder.calloutLine.setTranslationY(0f);
Michael Jurkad894c8c2012-11-20 16:46:09 -0800250 holder.calloutLine.animate().cancel();
Michael Jurkafe09ad82012-10-22 13:58:38 -0700251 }
Michael Jurka99a96552012-01-27 17:23:38 -0800252 holder.taskDescription = null;
253 holder.loadedThumbnailAndIcon = false;
254 }
255 }
256
Michael Jurka8b2e37e2012-05-08 20:06:13 -0700257 public RecentsPanelView(Context context, AttributeSet attrs) {
258 this(context, attrs, 0);
259 }
260
261 public RecentsPanelView(Context context, AttributeSet attrs, int defStyle) {
262 super(context, attrs, defStyle);
Michael Jurka8b2e37e2012-05-08 20:06:13 -0700263 updateValuesFromResources();
264
265 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RecentsPanelView,
266 defStyle, 0);
267
268 mRecentItemLayoutId = a.getResourceId(R.styleable.RecentsPanelView_recentItemLayout, 0);
Michael Jurka80343f62012-10-18 13:13:46 +0200269 mRecentTasksLoader = RecentTasksLoader.getInstance(context);
Michael Jurka8b2e37e2012-05-08 20:06:13 -0700270 a.recycle();
271 }
272
Michael Jurka99a96552012-01-27 17:23:38 -0800273 public int numItemsInOneScreenful() {
Michael Jurka4eaa9832012-02-29 15:51:49 -0800274 if (mRecentsContainer instanceof RecentsScrollView){
275 RecentsScrollView scrollView
276 = (RecentsScrollView) mRecentsContainer;
Michael Jurka99a96552012-01-27 17:23:38 -0800277 return scrollView.numItemsInOneScreenful();
Michael Jurka4eaa9832012-02-29 15:51:49 -0800278 } else {
Michael Jurka99a96552012-01-27 17:23:38 -0800279 throw new IllegalArgumentException("missing Recents[Horizontal]ScrollView");
280 }
Jim Miller5fda69c2011-02-16 15:17:11 -0800281 }
282
Daniel Sandler328310c2011-09-23 15:56:52 -0400283 private boolean pointInside(int x, int y, View v) {
284 final int l = v.getLeft();
285 final int r = v.getRight();
286 final int t = v.getTop();
287 final int b = v.getBottom();
Jim Miller44c66fe2010-10-20 18:32:52 -0700288 return x >= l && x < r && y >= t && y < b;
289 }
290
Daniel Sandler328310c2011-09-23 15:56:52 -0400291 public boolean isInContentArea(int x, int y) {
Michael Jurkab144bd72012-01-12 06:56:39 -0800292 if (pointInside(x, y, mRecentsContainer)) {
293 return true;
294 } else if (mStatusBarTouchProxy != null &&
295 pointInside(x, y, mStatusBarTouchProxy)) {
296 return true;
297 } else {
298 return false;
299 }
Daniel Sandler328310c2011-09-23 15:56:52 -0400300 }
301
Michael Jurkacb2522c2012-04-13 09:32:47 -0700302 public void show(boolean show) {
Michael Jurka80343f62012-10-18 13:13:46 +0200303 show(show, null, false, false);
Michael Jurkacb2522c2012-04-13 09:32:47 -0700304 }
305
306 public void show(boolean show, ArrayList<TaskDescription> recentTaskDescriptions,
Michael Jurkad894c8c2012-11-20 16:46:09 -0800307 boolean firstScreenful, boolean animateIconOfFirstTask) {
Michael Jurka0e7757b2013-03-04 16:18:51 +0100308 if (show && mCallUiHiddenBeforeNextReload) {
309 onUiHidden();
310 recentTaskDescriptions = null;
311 mAnimateIconOfFirstTask = false;
312 mWaitingForWindowAnimation = false;
313 } else {
314 mAnimateIconOfFirstTask = animateIconOfFirstTask;
315 mWaitingForWindowAnimation = animateIconOfFirstTask;
316 }
Michael Jurka99a96552012-01-27 17:23:38 -0800317 if (show) {
318 mWaitingToShow = true;
Michael Jurkacb2522c2012-04-13 09:32:47 -0700319 refreshRecentTasksList(recentTaskDescriptions, firstScreenful);
Michael Jurka99a96552012-01-27 17:23:38 -0800320 showIfReady();
321 } else {
Michael Jurkacb2522c2012-04-13 09:32:47 -0700322 showImpl(false);
Michael Jurka99a96552012-01-27 17:23:38 -0800323 }
324 }
325
326 private void showIfReady() {
Michael Jurkacb2522c2012-04-13 09:32:47 -0700327 // mWaitingToShow => there was a touch up on the recents button
328 // mRecentTaskDescriptions != null => we've created views for the first screenful of items
329 if (mWaitingToShow && mRecentTaskDescriptions != null) {
330 showImpl(true);
Michael Jurka99a96552012-01-27 17:23:38 -0800331 }
Michael Jurkaab48b682011-09-12 15:39:45 -0700332 }
333
Michael Jurka56a57832012-05-14 13:24:43 -0700334 static void sendCloseSystemWindows(Context context, String reason) {
335 if (ActivityManagerNative.isSystemReady()) {
336 try {
337 ActivityManagerNative.getDefault().closeSystemDialogs(reason);
338 } catch (RemoteException e) {
339 }
340 }
341 }
342
Michael Jurkacb2522c2012-04-13 09:32:47 -0700343 private void showImpl(boolean show) {
Michael Jurka56a57832012-05-14 13:24:43 -0700344 sendCloseSystemWindows(mContext, BaseStatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS);
345
Michael Jurkacb2522c2012-04-13 09:32:47 -0700346 mShowing = show;
347
Michael Jurka7daf95d2011-09-30 11:07:30 -0700348 if (show) {
Michael Jurkacb2522c2012-04-13 09:32:47 -0700349 // if there are no apps, bring up a "No recent apps" message
350 boolean noApps = mRecentTaskDescriptions != null
351 && (mRecentTaskDescriptions.size() == 0);
352 mRecentsNoApps.setAlpha(1f);
353 mRecentsNoApps.setVisibility(noApps ? View.VISIBLE : View.INVISIBLE);
Michael Jurka7daf95d2011-09-30 11:07:30 -0700354
Michael Jurkaab48b682011-09-12 15:39:45 -0700355 onAnimationEnd(null);
Michael Jurkae9166ed2011-07-27 18:23:18 -0700356 setFocusable(true);
357 setFocusableInTouchMode(true);
358 requestFocus();
Michael Jurkacb466432012-04-03 05:22:45 -0700359 } else {
Michael Jurkacb2522c2012-04-13 09:32:47 -0700360 mWaitingToShow = false;
361 // call onAnimationEnd() and clearRecentTasksList() in onUiHidden()
Michael Jurka0e7757b2013-03-04 16:18:51 +0100362 mCallUiHiddenBeforeNextReload = true;
Michael Jurkacb466432012-04-03 05:22:45 -0700363 if (mPopup != null) {
364 mPopup.dismiss();
365 }
Michael Jurkae9166ed2011-07-27 18:23:18 -0700366 }
Jim Miller85babff2011-01-11 14:26:03 -0800367 }
368
Michael Jurkaf42d90102013-05-08 18:00:04 +0200369 protected void onAttachedToWindow () {
370 super.onAttachedToWindow();
371 final ViewRootImpl root = getViewRootImpl();
372 if (root != null) {
373 root.setDrawDuringWindowsAnimating(true);
374 }
375 }
376
Michael Jurkacb2522c2012-04-13 09:32:47 -0700377 public void onUiHidden() {
Michael Jurka0e7757b2013-03-04 16:18:51 +0100378 mCallUiHiddenBeforeNextReload = false;
Michael Jurkacb2522c2012-04-13 09:32:47 -0700379 if (!mShowing && mRecentTaskDescriptions != null) {
380 onAnimationEnd(null);
381 clearRecentTasksList();
382 }
Michael Jurkac6461ca2011-09-02 12:12:15 -0700383 }
384
Michael Jurkacb2522c2012-04-13 09:32:47 -0700385 public void dismiss() {
386 ((RecentsActivity) mContext).dismissAndGoHome();
387 }
388
389 public void dismissAndGoBack() {
390 ((RecentsActivity) mContext).dismissAndGoBack();
Michael Jurka8b098662011-09-01 17:00:53 -0700391 }
392
Michael Jurka3b1fc472011-06-13 10:54:40 -0700393 public void onAnimationCancel(Animator animation) {
394 }
395
396 public void onAnimationEnd(Animator animation) {
397 if (mShowing) {
398 final LayoutTransition transitioner = new LayoutTransition();
399 ((ViewGroup)mRecentsContainer).setLayoutTransition(transitioner);
400 createCustomAnimations(transitioner);
401 } else {
402 ((ViewGroup)mRecentsContainer).setLayoutTransition(null);
403 }
404 }
405
406 public void onAnimationRepeat(Animator animation) {
407 }
408
409 public void onAnimationStart(Animator animation) {
410 }
411
Svetoslav Ganov6179ea32011-06-28 01:12:41 -0700412 @Override
413 public boolean dispatchHoverEvent(MotionEvent event) {
414 // Ignore hover events outside of this panel bounds since such events
415 // generate spurious accessibility events with the panel content when
416 // tapping outside of it, thus confusing the user.
417 final int x = (int) event.getX();
418 final int y = (int) event.getY();
419 if (x >= 0 && x < getWidth() && y >= 0 && y < getHeight()) {
420 return super.dispatchHoverEvent(event);
421 }
422 return true;
423 }
424
Jim Miller85babff2011-01-11 14:26:03 -0800425 /**
426 * Whether the panel is showing, or, if it's animating, whether it will be
427 * when the animation is done.
428 */
429 public boolean isShowing() {
430 return mShowing;
431 }
432
Daniel Sandler328310c2011-09-23 15:56:52 -0400433 public void setStatusBarView(View statusBarView) {
434 if (mStatusBarTouchProxy != null) {
435 mStatusBarTouchProxy.setStatusBar(statusBarView);
436 }
437 }
438
439 public void setRecentTasksLoader(RecentTasksLoader loader) {
440 mRecentTasksLoader = loader;
441 }
442
Michael Jurkaab48b682011-09-12 15:39:45 -0700443 public void updateValuesFromResources() {
Michael Jurkabfd24ac2011-11-13 13:50:38 -0800444 final Resources res = mContext.getResources();
445 mThumbnailWidth = Math.round(res.getDimension(R.dimen.status_bar_recents_thumbnail_width));
446 mFitThumbnailToXY = res.getBoolean(R.bool.config_recents_thumbnail_image_fits_to_xy);
Jim Miller44c66fe2010-10-20 18:32:52 -0700447 }
448
449 @Override
450 protected void onFinishInflate() {
451 super.onFinishInflate();
Daniel Sandler4a066c52012-04-20 14:49:13 -0400452
Jim Millerc0d27312011-07-14 18:54:01 -0700453 mRecentsContainer = (ViewGroup) findViewById(R.id.recents_container);
Daniel Sandler328310c2011-09-23 15:56:52 -0400454 mStatusBarTouchProxy = (StatusBarTouchProxy) findViewById(R.id.status_bar_touch_proxy);
Michael Jurkaab48b682011-09-12 15:39:45 -0700455 mListAdapter = new TaskDescriptionAdapter(mContext);
Michael Jurka4eaa9832012-02-29 15:51:49 -0800456 if (mRecentsContainer instanceof RecentsScrollView){
457 RecentsScrollView scrollView
458 = (RecentsScrollView) mRecentsContainer;
Jim Miller9f0f0e02011-05-17 20:06:29 -0700459 scrollView.setAdapter(mListAdapter);
460 scrollView.setCallback(this);
Michael Jurka4eaa9832012-02-29 15:51:49 -0800461 } else {
Michael Jurka3cd0a592011-08-16 12:40:30 -0700462 throw new IllegalArgumentException("missing Recents[Horizontal]ScrollView");
Jim Miller9f0f0e02011-05-17 20:06:29 -0700463 }
Jim Miller5fda69c2011-02-16 15:17:11 -0800464
Michael Jurka6d667082011-09-16 17:04:40 -0700465 mRecentsScrim = findViewById(R.id.recents_bg_protect);
466 mRecentsNoApps = findViewById(R.id.recents_no_apps);
Jim Millere5c16ab2010-12-03 19:18:38 -0800467
Michael Jurkaf16fc512012-02-27 15:02:23 -0800468 if (mRecentsScrim != null) {
Jeff Brown98365d72012-08-19 20:30:52 -0700469 mHighEndGfx = ActivityManager.isHighEndGfx();
Michael Jurkac016aaa2012-06-05 17:22:24 -0700470 if (!mHighEndGfx) {
Michael Jurkad5895a72012-05-12 13:24:58 -0700471 mRecentsScrim.setBackground(null);
Michael Jurkaf16fc512012-02-27 15:02:23 -0800472 } else if (mRecentsScrim.getBackground() instanceof BitmapDrawable) {
473 // In order to save space, we make the background texture repeat in the Y direction
474 ((BitmapDrawable) mRecentsScrim.getBackground()).setTileModeY(TileMode.REPEAT);
475 }
Jim Millere5c16ab2010-12-03 19:18:38 -0800476 }
477 }
478
Michael Jurka4eaa9832012-02-29 15:51:49 -0800479 public void setMinSwipeAlpha(float minAlpha) {
480 if (mRecentsContainer instanceof RecentsScrollView){
481 RecentsScrollView scrollView
482 = (RecentsScrollView) mRecentsContainer;
483 scrollView.setMinSwipeAlpha(minAlpha);
484 }
485 }
486
Jim Miller9f0f0e02011-05-17 20:06:29 -0700487 private void createCustomAnimations(LayoutTransition transitioner) {
Chet Haase212f6252011-08-12 09:19:10 -0700488 transitioner.setDuration(200);
489 transitioner.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 0);
490 transitioner.setAnimator(LayoutTransition.DISAPPEARING, null);
Jim Miller9f0f0e02011-05-17 20:06:29 -0700491 }
492
Michael Jurka99a96552012-01-27 17:23:38 -0800493 private void updateIcon(ViewHolder h, Drawable icon, boolean show, boolean anim) {
494 if (icon != null) {
495 h.iconView.setImageDrawable(icon);
496 if (show && h.iconView.getVisibility() != View.VISIBLE) {
497 if (anim) {
498 h.iconView.setAnimation(
499 AnimationUtils.loadAnimation(mContext, R.anim.recent_appear));
500 }
501 h.iconView.setVisibility(View.VISIBLE);
502 }
503 }
504 }
505
Michael Jurka412cba82011-10-17 09:05:00 -0700506 private void updateThumbnail(ViewHolder h, Bitmap thumbnail, boolean show, boolean anim) {
Michael Jurkaab48b682011-09-12 15:39:45 -0700507 if (thumbnail != null) {
508 // Should remove the default image in the frame
509 // that this now covers, to improve scrolling speed.
510 // That can't be done until the anim is complete though.
511 h.thumbnailViewImage.setImageBitmap(thumbnail);
Michael Jurka412cba82011-10-17 09:05:00 -0700512
513 // scale the image to fill the full width of the ImageView. do this only if
514 // we haven't set a bitmap before, or if the bitmap size has changed
515 if (h.thumbnailViewImageBitmap == null ||
516 h.thumbnailViewImageBitmap.getWidth() != thumbnail.getWidth() ||
517 h.thumbnailViewImageBitmap.getHeight() != thumbnail.getHeight()) {
Michael Jurkabfd24ac2011-11-13 13:50:38 -0800518 if (mFitThumbnailToXY) {
519 h.thumbnailViewImage.setScaleType(ScaleType.FIT_XY);
520 } else {
521 Matrix scaleMatrix = new Matrix();
522 float scale = mThumbnailWidth / (float) thumbnail.getWidth();
523 scaleMatrix.setScale(scale, scale);
524 h.thumbnailViewImage.setScaleType(ScaleType.MATRIX);
525 h.thumbnailViewImage.setImageMatrix(scaleMatrix);
526 }
Jim Miller44c66fe2010-10-20 18:32:52 -0700527 }
Michael Jurka412cba82011-10-17 09:05:00 -0700528 if (show && h.thumbnailView.getVisibility() != View.VISIBLE) {
529 if (anim) {
530 h.thumbnailView.setAnimation(
531 AnimationUtils.loadAnimation(mContext, R.anim.recent_appear));
532 }
533 h.thumbnailView.setVisibility(View.VISIBLE);
534 }
535 h.thumbnailViewImageBitmap = thumbnail;
Jim Miller44c66fe2010-10-20 18:32:52 -0700536 }
Jim Millerfefef312010-11-09 14:08:39 -0800537 }
538
Michael Jurka99a96552012-01-27 17:23:38 -0800539 void onTaskThumbnailLoaded(TaskDescription td) {
540 synchronized (td) {
Dianne Hackbornfc8fa632011-08-17 16:20:47 -0700541 if (mRecentsContainer != null) {
542 ViewGroup container = mRecentsContainer;
Michael Jurka4eaa9832012-02-29 15:51:49 -0800543 if (container instanceof RecentsScrollView) {
Michael Jurka99a96552012-01-27 17:23:38 -0800544 container = (ViewGroup) container.findViewById(
Dianne Hackbornfc8fa632011-08-17 16:20:47 -0700545 R.id.recents_linear_layout);
546 }
547 // Look for a view showing this thumbnail, to update.
Michael Jurka99a96552012-01-27 17:23:38 -0800548 for (int i=0; i < container.getChildCount(); i++) {
Dianne Hackbornfc8fa632011-08-17 16:20:47 -0700549 View v = container.getChildAt(i);
550 if (v.getTag() instanceof ViewHolder) {
551 ViewHolder h = (ViewHolder)v.getTag();
Michael Jurka99a96552012-01-27 17:23:38 -0800552 if (!h.loadedThumbnailAndIcon && h.taskDescription == td) {
Michael Jurka412cba82011-10-17 09:05:00 -0700553 // only fade in the thumbnail if recents is already visible-- we
554 // show it immediately otherwise
Michael Jurka99a96552012-01-27 17:23:38 -0800555 //boolean animateShow = mShowing &&
556 // mRecentsContainer.getAlpha() > ViewConfiguration.ALPHA_THRESHOLD;
557 boolean animateShow = false;
558 updateIcon(h, td.getIcon(), true, animateShow);
559 updateThumbnail(h, td.getThumbnail(), true, animateShow);
560 h.loadedThumbnailAndIcon = true;
Dianne Hackbornfc8fa632011-08-17 16:20:47 -0700561 }
562 }
563 }
564 }
Craig Mautnerca6da002012-09-20 14:54:37 -0700565 }
Michael Jurka99a96552012-01-27 17:23:38 -0800566 showIfReady();
Dianne Hackbornfc8fa632011-08-17 16:20:47 -0700567 }
568
Michael Jurkad894c8c2012-11-20 16:46:09 -0800569 private void animateInIconOfFirstTask() {
570 if (mItemToAnimateInWhenWindowAnimationIsFinished != null &&
571 !mRecentTasksLoader.isFirstScreenful()) {
572 int timeSinceWindowAnimation =
573 (int) (System.currentTimeMillis() - mWindowAnimationStartTime);
Michael Jurkaf42d90102013-05-08 18:00:04 +0200574 final int minStartDelay = 150;
Michael Jurkad894c8c2012-11-20 16:46:09 -0800575 final int startDelay = Math.max(0, Math.min(
576 minStartDelay - timeSinceWindowAnimation, minStartDelay));
Michael Jurka9bdaada2012-10-01 13:58:29 +0200577 final int duration = 250;
578 final ViewHolder holder = mItemToAnimateInWhenWindowAnimationIsFinished;
579 final TimeInterpolator cubic = new DecelerateInterpolator(1.5f);
Michael Jurkae0523f72013-04-08 15:44:00 -0700580 FirstFrameAnimatorHelper.initializeDrawListener(holder.iconView);
Michael Jurka9bdaada2012-10-01 13:58:29 +0200581 for (View v :
582 new View[] { holder.iconView, holder.labelView, holder.calloutLine }) {
583 if (v != null) {
Michael Jurkae0523f72013-04-08 15:44:00 -0700584 ViewPropertyAnimator vpa = v.animate().translationX(0).translationY(0)
585 .alpha(1f).setStartDelay(startDelay)
Michael Jurka9bdaada2012-10-01 13:58:29 +0200586 .setDuration(duration).setInterpolator(cubic);
Michael Jurkae0523f72013-04-08 15:44:00 -0700587 FirstFrameAnimatorHelper h = new FirstFrameAnimatorHelper(vpa, v);
Michael Jurka9bdaada2012-10-01 13:58:29 +0200588 }
589 }
590 mItemToAnimateInWhenWindowAnimationIsFinished = null;
Michael Jurkad894c8c2012-11-20 16:46:09 -0800591 mAnimateIconOfFirstTask = false;
Michael Jurka9bdaada2012-10-01 13:58:29 +0200592 }
593 }
594
Michael Jurkad894c8c2012-11-20 16:46:09 -0800595 public void onWindowAnimationStart() {
596 mWaitingForWindowAnimation = false;
597 mWindowAnimationStartTime = System.currentTimeMillis();
598 animateInIconOfFirstTask();
599 }
600
Michael Jurka412cba82011-10-17 09:05:00 -0700601 public void clearRecentTasksList() {
602 // Clear memory used by screenshots
Michael Jurkacb2522c2012-04-13 09:32:47 -0700603 if (mRecentTaskDescriptions != null) {
604 mRecentTasksLoader.cancelLoadingThumbnailsAndIcons(this);
605 onTaskLoadingCancelled();
606 }
607 }
608
609 public void onTaskLoadingCancelled() {
610 // Gets called by RecentTasksLoader when it's cancelled
611 if (mRecentTaskDescriptions != null) {
612 mRecentTaskDescriptions = null;
Michael Jurka412cba82011-10-17 09:05:00 -0700613 mListAdapter.notifyDataSetInvalidated();
Michael Jurka412cba82011-10-17 09:05:00 -0700614 }
615 }
616
Craig Mautnerca6da002012-09-20 14:54:37 -0700617 public void refreshViews() {
618 mListAdapter.notifyDataSetInvalidated();
619 updateUiElements();
620 showIfReady();
621 }
622
Michael Jurka412cba82011-10-17 09:05:00 -0700623 public void refreshRecentTasksList() {
Michael Jurka99a96552012-01-27 17:23:38 -0800624 refreshRecentTasksList(null, false);
Michael Jurka412cba82011-10-17 09:05:00 -0700625 }
626
Michael Jurka99a96552012-01-27 17:23:38 -0800627 private void refreshRecentTasksList(
628 ArrayList<TaskDescription> recentTasksList, boolean firstScreenful) {
Michael Jurkacb2522c2012-04-13 09:32:47 -0700629 if (mRecentTaskDescriptions == null && recentTasksList != null) {
630 onTasksLoaded(recentTasksList, firstScreenful);
631 } else {
632 mRecentTasksLoader.loadTasksInBackground();
Michael Jurka412cba82011-10-17 09:05:00 -0700633 }
Michael Jurkaab48b682011-09-12 15:39:45 -0700634 }
Michael Jurka7daf95d2011-09-30 11:07:30 -0700635
Michael Jurkacb2522c2012-04-13 09:32:47 -0700636 public void onTasksLoaded(ArrayList<TaskDescription> tasks, boolean firstScreenful) {
Michael Jurka99a96552012-01-27 17:23:38 -0800637 if (mRecentTaskDescriptions == null) {
Craig Mautnerbb1449b2012-03-23 16:11:14 -0700638 mRecentTaskDescriptions = new ArrayList<TaskDescription>(tasks);
Michael Jurka99a96552012-01-27 17:23:38 -0800639 } else {
640 mRecentTaskDescriptions.addAll(tasks);
641 }
Michael Jurka7ed267f2012-10-09 17:03:30 +0200642 if (((RecentsActivity) mContext).isActivityShowing()) {
Craig Mautnerca6da002012-09-20 14:54:37 -0700643 refreshViews();
644 }
Michael Jurka99a96552012-01-27 17:23:38 -0800645 }
646
Craig Mautnerca6da002012-09-20 14:54:37 -0700647 private void updateUiElements() {
Dianne Hackborn8da429e2012-09-23 12:52:19 -0700648 final int items = mRecentTaskDescriptions != null
649 ? mRecentTaskDescriptions.size() : 0;
Michael Jurkaab48b682011-09-12 15:39:45 -0700650
651 mRecentsContainer.setVisibility(items > 0 ? View.VISIBLE : View.GONE);
Michael Jurkaab48b682011-09-12 15:39:45 -0700652
653 // Set description for accessibility
Dianne Hackborn8da429e2012-09-23 12:52:19 -0700654 int numRecentApps = mRecentTaskDescriptions != null
655 ? mRecentTaskDescriptions.size() : 0;
Michael Jurka7daf95d2011-09-30 11:07:30 -0700656 String recentAppsAccessibilityDescription;
657 if (numRecentApps == 0) {
658 recentAppsAccessibilityDescription =
659 getResources().getString(R.string.status_bar_no_recent_apps);
660 } else {
661 recentAppsAccessibilityDescription = getResources().getQuantityString(
662 R.plurals.status_bar_accessibility_recent_apps, numRecentApps, numRecentApps);
663 }
664 setContentDescription(recentAppsAccessibilityDescription);
Jim Miller44c66fe2010-10-20 18:32:52 -0700665 }
666
Michael Jurkae5923632012-10-03 15:29:36 +0200667 public boolean simulateClick(int persistentTaskId) {
Michael Jurkacb2522c2012-04-13 09:32:47 -0700668 if (mRecentsContainer instanceof RecentsScrollView){
669 RecentsScrollView scrollView
670 = (RecentsScrollView) mRecentsContainer;
Michael Jurkae5923632012-10-03 15:29:36 +0200671 View v = scrollView.findViewForTask(persistentTaskId);
Michael Jurkacb2522c2012-04-13 09:32:47 -0700672 if (v != null) {
673 handleOnClick(v);
674 return true;
675 }
676 }
677 return false;
678 }
Michael Jurkac016aaa2012-06-05 17:22:24 -0700679
Jim Miller9f0f0e02011-05-17 20:06:29 -0700680 public void handleOnClick(View view) {
Dianne Hackborn8078d8c2012-03-20 11:11:26 -0700681 ViewHolder holder = (ViewHolder)view.getTag();
682 TaskDescription ad = holder.taskDescription;
Jim Miller9f0f0e02011-05-17 20:06:29 -0700683 final Context context = view.getContext();
Jim Millere5c16ab2010-12-03 19:18:38 -0800684 final ActivityManager am = (ActivityManager)
Jim Miller9f0f0e02011-05-17 20:06:29 -0700685 context.getSystemService(Context.ACTIVITY_SERVICE);
Michael Jurkac016aaa2012-06-05 17:22:24 -0700686 Bitmap bm = holder.thumbnailViewImageBitmap;
687 boolean usingDrawingCache;
688 if (bm.getWidth() == holder.thumbnailViewImage.getWidth() &&
689 bm.getHeight() == holder.thumbnailViewImage.getHeight()) {
690 usingDrawingCache = false;
691 } else {
692 holder.thumbnailViewImage.setDrawingCacheEnabled(true);
693 bm = holder.thumbnailViewImage.getDrawingCache();
694 usingDrawingCache = true;
695 }
Michael Jurka482f1592012-09-13 11:05:59 -0700696 Bundle opts = (bm == null) ?
697 null :
698 ActivityOptions.makeThumbnailScaleUpAnimation(
699 holder.thumbnailViewImage, bm, 0, 0, null).toBundle();
Michael Jurkacb2522c2012-04-13 09:32:47 -0700700
701 show(false);
Jim Miller9f0f0e02011-05-17 20:06:29 -0700702 if (ad.taskId >= 0) {
Dianne Hackbornb6777462010-11-12 12:43:22 -0800703 // This is an active task; it should just go to the foreground.
Dianne Hackborn8078d8c2012-03-20 11:11:26 -0700704 am.moveTaskToFront(ad.taskId, ActivityManager.MOVE_TASK_WITH_HOME,
Michael Jurka482f1592012-09-13 11:05:59 -0700705 opts);
Dianne Hackbornb6777462010-11-12 12:43:22 -0800706 } else {
707 Intent intent = ad.intent;
Dianne Hackborn621e17d2010-11-22 15:59:56 -0800708 intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
Dianne Hackborn38cc8962011-10-13 11:33:55 -0700709 | Intent.FLAG_ACTIVITY_TASK_ON_HOME
710 | Intent.FLAG_ACTIVITY_NEW_TASK);
Dianne Hackbornb6777462010-11-12 12:43:22 -0800711 if (DEBUG) Log.v(TAG, "Starting activity " + intent);
Michael Jurkaa2bdffe2013-02-08 15:41:56 +0100712 try {
713 context.startActivityAsUser(intent, opts,
714 new UserHandle(UserHandle.USER_CURRENT));
715 } catch (SecurityException e) {
716 Log.e(TAG, "Recents does not have the permission to launch " + intent, e);
717 }
Dianne Hackbornb6777462010-11-12 12:43:22 -0800718 }
Michael Jurkab9a38c52012-06-14 11:57:50 -0700719 if (usingDrawingCache) {
Michael Jurkac016aaa2012-06-05 17:22:24 -0700720 holder.thumbnailViewImage.setDrawingCacheEnabled(false);
721 }
Jim Millerf1e22e52011-01-26 15:39:51 -0800722 }
Jim Miller9f0f0e02011-05-17 20:06:29 -0700723
724 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
725 handleOnClick(view);
726 }
727
Michael Jurka07d40462011-07-19 10:54:38 -0700728 public void handleSwipe(View view) {
Michael Jurkaab48b682011-09-12 15:39:45 -0700729 TaskDescription ad = ((ViewHolder) view.getTag()).taskDescription;
Michael Jurkaa8eac1d2012-04-30 15:54:19 -0700730 if (ad == null) {
Michael Jurka9d69b442012-05-04 15:46:32 -0700731 Log.v(TAG, "Not able to find activity description for swiped task; view=" + view +
732 " tag=" + view.getTag());
733 return;
Michael Jurkaa8eac1d2012-04-30 15:54:19 -0700734 }
Dianne Hackbornfc8fa632011-08-17 16:20:47 -0700735 if (DEBUG) Log.v(TAG, "Jettison " + ad.getLabel());
Michael Jurkaab48b682011-09-12 15:39:45 -0700736 mRecentTaskDescriptions.remove(ad);
Michael Jurkae57922c2012-11-26 16:05:12 -0800737 mRecentTasksLoader.remove(ad);
Jim Miller9f0f0e02011-05-17 20:06:29 -0700738
739 // Handled by widget containers to enable LayoutTransitions properly
740 // mListAdapter.notifyDataSetChanged();
741
Michael Jurkaab48b682011-09-12 15:39:45 -0700742 if (mRecentTaskDescriptions.size() == 0) {
Michael Jurkacb2522c2012-04-13 09:32:47 -0700743 dismissAndGoBack();
Jim Miller9f0f0e02011-05-17 20:06:29 -0700744 }
745
746 // Currently, either direction means the same thing, so ignore direction and remove
747 // the task.
748 final ActivityManager am = (ActivityManager)
749 mContext.getSystemService(Context.ACTIVITY_SERVICE);
Michael Jurkaa8eac1d2012-04-30 15:54:19 -0700750 if (am != null) {
751 am.removeTask(ad.persistentTaskId, ActivityManager.REMOVE_TASK_KILL_PROCESS);
Jim Miller17377762011-10-11 15:33:34 -0700752
Michael Jurkaa8eac1d2012-04-30 15:54:19 -0700753 // Accessibility feedback
754 setContentDescription(
755 mContext.getString(R.string.accessibility_recents_item_dismissed, ad.getLabel()));
756 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
757 setContentDescription(null);
758 }
Jim Miller9f0f0e02011-05-17 20:06:29 -0700759 }
760
Jim Millerc0d27312011-07-14 18:54:01 -0700761 private void startApplicationDetailsActivity(String packageName) {
762 Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
763 Uri.fromParts("package", packageName, null));
Adam Powell0fc5b2b2012-07-18 18:20:29 -0700764 intent.setComponent(intent.resolveActivity(mContext.getPackageManager()));
765 TaskStackBuilder.create(getContext())
766 .addNextIntentWithParentStack(intent).startActivities();
Jim Millerc0d27312011-07-14 18:54:01 -0700767 }
768
Michael Jurkacb466432012-04-03 05:22:45 -0700769 public boolean onInterceptTouchEvent(MotionEvent ev) {
770 if (mPopup != null) {
771 return true;
772 } else {
773 return super.onInterceptTouchEvent(ev);
774 }
775 }
776
Michael Jurkafaa790c2011-09-02 17:35:02 -0700777 public void handleLongPress(
778 final View selectedView, final View anchorView, final View thumbnailView) {
779 thumbnailView.setSelected(true);
Michael Jurkacb466432012-04-03 05:22:45 -0700780 final PopupMenu popup =
781 new PopupMenu(mContext, anchorView == null ? selectedView : anchorView);
782 mPopup = popup;
Jim Millerc0d27312011-07-14 18:54:01 -0700783 popup.getMenuInflater().inflate(R.menu.recent_popup_menu, popup.getMenu());
784 popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
785 public boolean onMenuItemClick(MenuItem item) {
786 if (item.getItemId() == R.id.recent_remove_item) {
787 mRecentsContainer.removeViewInLayout(selectedView);
788 } else if (item.getItemId() == R.id.recent_inspect_item) {
789 ViewHolder viewHolder = (ViewHolder) selectedView.getTag();
790 if (viewHolder != null) {
Michael Jurkaab48b682011-09-12 15:39:45 -0700791 final TaskDescription ad = viewHolder.taskDescription;
Jim Millerc0d27312011-07-14 18:54:01 -0700792 startApplicationDetailsActivity(ad.packageName);
Michael Jurkacb2522c2012-04-13 09:32:47 -0700793 show(false);
Jim Millerc0d27312011-07-14 18:54:01 -0700794 } else {
795 throw new IllegalStateException("Oops, no tag on view " + selectedView);
796 }
797 } else {
798 return false;
799 }
800 return true;
801 }
802 });
Michael Jurkafaa790c2011-09-02 17:35:02 -0700803 popup.setOnDismissListener(new PopupMenu.OnDismissListener() {
804 public void onDismiss(PopupMenu menu) {
805 thumbnailView.setSelected(false);
Michael Jurkacb466432012-04-03 05:22:45 -0700806 mPopup = null;
Michael Jurkafaa790c2011-09-02 17:35:02 -0700807 }
808 });
Jim Millerc0d27312011-07-14 18:54:01 -0700809 popup.show();
Jim Miller9f0f0e02011-05-17 20:06:29 -0700810 }
Jim Miller44c66fe2010-10-20 18:32:52 -0700811}