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