blob: 7db1ce8cf6d3c5eb8b9b4284fd4e10fea54008e7 [file] [log] [blame]
Jim Miller44c66fe2010-10-20 18:32:52 -07001/*
2 * Copyright (C) 2010 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.statusbar.tablet;
18
19import java.util.ArrayList;
20import java.util.List;
21
Jim Millere5c16ab2010-12-03 19:18:38 -080022import android.animation.Animator;
Jim Millere5c16ab2010-12-03 19:18:38 -080023import android.animation.AnimatorSet;
Jim Millere5c16ab2010-12-03 19:18:38 -080024import android.animation.ObjectAnimator;
Jim Miller44c66fe2010-10-20 18:32:52 -070025import android.app.ActivityManager;
Jim Miller44c66fe2010-10-20 18:32:52 -070026import android.content.Context;
27import android.content.Intent;
Jim Miller44c66fe2010-10-20 18:32:52 -070028import android.content.pm.ActivityInfo;
29import android.content.pm.PackageManager;
30import android.content.pm.ResolveInfo;
Jim Millere5c16ab2010-12-03 19:18:38 -080031import android.content.res.Configuration;
32import android.content.res.Resources;
Jim Miller44c66fe2010-10-20 18:32:52 -070033import android.graphics.Bitmap;
Jim Millerf9905b42010-12-22 20:37:17 -080034import android.graphics.BitmapFactory;
Jim Millere5c16ab2010-12-03 19:18:38 -080035import android.graphics.Canvas;
Jim Millerfefef312010-11-09 14:08:39 -080036import android.graphics.Matrix;
Jim Millere5c16ab2010-12-03 19:18:38 -080037import android.graphics.Paint;
38import android.graphics.Rect;
Jim Millerf9905b42010-12-22 20:37:17 -080039import android.graphics.RectF;
Jim Millere5c16ab2010-12-03 19:18:38 -080040import android.graphics.Shader.TileMode;
41import android.graphics.drawable.BitmapDrawable;
Jim Miller44c66fe2010-10-20 18:32:52 -070042import android.graphics.drawable.Drawable;
Jim Miller44c66fe2010-10-20 18:32:52 -070043import android.util.AttributeSet;
Jim Millere5c16ab2010-12-03 19:18:38 -080044import android.util.DisplayMetrics;
Jim Miller44c66fe2010-10-20 18:32:52 -070045import android.util.Log;
Jim Miller85babff2011-01-11 14:26:03 -080046import android.util.Slog;
Jim Miller5fda69c2011-02-16 15:17:11 -080047import android.view.LayoutInflater;
Jim Miller44c66fe2010-10-20 18:32:52 -070048import android.view.View;
Jim Miller5fda69c2011-02-16 15:17:11 -080049import android.view.ViewGroup;
50import android.widget.AdapterView;
51import android.widget.AdapterView.OnItemClickListener;
52import android.widget.BaseAdapter;
Dianne Hackborn0f1de9a2011-05-11 17:34:49 -070053import android.widget.CheckBox;
Jim Miller44c66fe2010-10-20 18:32:52 -070054import android.widget.ImageView;
Jim Miller5fda69c2011-02-16 15:17:11 -080055import android.widget.ListView;
Jim Miller85babff2011-01-11 14:26:03 -080056import android.widget.RelativeLayout;
Jim Miller44c66fe2010-10-20 18:32:52 -070057import android.widget.TextView;
Jim Miller44c66fe2010-10-20 18:32:52 -070058
59import com.android.systemui.R;
60
Jim Miller5fda69c2011-02-16 15:17:11 -080061public class RecentAppsPanel extends RelativeLayout implements StatusBarPanel, OnItemClickListener {
Jim Millerf9905b42010-12-22 20:37:17 -080062 private static final int GLOW_PADDING = 15;
Jim Miller44c66fe2010-10-20 18:32:52 -070063 private static final String TAG = "RecentAppsPanel";
Joe Onoratofd52b182010-11-10 18:00:52 -080064 private static final boolean DEBUG = TabletStatusBar.DEBUG;
Jim Miller5fda69c2011-02-16 15:17:11 -080065 private static final int DISPLAY_TASKS = 20;
66 private static final int MAX_TASKS = DISPLAY_TASKS + 1; // allow extra for non-apps
Joe Onoratofd52b182010-11-10 18:00:52 -080067 private TabletStatusBar mBar;
Jim Millerfefef312010-11-09 14:08:39 -080068 private ArrayList<ActivityDescription> mActivityDescriptions;
Jim Millere5c16ab2010-12-03 19:18:38 -080069 private int mIconDpi;
Jim Miller85babff2011-01-11 14:26:03 -080070 private View mRecentsScrim;
71 private View mRecentsGlowView;
Jim Miller5fda69c2011-02-16 15:17:11 -080072 private ListView mRecentsContainer;
Dianne Hackborn0f1de9a2011-05-11 17:34:49 -070073 private CheckBox mCompatMode;
Jim Millerf9905b42010-12-22 20:37:17 -080074 private Bitmap mGlowBitmap;
Jim Miller85babff2011-01-11 14:26:03 -080075 private boolean mShowing;
76 private Choreographer mChoreo;
Jim Millerf1e22e52011-01-26 15:39:51 -080077 private View mRecentsDismissButton;
Jim Miller5fda69c2011-02-16 15:17:11 -080078 private ActvityDescriptionAdapter mListAdapter;
79 protected int mLastVisibleItem;
Jim Millerfefef312010-11-09 14:08:39 -080080
81 static class ActivityDescription {
82 int id;
83 Bitmap thumbnail; // generated by Activity.onCreateThumbnail()
84 Drawable icon; // application package icon
85 String label; // application package label
86 CharSequence description; // generated by Activity.onCreateDescription()
87 Intent intent; // launch intent for application
88 Matrix matrix; // arbitrary rotation matrix to correct orientation
Jim Millere5c16ab2010-12-03 19:18:38 -080089 String packageName; // used to override animations (see onClick())
Jim Millerfefef312010-11-09 14:08:39 -080090 int position; // position in list
91
92 public ActivityDescription(Bitmap _thumbnail,
Dianne Hackbornd2835932010-12-13 16:28:46 -080093 Drawable _icon, String _label, CharSequence _desc, Intent _intent,
94 int _id, int _pos, String _packageName)
Jim Millerfefef312010-11-09 14:08:39 -080095 {
96 thumbnail = _thumbnail;
97 icon = _icon;
98 label = _label;
99 description = _desc;
100 intent = _intent;
101 id = _id;
102 position = _pos;
Jim Millere5c16ab2010-12-03 19:18:38 -0800103 packageName = _packageName;
Jim Millerfefef312010-11-09 14:08:39 -0800104 }
105 };
106
Jim Millerb5a2b292011-03-01 16:14:59 -0800107 /* package */ final static class ViewHolder {
Jim Miller5fda69c2011-02-16 15:17:11 -0800108 private ImageView thumbnailView;
109 private ImageView iconView;
110 private TextView labelView;
111 private TextView descriptionView;
112 private ActivityDescription activityDescription;
113 }
114
Jim Millerb5a2b292011-03-01 16:14:59 -0800115 /* package */ final class ActvityDescriptionAdapter extends BaseAdapter {
Jim Miller5fda69c2011-02-16 15:17:11 -0800116 private LayoutInflater mInflater;
117
118 public ActvityDescriptionAdapter(Context context) {
119 mInflater = LayoutInflater.from(context);
120 }
121
122 public int getCount() {
123 return mActivityDescriptions != null ? mActivityDescriptions.size() : 0;
124 }
125
126 public Object getItem(int position) {
127 return position; // we only need the index
128 }
129
130 public long getItemId(int position) {
131 return position; // we just need something unique for this position
132 }
133
134 public View getView(int position, View convertView, ViewGroup parent) {
135 ViewHolder holder;
136 if (convertView == null) {
137 convertView = mInflater.inflate(R.layout.status_bar_recent_item, null);
138 holder = new ViewHolder();
139 holder.thumbnailView = (ImageView) convertView.findViewById(R.id.app_thumbnail);
140 holder.iconView = (ImageView) convertView.findViewById(R.id.app_icon);
141 holder.labelView = (TextView) convertView.findViewById(R.id.app_label);
142 holder.descriptionView = (TextView) convertView.findViewById(R.id.app_description);
143 convertView.setTag(holder);
144 } else {
145 holder = (ViewHolder) convertView.getTag();
146 }
147
148 // activityId is reverse since most recent appears at the bottom...
149 final int activityId = mActivityDescriptions.size() - position - 1;
150
151 final ActivityDescription activityDescription = mActivityDescriptions.get(activityId);
152 final Bitmap thumb = activityDescription.thumbnail;
153 holder.thumbnailView.setImageBitmap(compositeBitmap(mGlowBitmap, thumb));
154 holder.iconView.setImageDrawable(activityDescription.icon);
155 holder.labelView.setText(activityDescription.label);
156 holder.descriptionView.setText(activityDescription.description);
157 holder.thumbnailView.setTag(activityDescription);
158 holder.activityDescription = activityDescription;
159
160 return convertView;
161 }
162 }
163
Jim Miller44c66fe2010-10-20 18:32:52 -0700164 public boolean isInContentArea(int x, int y) {
Jim Miller6f5bd3c2011-01-25 17:03:27 -0800165 // use mRecentsContainer's exact bounds to determine horizontal position
166 final int l = mRecentsContainer.getLeft();
167 final int r = mRecentsContainer.getRight();
168 // use surrounding mRecentsGlowView's position in parent determine vertical bounds
169 final int t = mRecentsGlowView.getTop();
170 final int b = mRecentsGlowView.getBottom();
Jim Miller44c66fe2010-10-20 18:32:52 -0700171 return x >= l && x < r && y >= t && y < b;
172 }
173
Jim Miller85babff2011-01-11 14:26:03 -0800174 public void show(boolean show, boolean animate) {
175 if (animate) {
176 if (mShowing != show) {
177 mShowing = show;
178 if (show) {
179 setVisibility(View.VISIBLE);
180 }
181 mChoreo.startAnimation(show);
182 }
183 } else {
184 mShowing = show;
185 setVisibility(show ? View.VISIBLE : View.GONE);
186 mChoreo.jumpTo(show);
187 }
188 }
189
190 /**
191 * We need to be aligned at the bottom. LinearLayout can't do this, so instead,
192 * let LinearLayout do all the hard work, and then shift everything down to the bottom.
193 */
194 @Override
195 protected void onLayout(boolean changed, int l, int t, int r, int b) {
196 super.onLayout(changed, l, t, r, b);
197 mChoreo.setPanelHeight(mRecentsContainer.getHeight());
198 }
199
200 /**
201 * Whether the panel is showing, or, if it's animating, whether it will be
202 * when the animation is done.
203 */
204 public boolean isShowing() {
205 return mShowing;
206 }
207
208 private static class Choreographer implements Animator.AnimatorListener {
209 // should group this into a multi-property animation
210 private static final int OPEN_DURATION = 136;
211 private static final int CLOSE_DURATION = 250;
212
213 boolean mVisible;
214 int mPanelHeight;
215 View mRootView;
216 View mScrimView;
217 View mContentView;
218 AnimatorSet mContentAnim;
219
220 // the panel will start to appear this many px from the end
221 final int HYPERSPACE_OFFRAMP = 200;
222
223 public Choreographer(View root, View scrim, View content) {
224 mRootView = root;
225 mScrimView = scrim;
226 mContentView = content;
227 }
228
229 void createAnimation(boolean appearing) {
230 float start, end;
231
232 if (DEBUG) Log.e(TAG, "createAnimation()", new Exception());
233
234 // 0: on-screen
235 // height: off-screen
236 float y = mContentView.getTranslationY();
237 if (appearing) {
238 // we want to go from near-the-top to the top, unless we're half-open in the right
239 // general vicinity
240 start = (y < HYPERSPACE_OFFRAMP) ? y : HYPERSPACE_OFFRAMP;
241 end = 0;
242 } else {
243 start = y;
244 end = y + HYPERSPACE_OFFRAMP;
245 }
246
247 Animator posAnim = ObjectAnimator.ofFloat(mContentView, "translationY",
248 start, end);
249 posAnim.setInterpolator(appearing
250 ? new android.view.animation.DecelerateInterpolator(2.5f)
251 : new android.view.animation.AccelerateInterpolator(2.5f));
252
253 Animator glowAnim = ObjectAnimator.ofFloat(mContentView, "alpha",
254 mContentView.getAlpha(), appearing ? 1.0f : 0.0f);
255 glowAnim.setInterpolator(appearing
256 ? new android.view.animation.AccelerateInterpolator(1.0f)
257 : new android.view.animation.DecelerateInterpolator(1.0f));
258
259 Animator bgAnim = ObjectAnimator.ofInt(mScrimView.getBackground(),
260 "alpha", appearing ? 0 : 255, appearing ? 255 : 0);
261
262 mContentAnim = new AnimatorSet();
263 mContentAnim
264 .play(bgAnim)
265 .with(glowAnim)
266 .with(posAnim);
267 mContentAnim.setDuration(appearing ? OPEN_DURATION : CLOSE_DURATION);
268 mContentAnim.addListener(this);
269 }
270
271 void startAnimation(boolean appearing) {
272 if (DEBUG) Slog.d(TAG, "startAnimation(appearing=" + appearing + ")");
273
274 createAnimation(appearing);
275
276 mContentView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
277 mContentAnim.start();
278
279 mVisible = appearing;
280 }
281
282 void jumpTo(boolean appearing) {
283 mContentView.setTranslationY(appearing ? 0 : mPanelHeight);
284 }
285
286 public void setPanelHeight(int h) {
287 if (DEBUG) Slog.d(TAG, "panelHeight=" + h);
288 mPanelHeight = h;
289 }
290
291 public void onAnimationCancel(Animator animation) {
292 if (DEBUG) Slog.d(TAG, "onAnimationCancel");
293 // force this to zero so we close the window
294 mVisible = false;
295 }
296
297 public void onAnimationEnd(Animator animation) {
298 if (DEBUG) Slog.d(TAG, "onAnimationEnd");
299 if (!mVisible) {
300 mRootView.setVisibility(View.GONE);
301 }
302 mContentView.setLayerType(View.LAYER_TYPE_NONE, null);
303 mContentAnim = null;
304 }
305
306 public void onAnimationRepeat(Animator animation) {
307 }
308
309 public void onAnimationStart(Animator animation) {
310 }
311 }
312
Joe Onoratofd52b182010-11-10 18:00:52 -0800313 public void setBar(TabletStatusBar bar) {
Jim Miller44c66fe2010-10-20 18:32:52 -0700314 mBar = bar;
315 }
316
317 public RecentAppsPanel(Context context, AttributeSet attrs) {
318 this(context, attrs, 0);
319 }
320
321 public RecentAppsPanel(Context context, AttributeSet attrs, int defStyle) {
322 super(context, attrs, defStyle);
Jim Millere5c16ab2010-12-03 19:18:38 -0800323
324 Resources res = context.getResources();
325 boolean xlarge = (res.getConfiguration().screenLayout
326 & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE;
327
328 mIconDpi = xlarge ? DisplayMetrics.DENSITY_HIGH : res.getDisplayMetrics().densityDpi;
Jim Millerf9905b42010-12-22 20:37:17 -0800329 mGlowBitmap = BitmapFactory.decodeResource(res, R.drawable.recents_thumbnail_bg);
Jim Miller44c66fe2010-10-20 18:32:52 -0700330 }
331
332 @Override
Jim Miller5fda69c2011-02-16 15:17:11 -0800333 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
334 super.onSizeChanged(w, h, oldw, oldh);
335 // Keep track of the last visible item in the list so we can restore it
336 // to the bottom when the orientation changes.
337 int childCount = mRecentsContainer.getChildCount();
338 if (childCount > 0) {
339 mLastVisibleItem = mRecentsContainer.getFirstVisiblePosition() + childCount - 1;
340 View view = mRecentsContainer.getChildAt(childCount - 1);
341 final int distanceFromBottom = mRecentsContainer.getHeight() - view.getTop();
342 //final int distanceFromBottom = view.getHeight() + BOTTOM_OFFSET;
343
344 // This has to happen post-layout, so run it "in the future"
345 post(new Runnable() {
346 public void run() {
347 mRecentsContainer.setSelectionFromTop(mLastVisibleItem,
348 mRecentsContainer.getHeight() - distanceFromBottom);
349 }
350 });
351 }
352 }
353
354 @Override
Jim Miller44c66fe2010-10-20 18:32:52 -0700355 protected void onFinishInflate() {
356 super.onFinishInflate();
Jim Miller5fda69c2011-02-16 15:17:11 -0800357 LayoutInflater inflater = (LayoutInflater)
358 mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
359
360 mRecentsContainer = (ListView) findViewById(R.id.recents_container);
Dianne Hackborn0f1de9a2011-05-11 17:34:49 -0700361 mCompatMode = (CheckBox) findViewById(R.id.recents_compat_mode);
362 mCompatMode.setOnClickListener(new OnClickListener() {
363 public void onClick(View v) {
364 final ActivityManager am = (ActivityManager)
365 mContext.getSystemService(Context.ACTIVITY_SERVICE);
366 am.setFrontActivityScreenCompatMode(ActivityManager.COMPAT_MODE_TOGGLE);
367 hide(true);
368 }
369 });
Jim Miller5fda69c2011-02-16 15:17:11 -0800370 View footer = inflater.inflate(R.layout.status_bar_recent_panel_footer,
371 mRecentsContainer, false);
372 mRecentsContainer.setScrollbarFadingEnabled(true);
Jim Millerb5a2b292011-03-01 16:14:59 -0800373 mRecentsContainer.addFooterView(footer, null, false);
Jim Miller5fda69c2011-02-16 15:17:11 -0800374 mRecentsContainer.setAdapter(mListAdapter = new ActvityDescriptionAdapter(mContext));
375 mRecentsContainer.setOnItemClickListener(this);
Jim Miller67edceb2011-03-02 18:32:16 -0800376 final int leftPadding = mContext.getResources()
377 .getDimensionPixelOffset(R.dimen.status_bar_recents_thumbnail_left_margin);
378 mRecentsContainer.setOverScrollEffectPadding(leftPadding, 0);
Jim Miller5fda69c2011-02-16 15:17:11 -0800379
Jim Miller169a2112010-12-10 18:30:07 -0800380 mRecentsGlowView = findViewById(R.id.recents_glow);
Jim Miller85babff2011-01-11 14:26:03 -0800381 mRecentsScrim = (View) findViewById(R.id.recents_bg_protect);
382 mChoreo = new Choreographer(this, mRecentsScrim, mRecentsGlowView);
Jim Millerf1e22e52011-01-26 15:39:51 -0800383 mRecentsDismissButton = findViewById(R.id.recents_dismiss_button);
384 mRecentsDismissButton.setOnClickListener(new OnClickListener() {
385 public void onClick(View v) {
386 hide(true);
387 }
388 });
Jim Millere5c16ab2010-12-03 19:18:38 -0800389
390 // In order to save space, we make the background texture repeat in the Y direction
Jim Miller85babff2011-01-11 14:26:03 -0800391 if (mRecentsScrim != null && mRecentsScrim.getBackground() instanceof BitmapDrawable) {
392 ((BitmapDrawable) mRecentsScrim.getBackground()).setTileModeY(TileMode.REPEAT);
Jim Millere5c16ab2010-12-03 19:18:38 -0800393 }
394 }
395
396 @Override
Jim Miller44c66fe2010-10-20 18:32:52 -0700397 protected void onVisibilityChanged(View changedView, int visibility) {
398 super.onVisibilityChanged(changedView, visibility);
Jim Millere5c16ab2010-12-03 19:18:38 -0800399 if (DEBUG) Log.v(TAG, "onVisibilityChanged(" + changedView + ", " + visibility + ")");
Jim Miller44c66fe2010-10-20 18:32:52 -0700400 if (visibility == View.VISIBLE && changedView == this) {
Jim Millerfefef312010-11-09 14:08:39 -0800401 refreshApplicationList();
Jim Miller5fda69c2011-02-16 15:17:11 -0800402 post(new Runnable() {
403 public void run() {
404 mRecentsContainer.setSelection(mActivityDescriptions.size() - 1);
405 }
406 });
Jim Miller44c66fe2010-10-20 18:32:52 -0700407 }
408 }
409
Jim Millere5c16ab2010-12-03 19:18:38 -0800410 private Drawable getFullResDefaultActivityIcon() {
411 return getFullResIcon(Resources.getSystem(),
Michael Jurka573068c2011-01-17 13:29:53 -0800412 com.android.internal.R.mipmap.sym_def_app_icon);
Jim Millere5c16ab2010-12-03 19:18:38 -0800413 }
414
415 private Drawable getFullResIcon(Resources resources, int iconId) {
416 return resources.getDrawableForDensity(iconId, mIconDpi);
417 }
418
419 private Drawable getFullResIcon(ResolveInfo info, PackageManager packageManager) {
420 Resources resources;
421 try {
422 resources = packageManager.getResourcesForApplication(
423 info.activityInfo.applicationInfo);
424 } catch (PackageManager.NameNotFoundException e) {
425 resources = null;
426 }
427 if (resources != null) {
428 int iconId = info.activityInfo.getIconResource();
429 if (iconId != 0) {
430 return getFullResIcon(resources, iconId);
431 }
432 }
433 return getFullResDefaultActivityIcon();
434 }
435
Jim Millerfefef312010-11-09 14:08:39 -0800436 private ArrayList<ActivityDescription> getRecentTasks() {
437 ArrayList<ActivityDescription> activityDescriptions = new ArrayList<ActivityDescription>();
438 final PackageManager pm = mContext.getPackageManager();
Jim Miller44c66fe2010-10-20 18:32:52 -0700439 final ActivityManager am = (ActivityManager)
Jim Millerfefef312010-11-09 14:08:39 -0800440 mContext.getSystemService(Context.ACTIVITY_SERVICE);
Jim Miller44c66fe2010-10-20 18:32:52 -0700441
Jim Millerfefef312010-11-09 14:08:39 -0800442 final List<ActivityManager.RecentTaskInfo> recentTasks =
Dianne Hackbornd2835932010-12-13 16:28:46 -0800443 am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE
444 | ActivityManager.TASKS_GET_THUMBNAILS);
Jim Millerfefef312010-11-09 14:08:39 -0800445
446 ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
447 .resolveActivityInfo(pm, 0);
Jim Miller44c66fe2010-10-20 18:32:52 -0700448
449 int numTasks = recentTasks.size();
Jim Millerd19bede2010-12-14 17:17:05 -0800450
451 // skip the first activity - assume it's either the home screen or the current app.
452 final int first = 1;
453 for (int i = first, index = 0; i < numTasks && (index < MAX_TASKS); ++i) {
Jim Millerfefef312010-11-09 14:08:39 -0800454 final ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(i);
Jim Miller44c66fe2010-10-20 18:32:52 -0700455
Jim Millerfefef312010-11-09 14:08:39 -0800456 Intent intent = new Intent(recentInfo.baseIntent);
457 if (recentInfo.origActivity != null) {
458 intent.setComponent(recentInfo.origActivity);
Jim Miller44c66fe2010-10-20 18:32:52 -0700459 }
460
Jim Millerfefef312010-11-09 14:08:39 -0800461 // Skip the current home activity.
Jim Miller44c66fe2010-10-20 18:32:52 -0700462 if (homeInfo != null
463 && homeInfo.packageName.equals(intent.getComponent().getPackageName())
464 && homeInfo.name.equals(intent.getComponent().getClassName())) {
Jim Millerfefef312010-11-09 14:08:39 -0800465 continue;
Jim Miller44c66fe2010-10-20 18:32:52 -0700466 }
467
468 intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
469 | Intent.FLAG_ACTIVITY_NEW_TASK);
470 final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
471 if (resolveInfo != null) {
Jim Millerfefef312010-11-09 14:08:39 -0800472 final ActivityInfo info = resolveInfo.activityInfo;
473 final String title = info.loadLabel(pm).toString();
Jim Millere5c16ab2010-12-03 19:18:38 -0800474 // Drawable icon = info.loadIcon(pm);
475 Drawable icon = getFullResIcon(resolveInfo, pm);
Jim Millerfefef312010-11-09 14:08:39 -0800476 int id = recentTasks.get(i).id;
Jim Miller44c66fe2010-10-20 18:32:52 -0700477 if (title != null && title.length() > 0 && icon != null) {
Jim Millere5c16ab2010-12-03 19:18:38 -0800478 if (DEBUG) Log.v(TAG, "creating activity desc for id=" + id + ", label=" + title);
Jim Millerfefef312010-11-09 14:08:39 -0800479 ActivityDescription item = new ActivityDescription(
Dianne Hackbornd94df452011-02-16 18:53:31 -0800480 am.getTaskThumbnail(recentInfo.persistentId),
481 icon, title, recentInfo.description, intent, id,
482 index, info.packageName);
Jim Millerfefef312010-11-09 14:08:39 -0800483 activityDescriptions.add(item);
484 ++index;
485 } else {
Jim Millere5c16ab2010-12-03 19:18:38 -0800486 if (DEBUG) Log.v(TAG, "SKIPPING item " + id);
Jim Miller44c66fe2010-10-20 18:32:52 -0700487 }
488 }
489 }
Jim Millerfefef312010-11-09 14:08:39 -0800490 return activityDescriptions;
491 }
492
493 ActivityDescription findActivityDescription(int id)
494 {
495 ActivityDescription desc = null;
496 for (int i = 0; i < mActivityDescriptions.size(); i++) {
497 ActivityDescription item = mActivityDescriptions.get(i);
498 if (item != null && item.id == id) {
499 desc = item;
500 break;
501 }
502 }
503 return desc;
504 }
505
Dianne Hackborn0f1de9a2011-05-11 17:34:49 -0700506 private void updateShownCompatMode() {
507 final ActivityManager am = (ActivityManager)
508 mContext.getSystemService(Context.ACTIVITY_SERVICE);
509 int mode = am.getFrontActivityScreenCompatMode();
510 switch (mode) {
511 case ActivityManager.COMPAT_MODE_DISABLED:
512 mCompatMode.setVisibility(View.VISIBLE);
513 mCompatMode.setChecked(true);
514 break;
515 case ActivityManager.COMPAT_MODE_ENABLED:
516 mCompatMode.setVisibility(View.VISIBLE);
517 mCompatMode.setChecked(false);
518 break;
519 default:
520 mCompatMode.setVisibility(View.GONE);
521 break;
522 }
523 }
524
Jim Millerfefef312010-11-09 14:08:39 -0800525 private void refreshApplicationList() {
526 mActivityDescriptions = getRecentTasks();
Jim Miller5fda69c2011-02-16 15:17:11 -0800527 mListAdapter.notifyDataSetInvalidated();
Jim Miller01f99442011-01-10 21:02:25 -0800528 if (mActivityDescriptions.size() > 0) {
Jim Miller5fda69c2011-02-16 15:17:11 -0800529 mLastVisibleItem = mActivityDescriptions.size() - 1; // scroll to bottom after reloading
530 updateUiElements(getResources().getConfiguration());
Dianne Hackborn0f1de9a2011-05-11 17:34:49 -0700531 updateShownCompatMode();
Jim Miller01f99442011-01-10 21:02:25 -0800532 } else {
Jim Miller85babff2011-01-11 14:26:03 -0800533 // Immediately hide this panel
Jim Millerf1e22e52011-01-26 15:39:51 -0800534 hide(false);
Jim Miller01f99442011-01-10 21:02:25 -0800535 }
Jim Millerfefef312010-11-09 14:08:39 -0800536 }
537
Jim Millerf9905b42010-12-22 20:37:17 -0800538 private Bitmap compositeBitmap(Bitmap background, Bitmap thumbnail) {
539 Bitmap outBitmap = background.copy(background.getConfig(), true);
Jim Miller25eef892011-01-04 13:52:22 -0800540 if (thumbnail != null) {
541 Canvas canvas = new Canvas(outBitmap);
542 Paint paint = new Paint();
543 paint.setAntiAlias(true);
544 paint.setFilterBitmap(true);
545 paint.setAlpha(255);
546 final int srcWidth = thumbnail.getWidth();
Jim Millere70d5062011-03-08 21:38:39 -0800547 final int srcHeight = thumbnail.getHeight();
Jim Miller25eef892011-01-04 13:52:22 -0800548 canvas.drawBitmap(thumbnail,
549 new Rect(0, 0, srcWidth-1, srcHeight-1),
550 new RectF(GLOW_PADDING,
Jim Miller5fda69c2011-02-16 15:17:11 -0800551 GLOW_PADDING - 7.0f,
552 outBitmap.getWidth() - GLOW_PADDING + 3.0f,
553 outBitmap.getHeight() - GLOW_PADDING + 7.0f), paint);
Jim Miller25eef892011-01-04 13:52:22 -0800554 }
Jim Millere5c16ab2010-12-03 19:18:38 -0800555 return outBitmap;
556 }
557
Jim Miller5fda69c2011-02-16 15:17:11 -0800558 private void updateUiElements(Configuration config) {
559 final int items = mActivityDescriptions.size();
Jim Millere5c16ab2010-12-03 19:18:38 -0800560
Jim Miller5fda69c2011-02-16 15:17:11 -0800561 mRecentsContainer.setVisibility(items > 0 ? View.VISIBLE : View.GONE);
562 mRecentsGlowView.setVisibility(items > 0 ? View.VISIBLE : View.GONE);
Jim Miller44c66fe2010-10-20 18:32:52 -0700563 }
564
Jim Miller5fda69c2011-02-16 15:17:11 -0800565 private void hide(boolean animate) {
566 if (!animate) {
567 setVisibility(View.GONE);
568 }
569 mBar.animateCollapse();
570 }
571
572 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
573 ActivityDescription ad = ((ViewHolder) view.getTag()).activityDescription;
Jim Millere5c16ab2010-12-03 19:18:38 -0800574 final ActivityManager am = (ActivityManager)
575 getContext().getSystemService(Context.ACTIVITY_SERVICE);
Dianne Hackbornb6777462010-11-12 12:43:22 -0800576 if (ad.id >= 0) {
577 // This is an active task; it should just go to the foreground.
Dianne Hackborn621e17d2010-11-22 15:59:56 -0800578 am.moveTaskToFront(ad.id, ActivityManager.MOVE_TASK_WITH_HOME);
Dianne Hackbornb6777462010-11-12 12:43:22 -0800579 } else {
580 Intent intent = ad.intent;
Dianne Hackborn621e17d2010-11-22 15:59:56 -0800581 intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
582 | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
Dianne Hackbornb6777462010-11-12 12:43:22 -0800583 if (DEBUG) Log.v(TAG, "Starting activity " + intent);
584 getContext().startActivity(intent);
585 }
Jim Millerf1e22e52011-01-26 15:39:51 -0800586 hide(true);
587 }
Jim Miller44c66fe2010-10-20 18:32:52 -0700588}