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 18 package com.android.carouseltest; 19 20 import java.util.ArrayList; 21 import java.util.List; 22 import com.android.carouseltest.R; 23 24 import com.android.ex.carousel.CarouselController; 25 import com.android.ex.carousel.CarouselViewHelper; 26 27 import android.app.Activity; 28 import android.app.ActivityManager; 29 import android.app.IThumbnailReceiver; 30 import android.app.ActivityManager.RunningTaskInfo; 31 import android.content.ActivityNotFoundException; 32 import android.content.Context; 33 import android.content.Intent; 34 import android.content.pm.ActivityInfo; 35 import android.content.pm.PackageManager; 36 import android.content.pm.ResolveInfo; 37 import android.content.res.Configuration; 38 import android.content.res.Resources; 39 import android.graphics.Bitmap; 40 import android.graphics.BitmapFactory; 41 import android.graphics.Canvas; 42 import android.graphics.Matrix; 43 import android.graphics.Paint; 44 import android.graphics.Bitmap.Config; 45 import android.graphics.drawable.Drawable; 46 import android.os.Bundle; 47 import android.os.RemoteException; 48 import android.util.Log; 49 import android.view.View; 50 51 public 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 ActivityDescription(Bitmap _thumbnail, Drawable _icon, String _label, String _desc, int _id)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 clear()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 findActivityDescription(int id)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 LocalCarouselViewHelper(Context context)114 public LocalCarouselViewHelper(Context context) { 115 super(context); 116 } 117 118 @Override getDetailTextureParameters(int id)119 public DetailTextureParameters getDetailTextureParameters(int id) { 120 return mDetailTextureParameters; 121 } 122 123 @Override onCardSelected(int n)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 getTexture(int n)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 getDetailTexture(int n)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 onCreate(Bundle savedInstanceState)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 onResume()225 protected void onResume() { 226 super.onResume(); 227 mHelper.onResume(); 228 refresh(); 229 } 230 231 @Override onPause()232 protected void onPause() { 233 super.onPause(); 234 mHelper.onPause(); 235 } 236 237 @Override onConfigurationChanged(Configuration newConfig)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 updateRunningTasks()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 updateRecentTasks()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 refresh()326 private void refresh() { 327 updateRecentTasks(); 328 updateRunningTasks(); 329 mView.createCards(mActivityDescriptions.size()); 330 } 331 } 332