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