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