Recents.java revision 9214eff52adf56b7c9532e40b784d52f9f94b6d1
1/* 2 * Copyright (C) 2013 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 17package com.android.systemui.recent; 18 19import android.app.ActivityOptions; 20import android.content.ActivityNotFoundException; 21import android.content.Intent; 22import android.content.res.Configuration; 23import android.content.res.Resources; 24import android.graphics.Bitmap; 25import android.graphics.Canvas; 26import android.graphics.Paint; 27import android.graphics.drawable.BitmapDrawable; 28import android.graphics.drawable.Drawable; 29import android.os.Bundle; 30import android.os.UserHandle; 31import android.util.DisplayMetrics; 32import android.util.Log; 33import android.view.Display; 34import android.view.View; 35import com.android.systemui.R; 36import com.android.systemui.RecentsComponent; 37import com.android.systemui.SystemUI; 38import com.android.systemui.recents.AlternateRecentsComponent; 39 40 41public class Recents extends SystemUI implements RecentsComponent { 42 private static final String TAG = "Recents"; 43 private static final boolean DEBUG = true; 44 45 // Which recents to use 46 boolean mUseAlternateRecents = true; 47 AlternateRecentsComponent mAlternateRecents; 48 boolean mBootCompleted = false; 49 50 @Override 51 public void start() { 52 if (mUseAlternateRecents) { 53 if (mAlternateRecents == null) { 54 mAlternateRecents = new AlternateRecentsComponent(mContext); 55 } 56 mAlternateRecents.onStart(); 57 } 58 59 putComponent(RecentsComponent.class, this); 60 } 61 62 @Override 63 protected void onBootCompleted() { 64 if (mUseAlternateRecents) { 65 if (mAlternateRecents != null) { 66 mAlternateRecents.onBootCompleted(); 67 } 68 } 69 mBootCompleted = true; 70 } 71 72 @Override 73 public void showRecents(boolean triggeredFromAltTab, View statusBarView) { 74 if (mUseAlternateRecents) { 75 mAlternateRecents.onShowRecents(triggeredFromAltTab, statusBarView); 76 } 77 } 78 79 @Override 80 public void hideRecents(boolean triggeredFromAltTab) { 81 if (mUseAlternateRecents) { 82 mAlternateRecents.onHideRecents(triggeredFromAltTab); 83 } else { 84 Intent intent = new Intent(RecentsActivity.CLOSE_RECENTS_INTENT); 85 intent.setPackage("com.android.systemui"); 86 sendBroadcastSafely(intent); 87 88 RecentTasksLoader.getInstance(mContext).cancelPreloadingFirstTask(); 89 } 90 } 91 92 @Override 93 public void toggleRecents(Display display, int layoutDirection, View statusBarView) { 94 if (mUseAlternateRecents) { 95 // Launch the alternate recents if required 96 mAlternateRecents.onToggleRecents(statusBarView); 97 return; 98 } 99 100 if (DEBUG) Log.d(TAG, "toggle recents panel"); 101 try { 102 TaskDescription firstTask = RecentTasksLoader.getInstance(mContext).getFirstTask(); 103 104 Intent intent = new Intent(RecentsActivity.TOGGLE_RECENTS_INTENT); 105 intent.setClassName("com.android.systemui", 106 "com.android.systemui.recent.RecentsActivity"); 107 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 108 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); 109 110 if (firstTask == null) { 111 if (RecentsActivity.forceOpaqueBackground(mContext)) { 112 ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext, 113 R.anim.recents_launch_from_launcher_enter, 114 R.anim.recents_launch_from_launcher_exit); 115 mContext.startActivityAsUser(intent, opts.toBundle(), new UserHandle( 116 UserHandle.USER_CURRENT)); 117 } else { 118 // The correct window animation will be applied via the activity's style 119 mContext.startActivityAsUser(intent, new UserHandle( 120 UserHandle.USER_CURRENT)); 121 } 122 123 } else { 124 Bitmap first = null; 125 if (firstTask.getThumbnail() instanceof BitmapDrawable) { 126 first = ((BitmapDrawable) firstTask.getThumbnail()).getBitmap(); 127 } else { 128 first = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); 129 Drawable d = RecentTasksLoader.getInstance(mContext).getDefaultThumbnail(); 130 d.draw(new Canvas(first)); 131 } 132 final Resources res = mContext.getResources(); 133 134 float thumbWidth = res 135 .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_width); 136 float thumbHeight = res 137 .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_height); 138 if (first == null) { 139 throw new RuntimeException("Recents thumbnail is null"); 140 } 141 if (first.getWidth() != thumbWidth || first.getHeight() != thumbHeight) { 142 first = Bitmap.createScaledBitmap(first, (int) thumbWidth, (int) thumbHeight, 143 true); 144 if (first == null) { 145 throw new RuntimeException("Recents thumbnail is null"); 146 } 147 } 148 149 150 DisplayMetrics dm = new DisplayMetrics(); 151 display.getMetrics(dm); 152 // calculate it here, but consider moving it elsewhere 153 // first, determine which orientation you're in. 154 final Configuration config = res.getConfiguration(); 155 int x, y; 156 157 if (config.orientation == Configuration.ORIENTATION_PORTRAIT) { 158 float appLabelLeftMargin = res.getDimensionPixelSize( 159 R.dimen.status_bar_recents_app_label_left_margin); 160 float appLabelWidth = res.getDimensionPixelSize( 161 R.dimen.status_bar_recents_app_label_width); 162 float thumbLeftMargin = res.getDimensionPixelSize( 163 R.dimen.status_bar_recents_thumbnail_left_margin); 164 float thumbBgPadding = res.getDimensionPixelSize( 165 R.dimen.status_bar_recents_thumbnail_bg_padding); 166 167 float width = appLabelLeftMargin + 168 +appLabelWidth 169 + thumbLeftMargin 170 + thumbWidth 171 + 2 * thumbBgPadding; 172 173 x = (int) ((dm.widthPixels - width) / 2f + appLabelLeftMargin + appLabelWidth 174 + thumbBgPadding + thumbLeftMargin); 175 y = (int) (dm.heightPixels 176 - res.getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_height) 177 - thumbBgPadding); 178 if (layoutDirection == View.LAYOUT_DIRECTION_RTL) { 179 x = dm.widthPixels - x - res.getDimensionPixelSize( 180 R.dimen.status_bar_recents_thumbnail_width); 181 } 182 183 } else { // if (config.orientation == Configuration.ORIENTATION_LANDSCAPE) { 184 float thumbTopMargin = res.getDimensionPixelSize( 185 R.dimen.status_bar_recents_thumbnail_top_margin); 186 float thumbBgPadding = res.getDimensionPixelSize( 187 R.dimen.status_bar_recents_thumbnail_bg_padding); 188 float textPadding = res.getDimensionPixelSize( 189 R.dimen.status_bar_recents_text_description_padding); 190 float labelTextSize = res.getDimensionPixelSize( 191 R.dimen.status_bar_recents_app_label_text_size); 192 Paint p = new Paint(); 193 p.setTextSize(labelTextSize); 194 float labelTextHeight = p.getFontMetricsInt().bottom 195 - p.getFontMetricsInt().top; 196 float descriptionTextSize = res.getDimensionPixelSize( 197 R.dimen.status_bar_recents_app_description_text_size); 198 p.setTextSize(descriptionTextSize); 199 float descriptionTextHeight = p.getFontMetricsInt().bottom 200 - p.getFontMetricsInt().top; 201 202 float statusBarHeight = res.getDimensionPixelSize( 203 com.android.internal.R.dimen.status_bar_height); 204 float recentsItemTopPadding = statusBarHeight; 205 206 float height = thumbTopMargin 207 + thumbHeight 208 + 2 * thumbBgPadding + textPadding + labelTextHeight 209 + recentsItemTopPadding + textPadding + descriptionTextHeight; 210 float recentsItemRightPadding = res 211 .getDimensionPixelSize(R.dimen.status_bar_recents_item_padding); 212 float recentsScrollViewRightPadding = res 213 .getDimensionPixelSize(R.dimen.status_bar_recents_right_glow_margin); 214 x = (int) (dm.widthPixels - res 215 .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_width) 216 - thumbBgPadding - recentsItemRightPadding 217 - recentsScrollViewRightPadding); 218 y = (int) ((dm.heightPixels - statusBarHeight - height) / 2f + thumbTopMargin 219 + recentsItemTopPadding + thumbBgPadding + statusBarHeight); 220 } 221 222 ActivityOptions opts = ActivityOptions.makeThumbnailScaleDownAnimation( 223 statusBarView, 224 first, x, y, 225 new ActivityOptions.OnAnimationStartedListener() { 226 public void onAnimationStarted() { 227 Intent intent = 228 new Intent(RecentsActivity.WINDOW_ANIMATION_START_INTENT); 229 intent.setPackage("com.android.systemui"); 230 sendBroadcastSafely(intent); 231 } 232 }); 233 intent.putExtra(RecentsActivity.WAITING_FOR_WINDOW_ANIMATION_PARAM, true); 234 startActivitySafely(intent, opts.toBundle()); 235 } 236 } catch (ActivityNotFoundException e) { 237 Log.e(TAG, "Failed to launch RecentAppsIntent", e); 238 } 239 } 240 241 @Override 242 protected void onConfigurationChanged(Configuration newConfig) { 243 if (mUseAlternateRecents) { 244 mAlternateRecents.onConfigurationChanged(newConfig); 245 } 246 } 247 248 @Override 249 public void preloadRecents() { 250 if (mUseAlternateRecents) { 251 mAlternateRecents.onPreloadRecents(); 252 } else { 253 Intent intent = new Intent(RecentsActivity.PRELOAD_INTENT); 254 intent.setClassName("com.android.systemui", 255 "com.android.systemui.recent.RecentsPreloadReceiver"); 256 sendBroadcastSafely(intent); 257 258 RecentTasksLoader.getInstance(mContext).preloadFirstTask(); 259 } 260 } 261 262 @Override 263 public void cancelPreloadingRecents() { 264 if (mUseAlternateRecents) { 265 mAlternateRecents.onCancelPreloadingRecents(); 266 } else { 267 Intent intent = new Intent(RecentsActivity.CANCEL_PRELOAD_INTENT); 268 intent.setClassName("com.android.systemui", 269 "com.android.systemui.recent.RecentsPreloadReceiver"); 270 sendBroadcastSafely(intent); 271 272 RecentTasksLoader.getInstance(mContext).cancelPreloadingFirstTask(); 273 } 274 } 275 276 @Override 277 public void setCallback(Callbacks cb) { 278 if (mUseAlternateRecents) { 279 mAlternateRecents.setRecentsComponentCallback(cb); 280 } 281 } 282 283 /** 284 * Send broadcast only if BOOT_COMPLETED 285 */ 286 private void sendBroadcastSafely(Intent intent) { 287 if (!mBootCompleted) return; 288 mContext.sendBroadcastAsUser(intent, new UserHandle(UserHandle.USER_CURRENT)); 289 } 290 291 /** 292 * Start activity only if BOOT_COMPLETED 293 */ 294 private void startActivitySafely(Intent intent, Bundle opts) { 295 if (!mBootCompleted) return; 296 mContext.startActivityAsUser(intent, opts, new UserHandle(UserHandle.USER_CURRENT)); 297 } 298} 299