blob: 6e5d241dee137de42a52f372baf260f6d6a71264 [file] [log] [blame]
Jim Millere6ad1a82010-08-20 19:25:39 -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
17
18package com.android.systemui.statusbar;
19
Jim Miller783cb602010-09-02 18:08:05 -070020import com.android.ex.carousel.CarouselView;
21import com.android.ex.carousel.CarouselRS.CarouselCallback;
Jim Millere6ad1a82010-08-20 19:25:39 -070022import com.android.internal.R;
23
24import java.util.ArrayList;
25import java.util.List;
26
Jim Millere6ad1a82010-08-20 19:25:39 -070027import android.app.Activity;
28import android.app.ActivityManager;
29import android.app.IThumbnailReceiver;
30import android.app.ActivityManager.RunningTaskInfo;
31import android.content.ActivityNotFoundException;
32import android.content.Context;
33import android.content.Intent;
34import android.content.pm.ActivityInfo;
35import android.content.pm.PackageManager;
36import android.content.pm.ResolveInfo;
37import android.content.res.Configuration;
38import android.content.res.Resources;
39import android.graphics.Bitmap;
40import android.graphics.Matrix;
41import android.graphics.Bitmap.Config;
42import android.graphics.drawable.Drawable;
43import android.graphics.PixelFormat;
44import android.os.Bundle;
45import android.os.RemoteException;
46import android.util.Log;
47import android.view.View;
48
49public class RecentApplicationsActivity extends Activity {
50 private static final String TAG = "RecentApplicationsActivity";
51 private static boolean DBG = true;
52 private static final int CARD_SLOTS = 56;
53 private static final int VISIBLE_SLOTS = 7;
54 private static final int MAX_TASKS = VISIBLE_SLOTS * 2;
55 private ActivityManager mActivityManager;
56 private List<RunningTaskInfo> mRunningTaskList;
57 private boolean mPortraitMode = true;
58 private ArrayList<ActivityDescription> mActivityDescriptions
59 = new ArrayList<ActivityDescription>();
60 private CarouselView mCarouselView;
61 private View mNoRecentsView;
62 private Bitmap mBlankBitmap = Bitmap.createBitmap(
63 new int[] {0xff808080, 0xffffffff, 0xff808080, 0xffffffff}, 2, 2, Config.RGB_565);
64
65 static class ActivityDescription {
66 int id;
67 Bitmap thumbnail; // generated by Activity.onCreateThumbnail()
68 Drawable icon; // application package icon
69 String label; // application package label
70 String description; // generated by Activity.onCreateDescription()
71 Intent intent; // launch intent for application
72 Matrix matrix; // arbitrary rotation matrix to correct orientation
73 int position; // position in list
74
75 public ActivityDescription(Bitmap _thumbnail,
76 Drawable _icon, String _label, String _desc, int _id, int _pos)
77 {
78 thumbnail = _thumbnail;
79 icon = _icon;
80 label = _label;
81 description = _desc;
82 id = _id;
83 position = _pos;
84 }
85
86 public void clear() {
87 icon = null;
88 thumbnail = null;
89 label = null;
90 description = null;
91 intent = null;
92 matrix = null;
93 id = -1;
94 position = -1;
95 }
96 };
97
98 private ActivityDescription findActivityDescription(int id) {
99 for (int i = 0; i < mActivityDescriptions.size(); i++) {
100 ActivityDescription item = mActivityDescriptions.get(i);
101 if (item != null && item.id == id) {
102 return item;
103 }
104 }
105 return null;
106 }
107
108 final CarouselCallback mCarouselCallback = new CarouselCallback() {
109
110 public void onAnimationFinished() {
111
112 }
113
114 public void onAnimationStarted() {
115
116 }
117
118 public void onCardSelected(int n) {
119 if (n < mActivityDescriptions.size()) {
120 ActivityDescription item = mActivityDescriptions.get(n);
121 // prepare a launch intent and send it
122 if (item.intent != null) {
123 item.intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
124 try {
125 if (DBG) Log.v(TAG, "Starting intent " + item.intent);
126 startActivity(item.intent);
127 //overridePendingTransition(R.anim.zoom_enter, R.anim.zoom_exit);
128 } catch (ActivityNotFoundException e) {
129 if (DBG) Log.w("Recent", "Unable to launch recent task", e);
130 }
131 finish();
132 }
133 }
134 }
135
136 public void onInvalidateTexture(int n) {
137
138 }
139
140 public void onRequestGeometry(int n) {
141
142 }
143
144 public void onInvalidateGeometry(int n) {
145
146 }
147
148 public void onRequestTexture(final int n) {
149 if (DBG) Log.v(TAG, "onRequestTexture(" + n + ")");
150 if (n < mActivityDescriptions.size()) {
151 mCarouselView.post(new Runnable() {
152 public void run() {
153 ActivityDescription info = mActivityDescriptions.get(n);
154 if (info != null) {
155 if (DBG) Log.v(TAG, "FOUND ACTIVITY THUMBNAIL " + info.thumbnail);
156 Bitmap bitmap = info.thumbnail == null ? mBlankBitmap : info.thumbnail;
157 mCarouselView.setTextureForItem(n, bitmap);
158 } else {
159 if (DBG) Log.v(TAG, "FAILED TO GET ACTIVITY THUMBNAIL FOR ITEM " + n);
160 }
161 }
162 });
163 }
164 }
165 };
166
167 private final IThumbnailReceiver mThumbnailReceiver = new IThumbnailReceiver.Stub() {
168
169 public void finished() throws RemoteException {
170
171 }
172
173 public void newThumbnail(final int id, final Bitmap bitmap, CharSequence description)
174 throws RemoteException {
175 int w = bitmap.getWidth();
176 int h = bitmap.getHeight();
177 if (DBG) Log.v(TAG, "New thumbnail for id=" + id + ", dimensions=" + w + "x" + h
178 + " description '" + description + "'");
179 ActivityDescription info = findActivityDescription(id);
180 if (info != null) {
181 info.thumbnail = bitmap;
182 final int thumbWidth = bitmap.getWidth();
183 final int thumbHeight = bitmap.getHeight();
184 if ((mPortraitMode && thumbWidth > thumbHeight)
185 || (!mPortraitMode && thumbWidth < thumbHeight)) {
186 Matrix matrix = new Matrix();
187 matrix.setRotate(90.0f, (float) thumbWidth / 2, (float) thumbHeight / 2);
188 info.matrix = matrix;
189 } else {
190 info.matrix = null;
191 }
192 mCarouselView.setTextureForItem(info.position, info.thumbnail);
193 } else {
194 if (DBG) Log.v(TAG, "Can't find view for id " + id);
195 }
196 }
197 };
198
199 @Override
200 protected void onCreate(Bundle savedInstanceState) {
201 super.onCreate(savedInstanceState);
202
203 final Resources res = getResources();
204 final View decorView = getWindow().getDecorView();
205
206 getWindow().getDecorView().setBackgroundColor(0x80000000);
207 setContentView(R.layout.recent_apps_activity);
208 mCarouselView = (CarouselView)findViewById(R.id.carousel);
209 mNoRecentsView = (View) findViewById(R.id.no_applications_message);
210 //mCarouselView = new CarouselView(this);
211 //setContentView(mCarouselView);
212 mCarouselView.setSlotCount(CARD_SLOTS);
213 mCarouselView.setVisibleSlots(VISIBLE_SLOTS);
214 mCarouselView.createCards(1);
215 mCarouselView.setStartAngle((float) -(2.0f*Math.PI * 5 / CARD_SLOTS));
216 mCarouselView.setDefaultBitmap(mBlankBitmap);
217 mCarouselView.setLoadingBitmap(mBlankBitmap);
218 mCarouselView.setCallback(mCarouselCallback);
219 mCarouselView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
220
221 mActivityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
222 mPortraitMode = decorView.getHeight() > decorView.getWidth();
223
224 refresh();
225
226
227 }
228
229 @Override
230 protected void onResume() {
231 super.onResume();
232 refresh();
233 }
234
235 @Override
236 public void onConfigurationChanged(Configuration newConfig) {
237 super.onConfigurationChanged(newConfig);
238 mPortraitMode = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT;
239 if (DBG) Log.v(TAG, "CONFIG CHANGE, mPortraitMode = " + mPortraitMode);
240 refresh();
241 }
242
243 void updateRunningTasks() {
244 mRunningTaskList = mActivityManager.getRunningTasks(MAX_TASKS, 0, mThumbnailReceiver);
245 if (DBG) Log.v(TAG, "Portrait: " + mPortraitMode);
246 for (RunningTaskInfo r : mRunningTaskList) {
247 if (r.thumbnail != null) {
248 int thumbWidth = r.thumbnail.getWidth();
249 int thumbHeight = r.thumbnail.getHeight();
250 if (DBG) Log.v(TAG, "Got thumbnail " + thumbWidth + "x" + thumbHeight);
251 ActivityDescription desc = findActivityDescription(r.id);
252 if (desc != null) {
253 desc.thumbnail = r.thumbnail;
254 desc.label = r.topActivity.flattenToShortString();
255 if ((mPortraitMode && thumbWidth > thumbHeight)
256 || (!mPortraitMode && thumbWidth < thumbHeight)) {
257 Matrix matrix = new Matrix();
258 matrix.setRotate(90.0f, (float) thumbWidth / 2, (float) thumbHeight / 2);
259 desc.matrix = matrix;
260 }
261 } else {
262 if (DBG) Log.v(TAG, "Couldn't find ActivityDesc for id=" + r.id);
263 }
264 } else {
265 if (DBG) Log.v(TAG, "*** RUNNING THUMBNAIL WAS NULL ***");
266 }
267 }
268 mCarouselView.createCards(mActivityDescriptions.size());
269 }
270
271 private void updateRecentTasks() {
272 final PackageManager pm = getPackageManager();
273 final ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
274
275 final List<ActivityManager.RecentTaskInfo> recentTasks =
276 am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
277
278 ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
279 .resolveActivityInfo(pm, 0);
280
281 // IconUtilities iconUtilities = new IconUtilities(this); // FIXME
282
283 int numTasks = recentTasks.size();
284 mActivityDescriptions.clear();
285 for (int i = 0, index = 0; i < numTasks && (index < MAX_TASKS); ++i) {
286 final ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(i);
287
288 Intent intent = new Intent(recentInfo.baseIntent);
289 if (recentInfo.origActivity != null) {
290 intent.setComponent(recentInfo.origActivity);
291 }
292
293 // Skip the current home activity.
294 if (homeInfo != null
295 && homeInfo.packageName.equals(intent.getComponent().getPackageName())
296 && homeInfo.name.equals(intent.getComponent().getClassName())) {
297 continue;
298 }
299
300 intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
301 | Intent.FLAG_ACTIVITY_NEW_TASK);
302 final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
303 if (resolveInfo != null) {
304 final ActivityInfo info = resolveInfo.activityInfo;
305 final String title = info.loadLabel(pm).toString();
306 Drawable icon = info.loadIcon(pm);
307
308 int id = recentTasks.get(i).id;
309 if (id != -1 && title != null && title.length() > 0 && icon != null) {
310 // icon = null; FIXME: iconUtilities.createIconDrawable(icon);
311 ActivityDescription item = new ActivityDescription(
312 null, icon, title, null, id, index);
313 item.intent = intent;
314 mActivityDescriptions.add(item);
315 if (DBG) Log.v(TAG, "Added item[" + index
316 + "], id=" + item.id
317 + ", title=" + item.label);
318 ++index;
319 } else {
320 if (DBG) Log.v(TAG, "SKIPPING item " + id);
321 }
322 }
323 }
324 }
325
326 private void refresh() {
327 updateRecentTasks();
328 updateRunningTasks();
329 if (mActivityDescriptions.size() == 0) {
330 // show "No Recent Takss"
331 mNoRecentsView.setVisibility(View.VISIBLE);
332 mCarouselView.setVisibility(View.GONE);
333 } else {
334 mNoRecentsView.setVisibility(View.GONE);
335 mCarouselView.setVisibility(View.VISIBLE);
336 mCarouselView.createCards(mActivityDescriptions.size());
337 }
338 }
339}