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.CarouselController;
25import com.android.ex.carousel.CarouselViewHelper;
26
27import 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.BitmapFactory;
41import android.graphics.Canvas;
42import android.graphics.Matrix;
43import android.graphics.Paint;
44import android.graphics.Bitmap.Config;
45import android.graphics.drawable.Drawable;
46import android.os.Bundle;
47import android.os.RemoteException;
48import android.util.Log;
49import android.view.View;
50
51public class TaskSwitcherActivity extends Activity {
52    private static final String TAG = "TaskSwitcherActivity";
53    private static final int CARD_SLOTS = 56;
54    private static final int MAX_TASKS = 20;
55    private static final int VISIBLE_SLOTS = 7;
56    protected static final boolean DBG = false;
57    private ActivityManager mActivityManager;
58    private List<RunningTaskInfo> mRunningTaskList;
59    private boolean mPortraitMode = true;
60    private ArrayList<ActivityDescription> mActivityDescriptions
61            = new ArrayList<ActivityDescription>();
62    private CarouselController mController;
63    private MyCarouselView mView;
64    private Bitmap mBlankBitmap = Bitmap.createBitmap(128, 128, Config.RGB_565);
65    private LocalCarouselViewHelper mHelper;
66
67    static class ActivityDescription {
68        int id;
69        Bitmap thumbnail;
70        Drawable icon;
71        CharSequence label;
72        CharSequence description;
73        Intent intent;
74        Matrix matrix;
75
76        public ActivityDescription(Bitmap _thumbnail,
77                Drawable _icon, String _label, String _desc, int _id)
78        {
79            thumbnail = _thumbnail;
80            icon = _icon;
81            label = _label;
82            description = _desc;
83            id = _id;
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        }
95    };
96
97    private ActivityDescription findActivityDescription(int id) {
98        for (int i = 0; i < mActivityDescriptions.size(); i++) {
99            ActivityDescription item = mActivityDescriptions.get(i);
100            if (item != null && item.id == id) {
101                return item;
102            }
103        }
104        return null;
105    }
106
107    class LocalCarouselViewHelper extends CarouselViewHelper {
108        private static final int DETAIL_TEXTURE_WIDTH = 256;
109        private static final int DETAIL_TEXTURE_HEIGHT = 80;
110        private Paint mPaint = new Paint();
111        private DetailTextureParameters mDetailTextureParameters
112                = new DetailTextureParameters(5.0f, 5.0f);
113
114        public LocalCarouselViewHelper(Context context) {
115            super(context);
116        }
117
118        @Override
119        public DetailTextureParameters getDetailTextureParameters(int id) {
120            return mDetailTextureParameters;
121        }
122
123        @Override
124        public void onCardSelected(int n) {
125            if (n < mActivityDescriptions.size()) {
126                ActivityDescription item = mActivityDescriptions.get(n);
127                // prepare a launch intent and send it
128                if (item.intent != null) {
129                    item.intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
130                    try {
131                        Log.v(TAG, "Starting intent " + item.intent);
132                        startActivity(item.intent);
133                        overridePendingTransition(R.anim.zoom_enter, R.anim.zoom_exit);
134                    } catch (ActivityNotFoundException e) {
135                        Log.w("Recent", "Unable to launch recent task", e);
136                    }
137                    finish();
138                }
139            }
140        }
141
142        @Override
143        public Bitmap getTexture(int n) {
144            ActivityDescription desc = mActivityDescriptions.get(n);
145            Bitmap bitmap = desc.thumbnail == null ? mBlankBitmap : desc.thumbnail;
146            return bitmap;
147        }
148
149        @Override
150        public Bitmap getDetailTexture(int n) {
151            Bitmap bitmap = null;
152            if (n < mActivityDescriptions.size()) {
153                ActivityDescription item = mActivityDescriptions.get(n);
154                bitmap = Bitmap.createBitmap(DETAIL_TEXTURE_WIDTH, DETAIL_TEXTURE_HEIGHT,
155                    Bitmap.Config.ARGB_8888);
156                Canvas canvas = new Canvas(bitmap);
157                canvas.drawARGB(128,128,128,255);
158                mPaint.setTextSize(15.0f);
159                mPaint.setColor(0xffffffff);
160                mPaint.setAntiAlias(true);
161                canvas.drawText(item.label.toString(),0, DETAIL_TEXTURE_HEIGHT/2, mPaint);
162            }
163            return bitmap;
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            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            } else {
193                Log.v(TAG, "Can't find view for id " + id);
194            }
195        }
196    };
197
198    @Override
199    protected void onCreate(Bundle savedInstanceState) {
200        super.onCreate(savedInstanceState);
201
202        final Resources res = getResources();
203        final View decorView = getWindow().getDecorView();
204
205        mController = new CarouselController();
206        mView = new MyCarouselView(this, mController);
207        mHelper = new LocalCarouselViewHelper(this);
208        mHelper.setCarouselView(mView);
209        mView.setSlotCount(CARD_SLOTS);
210        mView.setVisibleSlots(VISIBLE_SLOTS);
211        mView.createCards(1);
212        mView.setStartAngle((float) -(2.0f*Math.PI * 5 / CARD_SLOTS));
213        mView.setDefaultBitmap(BitmapFactory.decodeResource(res, R.drawable.wait));
214        mView.setLoadingBitmap(BitmapFactory.decodeResource(res, R.drawable.wait));
215        mView.setBackgroundColor(0.1f, 0.1f, 0.1f, 1.0f);
216
217        mActivityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
218        mPortraitMode = decorView.getHeight() > decorView.getWidth();
219
220        refresh();
221        setContentView(mView);
222    }
223
224    @Override
225    protected void onResume() {
226        super.onResume();
227        mHelper.onResume();
228        refresh();
229    }
230
231    @Override
232    protected void onPause() {
233        super.onPause();
234        mHelper.onPause();
235    }
236
237    @Override
238    public void onConfigurationChanged(Configuration newConfig) {
239        super.onConfigurationChanged(newConfig);
240        mPortraitMode = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT;
241        Log.v(TAG, "CONFIG CHANGE, mPortraitMode = " + mPortraitMode);
242        refresh();
243    }
244
245    void updateRunningTasks() {
246        mRunningTaskList = mActivityManager.getRunningTasks(MAX_TASKS + 2, 0, mThumbnailReceiver);
247        Log.v(TAG, "Portrait: " + mPortraitMode);
248        for (RunningTaskInfo r : mRunningTaskList) {
249            if (r.thumbnail != null) {
250                int thumbWidth = r.thumbnail.getWidth();
251                int thumbHeight = r.thumbnail.getHeight();
252                Log.v(TAG, "Got thumbnail " + thumbWidth + "x" + thumbHeight);
253                ActivityDescription desc = findActivityDescription(r.id);
254                if (desc != null) {
255                    desc.thumbnail = r.thumbnail;
256                    desc.description = r.description;
257                    if ((mPortraitMode && thumbWidth > thumbHeight)
258                            || (!mPortraitMode && thumbWidth < thumbHeight)) {
259                        Matrix matrix = new Matrix();
260                        matrix.setRotate(90.0f, (float) thumbWidth / 2, (float) thumbHeight / 2);
261                        desc.matrix = matrix;
262                    }
263                } else {
264                    Log.v(TAG, "Couldn't find ActivityDesc for id=" + r.id);
265                }
266            } else {
267                Log.v(TAG, "*** RUNNING THUMBNAIL WAS NULL ***");
268            }
269        }
270        // HACK refresh carousel
271        mView.createCards(mActivityDescriptions.size());
272    }
273
274    private void updateRecentTasks() {
275        final PackageManager pm = getPackageManager();
276        final ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
277
278        final List<ActivityManager.RecentTaskInfo> recentTasks =
279                am.getRecentTasks(MAX_TASKS + 2, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
280
281        ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
282                    .resolveActivityInfo(pm, 0);
283
284        //IconUtilities iconUtilities = new IconUtilities(this);
285
286        int numTasks = recentTasks.size();
287        mActivityDescriptions.clear();
288        for (int i = 1, index = 0; i < numTasks && (index < MAX_TASKS + 2); ++i) {
289            final ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(i);
290
291            Intent intent = new Intent(recentInfo.baseIntent);
292            if (recentInfo.origActivity != null) {
293                intent.setComponent(recentInfo.origActivity);
294            }
295
296            // Skip the current home activity.
297            if (homeInfo != null
298                    && homeInfo.packageName.equals(intent.getComponent().getPackageName())
299                    && homeInfo.name.equals(intent.getComponent().getClassName())) {
300                continue;
301            }
302
303            intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
304                    | Intent.FLAG_ACTIVITY_NEW_TASK);
305            final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
306            if (resolveInfo != null) {
307                final ActivityInfo info = resolveInfo.activityInfo;
308                final String title = info.loadLabel(pm).toString();
309                Drawable icon = info.loadIcon(pm);
310
311                int id = recentInfo.id;
312                if (id != -1 && title != null && title.length() > 0 && icon != null) {
313                    //icon = iconUtilities.createIconDrawable(icon);
314                    ActivityDescription item = new ActivityDescription(null, icon, title, null, id);
315                    item.intent = intent;
316                    mActivityDescriptions.add(item);
317                    Log.v(TAG, "Added item[" + index + "], id=" + item.id);
318                    ++index;
319                } else {
320                    Log.v(TAG, "SKIPPING item " + id);
321                }
322            }
323        }
324    }
325
326    private void refresh() {
327        updateRecentTasks();
328        updateRunningTasks();
329        mView.createCards(mActivityDescriptions.size());
330    }
331}
332