Launcher.java revision 7bb1749c69384faf00b238f0684d3b2e23406451
1/* 2 * Copyright (C) 2008 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.launcher2; 18 19import android.app.Activity; 20import android.app.AlertDialog; 21import android.app.Dialog; 22import android.app.ISearchManager; 23import android.app.SearchManager; 24import android.app.StatusBarManager; 25import android.app.WallpaperInfo; 26import android.app.WallpaperManager; 27import android.content.ActivityNotFoundException; 28import android.content.ComponentName; 29import android.content.Context; 30import android.content.DialogInterface; 31import android.content.Intent; 32import android.content.Intent.ShortcutIconResource; 33import android.content.pm.ActivityInfo; 34import android.content.pm.LabeledIntent; 35import android.content.pm.PackageManager; 36import android.content.pm.PackageManager.NameNotFoundException; 37import android.content.res.Configuration; 38import android.content.res.Resources; 39import android.graphics.Bitmap; 40import android.graphics.drawable.Drawable; 41import android.graphics.drawable.TransitionDrawable; 42import android.os.Bundle; 43import android.os.Looper; 44import android.os.Message; 45import android.os.MessageQueue; 46import android.os.Parcelable; 47import android.os.RemoteException; 48import android.os.ServiceManager; 49import android.provider.LiveFolders; 50import android.text.Selection; 51import android.text.SpannableStringBuilder; 52import android.text.TextUtils; 53import android.text.method.TextKeyListener; 54import static android.util.Log.*; 55import android.util.Log; 56import android.view.Display; 57import android.view.KeyEvent; 58import android.view.LayoutInflater; 59import android.view.Menu; 60import android.view.MenuItem; 61import android.view.View; 62import android.view.ViewGroup; 63import android.view.WindowManager; 64import android.view.View.OnLongClickListener; 65import android.view.inputmethod.InputMethodManager; 66import android.widget.EditText; 67import android.widget.TextView; 68import android.widget.Toast; 69import android.appwidget.AppWidgetManager; 70import android.appwidget.AppWidgetProviderInfo; 71 72import java.lang.ref.WeakReference; 73import java.util.ArrayList; 74import java.util.HashMap; 75import java.util.LinkedList; 76import java.io.DataOutputStream; 77import java.io.FileNotFoundException; 78import java.io.IOException; 79import java.io.DataInputStream; 80 81/** 82 * Default launcher application. 83 */ 84public final class Launcher extends Activity 85 implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks { 86 static final String LOG_TAG = "Launcher"; 87 static final String TAG = LOG_TAG; 88 static final boolean LOGD = false; 89 90 static final boolean PROFILE_STARTUP = false; 91 static final boolean PROFILE_ROTATE = false; 92 static final boolean DEBUG_USER_INTERFACE = false; 93 94 private static final int WALLPAPER_SCREENS_SPAN = 2; 95 96 private static final int MENU_GROUP_ADD = 1; 97 private static final int MENU_ADD = Menu.FIRST + 1; 98 private static final int MENU_WALLPAPER_SETTINGS = MENU_ADD + 1; 99 private static final int MENU_SEARCH = MENU_WALLPAPER_SETTINGS + 1; 100 private static final int MENU_NOTIFICATIONS = MENU_SEARCH + 1; 101 private static final int MENU_SETTINGS = MENU_NOTIFICATIONS + 1; 102 103 private static final int REQUEST_CREATE_SHORTCUT = 1; 104 private static final int REQUEST_CREATE_LIVE_FOLDER = 4; 105 private static final int REQUEST_CREATE_APPWIDGET = 5; 106 private static final int REQUEST_PICK_APPLICATION = 6; 107 private static final int REQUEST_PICK_SHORTCUT = 7; 108 private static final int REQUEST_PICK_LIVE_FOLDER = 8; 109 private static final int REQUEST_PICK_APPWIDGET = 9; 110 111 static final String EXTRA_SHORTCUT_DUPLICATE = "duplicate"; 112 113 static final String EXTRA_CUSTOM_WIDGET = "custom_widget"; 114 static final String SEARCH_WIDGET = "search_widget"; 115 116 static final int SCREEN_COUNT = 3; 117 static final int DEFAULT_SCREN = 1; 118 static final int NUMBER_CELLS_X = 4; 119 static final int NUMBER_CELLS_Y = 4; 120 121 static final int DIALOG_CREATE_SHORTCUT = 1; 122 static final int DIALOG_RENAME_FOLDER = 2; 123 124 private static final String PREFERENCES = "launcher.preferences"; 125 126 // Type: int 127 private static final String RUNTIME_STATE_CURRENT_SCREEN = "launcher.current_screen"; 128 // Type: boolean 129 private static final String RUNTIME_STATE_ALL_APPS_FOLDER = "launcher.all_apps_folder"; 130 // Type: long 131 private static final String RUNTIME_STATE_USER_FOLDERS = "launcher.user_folder"; 132 // Type: int 133 private static final String RUNTIME_STATE_PENDING_ADD_SCREEN = "launcher.add_screen"; 134 // Type: int 135 private static final String RUNTIME_STATE_PENDING_ADD_CELL_X = "launcher.add_cellX"; 136 // Type: int 137 private static final String RUNTIME_STATE_PENDING_ADD_CELL_Y = "launcher.add_cellY"; 138 // Type: int 139 private static final String RUNTIME_STATE_PENDING_ADD_SPAN_X = "launcher.add_spanX"; 140 // Type: int 141 private static final String RUNTIME_STATE_PENDING_ADD_SPAN_Y = "launcher.add_spanY"; 142 // Type: int 143 private static final String RUNTIME_STATE_PENDING_ADD_COUNT_X = "launcher.add_countX"; 144 // Type: int 145 private static final String RUNTIME_STATE_PENDING_ADD_COUNT_Y = "launcher.add_countY"; 146 // Type: int[] 147 private static final String RUNTIME_STATE_PENDING_ADD_OCCUPIED_CELLS = "launcher.add_occupied_cells"; 148 // Type: boolean 149 private static final String RUNTIME_STATE_PENDING_FOLDER_RENAME = "launcher.rename_folder"; 150 // Type: long 151 private static final String RUNTIME_STATE_PENDING_FOLDER_RENAME_ID = "launcher.rename_folder_id"; 152 153 static final int APPWIDGET_HOST_ID = 1024; 154 155 private static final Object sLock = new Object(); 156 private static int sScreen = DEFAULT_SCREN; 157 158 private LayoutInflater mInflater; 159 160 private DragController mDragController; 161 private SwipeController mSwipeController; 162 private Workspace mWorkspace; 163 164 private AppWidgetManager mAppWidgetManager; 165 private LauncherAppWidgetHost mAppWidgetHost; 166 167 private CellLayout.CellInfo mAddItemCellInfo; 168 private CellLayout.CellInfo mMenuAddInfo; 169 private final int[] mCellCoordinates = new int[2]; 170 private FolderInfo mFolderInfo; 171 172 private DeleteZone mDeleteZone; 173 private HandleView mHandleView; 174 private AllAppsView mAllAppsGrid; 175 176 private Bundle mSavedState; 177 178 private SpannableStringBuilder mDefaultKeySsb = null; 179 180 private boolean mIsNewIntent; 181 182 private boolean mWorkspaceLoading = true; 183 184 private boolean mRestoring; 185 private boolean mWaitingForResult; 186 private boolean mLocaleChanged; 187 188 private boolean mHomeDown; 189 private boolean mBackDown; 190 191 private Bundle mSavedInstanceState; 192 193 private LauncherModel mModel; 194 195 private ArrayList<ItemInfo> mDesktopItems = new ArrayList(); 196 private static HashMap<Long, FolderInfo> mFolders = new HashMap(); 197 private ArrayList<ApplicationInfo> mAllAppsList = new ArrayList(); 198 199 @Override 200 protected void onCreate(Bundle savedInstanceState) { 201 super.onCreate(savedInstanceState); 202 203 mModel = ((LauncherApplication)getApplication()).setLauncher(this); 204 mInflater = getLayoutInflater(); 205 206 mAppWidgetManager = AppWidgetManager.getInstance(this); 207 208 mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID); 209 mAppWidgetHost.startListening(); 210 211 if (PROFILE_STARTUP) { 212 android.os.Debug.startMethodTracing("/sdcard/launcher"); 213 } 214 215 checkForLocaleChange(); 216 setWallpaperDimension(); 217 218 setContentView(R.layout.launcher); 219 setupViews(); 220 221 lockAllApps(); 222 223 mSavedState = savedInstanceState; 224 restoreState(mSavedState); 225 226 if (PROFILE_STARTUP) { 227 android.os.Debug.stopMethodTracing(); 228 } 229 230 if (!mRestoring) { 231 mModel.startLoader(this, true); 232 } 233 234 // For handling default keys 235 mDefaultKeySsb = new SpannableStringBuilder(); 236 Selection.setSelection(mDefaultKeySsb, 0); 237 } 238 239 private void checkForLocaleChange() { 240 final LocaleConfiguration localeConfiguration = new LocaleConfiguration(); 241 readConfiguration(this, localeConfiguration); 242 243 final Configuration configuration = getResources().getConfiguration(); 244 245 final String previousLocale = localeConfiguration.locale; 246 final String locale = configuration.locale.toString(); 247 248 final int previousMcc = localeConfiguration.mcc; 249 final int mcc = configuration.mcc; 250 251 final int previousMnc = localeConfiguration.mnc; 252 final int mnc = configuration.mnc; 253 254 mLocaleChanged = !locale.equals(previousLocale) || mcc != previousMcc || mnc != previousMnc; 255 256 if (mLocaleChanged) { 257 localeConfiguration.locale = locale; 258 localeConfiguration.mcc = mcc; 259 localeConfiguration.mnc = mnc; 260 261 writeConfiguration(this, localeConfiguration); 262 AppInfoCache.flush(); 263 } 264 } 265 266 private static class LocaleConfiguration { 267 public String locale; 268 public int mcc = -1; 269 public int mnc = -1; 270 } 271 272 private static void readConfiguration(Context context, LocaleConfiguration configuration) { 273 DataInputStream in = null; 274 try { 275 in = new DataInputStream(context.openFileInput(PREFERENCES)); 276 configuration.locale = in.readUTF(); 277 configuration.mcc = in.readInt(); 278 configuration.mnc = in.readInt(); 279 } catch (FileNotFoundException e) { 280 // Ignore 281 } catch (IOException e) { 282 // Ignore 283 } finally { 284 if (in != null) { 285 try { 286 in.close(); 287 } catch (IOException e) { 288 // Ignore 289 } 290 } 291 } 292 } 293 294 private static void writeConfiguration(Context context, LocaleConfiguration configuration) { 295 DataOutputStream out = null; 296 try { 297 out = new DataOutputStream(context.openFileOutput(PREFERENCES, MODE_PRIVATE)); 298 out.writeUTF(configuration.locale); 299 out.writeInt(configuration.mcc); 300 out.writeInt(configuration.mnc); 301 out.flush(); 302 } catch (FileNotFoundException e) { 303 // Ignore 304 } catch (IOException e) { 305 //noinspection ResultOfMethodCallIgnored 306 context.getFileStreamPath(PREFERENCES).delete(); 307 } finally { 308 if (out != null) { 309 try { 310 out.close(); 311 } catch (IOException e) { 312 // Ignore 313 } 314 } 315 } 316 } 317 318 static int getScreen() { 319 synchronized (sLock) { 320 return sScreen; 321 } 322 } 323 324 static void setScreen(int screen) { 325 synchronized (sLock) { 326 sScreen = screen; 327 } 328 } 329 330 private void setWallpaperDimension() { 331 WallpaperManager wpm = (WallpaperManager)getSystemService(WALLPAPER_SERVICE); 332 333 Display display = getWindowManager().getDefaultDisplay(); 334 boolean isPortrait = display.getWidth() < display.getHeight(); 335 336 final int width = isPortrait ? display.getWidth() : display.getHeight(); 337 final int height = isPortrait ? display.getHeight() : display.getWidth(); 338 wpm.suggestDesiredDimensions(width * WALLPAPER_SCREENS_SPAN, height); 339 } 340 341 @Override 342 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 343 mWaitingForResult = false; 344 345 // The pattern used here is that a user PICKs a specific application, 346 // which, depending on the target, might need to CREATE the actual target. 347 348 // For example, the user would PICK_SHORTCUT for "Music playlist", and we 349 // launch over to the Music app to actually CREATE_SHORTCUT. 350 351 if (resultCode == RESULT_OK && mAddItemCellInfo != null) { 352 switch (requestCode) { 353 case REQUEST_PICK_APPLICATION: 354 completeAddApplication(this, data, mAddItemCellInfo); 355 break; 356 case REQUEST_PICK_SHORTCUT: 357 processShortcut(data, REQUEST_PICK_APPLICATION, REQUEST_CREATE_SHORTCUT); 358 break; 359 case REQUEST_CREATE_SHORTCUT: 360 completeAddShortcut(data, mAddItemCellInfo); 361 break; 362 case REQUEST_PICK_LIVE_FOLDER: 363 addLiveFolder(data); 364 break; 365 case REQUEST_CREATE_LIVE_FOLDER: 366 completeAddLiveFolder(data, mAddItemCellInfo); 367 break; 368 case REQUEST_PICK_APPWIDGET: 369 addAppWidget(data); 370 break; 371 case REQUEST_CREATE_APPWIDGET: 372 completeAddAppWidget(data, mAddItemCellInfo); 373 break; 374 } 375 } else if (requestCode == REQUEST_PICK_APPWIDGET && 376 resultCode == RESULT_CANCELED && data != null) { 377 // Clean up the appWidgetId if we canceled 378 int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); 379 if (appWidgetId != -1) { 380 mAppWidgetHost.deleteAppWidgetId(appWidgetId); 381 } 382 } 383 } 384 385 @Override 386 protected void onResume() { 387 super.onResume(); 388 389 if (mRestoring) { 390 mWorkspaceLoading = true; 391 mModel.startLoader(this, true); 392 mRestoring = false; 393 } 394 395 // If this was a new intent (i.e., the mIsNewIntent flag got set to true by 396 // onNewIntent), then close the search dialog if needed, because it probably 397 // came from the user pressing 'home' (rather than, for example, pressing 'back'). 398 if (mIsNewIntent) { 399 // Post to a handler so that this happens after the search dialog tries to open 400 // itself again. 401 mWorkspace.post(new Runnable() { 402 public void run() { 403 ISearchManager searchManagerService = ISearchManager.Stub.asInterface( 404 ServiceManager.getService(Context.SEARCH_SERVICE)); 405 try { 406 searchManagerService.stopSearch(); 407 } catch (RemoteException e) { 408 e(LOG_TAG, "error stopping search", e); 409 } 410 } 411 }); 412 } 413 414 mIsNewIntent = false; 415 } 416 417 @Override 418 protected void onPause() { 419 super.onPause(); 420 closeAllApps(false); 421 } 422 423 @Override 424 public Object onRetainNonConfigurationInstance() { 425 // Flag the loader to stop early before switching 426 mModel.stopLoader(); 427 428 if (PROFILE_ROTATE) { 429 android.os.Debug.startMethodTracing("/sdcard/launcher-rotate"); 430 } 431 return null; 432 } 433 434 private boolean acceptFilter() { 435 final InputMethodManager inputManager = (InputMethodManager) 436 getSystemService(Context.INPUT_METHOD_SERVICE); 437 return !inputManager.isFullscreenMode(); 438 } 439 440 @Override 441 public boolean onKeyDown(int keyCode, KeyEvent event) { 442 boolean handled = super.onKeyDown(keyCode, event); 443 if (!handled && acceptFilter() && keyCode != KeyEvent.KEYCODE_ENTER) { 444 boolean gotKey = TextKeyListener.getInstance().onKeyDown(mWorkspace, mDefaultKeySsb, 445 keyCode, event); 446 if (gotKey && mDefaultKeySsb != null && mDefaultKeySsb.length() > 0) { 447 // something usable has been typed - start a search 448 // the typed text will be retrieved and cleared by 449 // showSearchDialog() 450 // If there are multiple keystrokes before the search dialog takes focus, 451 // onSearchRequested() will be called for every keystroke, 452 // but it is idempotent, so it's fine. 453 return onSearchRequested(); 454 } 455 } 456 457 return handled; 458 } 459 460 private String getTypedText() { 461 return mDefaultKeySsb.toString(); 462 } 463 464 private void clearTypedText() { 465 mDefaultKeySsb.clear(); 466 mDefaultKeySsb.clearSpans(); 467 Selection.setSelection(mDefaultKeySsb, 0); 468 } 469 470 /** 471 * Restores the previous state, if it exists. 472 * 473 * @param savedState The previous state. 474 */ 475 private void restoreState(Bundle savedState) { 476 if (savedState == null) { 477 return; 478 } 479 480 final int currentScreen = savedState.getInt(RUNTIME_STATE_CURRENT_SCREEN, -1); 481 if (currentScreen > -1) { 482 mWorkspace.setCurrentScreen(currentScreen); 483 } 484 485 final int addScreen = savedState.getInt(RUNTIME_STATE_PENDING_ADD_SCREEN, -1); 486 if (addScreen > -1) { 487 mAddItemCellInfo = new CellLayout.CellInfo(); 488 final CellLayout.CellInfo addItemCellInfo = mAddItemCellInfo; 489 addItemCellInfo.valid = true; 490 addItemCellInfo.screen = addScreen; 491 addItemCellInfo.cellX = savedState.getInt(RUNTIME_STATE_PENDING_ADD_CELL_X); 492 addItemCellInfo.cellY = savedState.getInt(RUNTIME_STATE_PENDING_ADD_CELL_Y); 493 addItemCellInfo.spanX = savedState.getInt(RUNTIME_STATE_PENDING_ADD_SPAN_X); 494 addItemCellInfo.spanY = savedState.getInt(RUNTIME_STATE_PENDING_ADD_SPAN_Y); 495 addItemCellInfo.findVacantCellsFromOccupied( 496 savedState.getBooleanArray(RUNTIME_STATE_PENDING_ADD_OCCUPIED_CELLS), 497 savedState.getInt(RUNTIME_STATE_PENDING_ADD_COUNT_X), 498 savedState.getInt(RUNTIME_STATE_PENDING_ADD_COUNT_Y)); 499 mRestoring = true; 500 } 501 502 boolean renameFolder = savedState.getBoolean(RUNTIME_STATE_PENDING_FOLDER_RENAME, false); 503 if (renameFolder) { 504 long id = savedState.getLong(RUNTIME_STATE_PENDING_FOLDER_RENAME_ID); 505 mFolderInfo = mModel.getFolderById(this, mFolders, id); 506 mRestoring = true; 507 } 508 } 509 510 /** 511 * Finds all the views we need and configure them properly. 512 */ 513 private void setupViews() { 514 mDragController = new DragController(this); 515 DragController dragController = mDragController; 516 mSwipeController = new SwipeController(this); 517 SwipeController swipeController = mSwipeController; 518 519 DragLayer dragLayer = (DragLayer) findViewById(R.id.drag_layer); 520 dragLayer.setDragController(dragController); 521 dragLayer.setSwipeController(swipeController); 522 523 mAllAppsGrid = (AllAppsView)dragLayer.findViewById(R.id.all_apps_view); 524 mAllAppsGrid.setLauncher(this); 525 mAllAppsGrid.setDragController(dragController); 526 mAllAppsGrid.setWillNotDraw(false); // We don't want a hole punched in our window. 527 swipeController.setAllAppsView(mAllAppsGrid); 528 529 mWorkspace = (Workspace) dragLayer.findViewById(R.id.workspace); 530 final Workspace workspace = mWorkspace; 531 532 DeleteZone deleteZone = (DeleteZone) dragLayer.findViewById(R.id.delete_zone); 533 mDeleteZone = deleteZone; 534 535 mHandleView = (HandleView) findViewById(R.id.all_apps_button); 536 mHandleView.setLauncher(this); 537 mHandleView.setOnClickListener(this); 538 /* TODO 539 TransitionDrawable handleIcon = (TransitionDrawable) mHandleView.getDrawable(); 540 handleIocon.setCrossFadeEnabled(true); 541 */ 542 543 workspace.setOnLongClickListener(this); 544 workspace.setDragController(dragController); 545 workspace.setLauncher(this); 546 547 deleteZone.setLauncher(this); 548 deleteZone.setDragController(dragController); 549 deleteZone.setHandle(mHandleView); 550 551 dragController.setDragScoller(workspace); 552 dragController.setDragListener(deleteZone); 553 dragController.setScrollView(dragLayer); 554 555 // The order here is bottom to top. 556 dragController.addDropTarget(workspace); 557 dragController.addDropTarget(deleteZone); 558 } 559 560 /** 561 * Creates a view representing a shortcut. 562 * 563 * @param info The data structure describing the shortcut. 564 * 565 * @return A View inflated from R.layout.application. 566 */ 567 View createShortcut(ApplicationInfo info) { 568 return createShortcut(R.layout.application, 569 (ViewGroup) mWorkspace.getChildAt(mWorkspace.getCurrentScreen()), info); 570 } 571 572 /** 573 * Creates a view representing a shortcut inflated from the specified resource. 574 * 575 * @param layoutResId The id of the XML layout used to create the shortcut. 576 * @param parent The group the shortcut belongs to. 577 * @param info The data structure describing the shortcut. 578 * 579 * @return A View inflated from layoutResId. 580 */ 581 View createShortcut(int layoutResId, ViewGroup parent, ApplicationInfo info) { 582 TextView favorite = (TextView) mInflater.inflate(layoutResId, parent, false); 583 584 if (info.icon == null) { 585 info.icon = AppInfoCache.getIconDrawable(getPackageManager(), info); 586 } 587 if (!info.filtered) { 588 info.icon = Utilities.createIconThumbnail(info.icon, this); 589 info.filtered = true; 590 } 591 592 favorite.setCompoundDrawablesWithIntrinsicBounds(null, info.icon, null, null); 593 favorite.setText(info.title); 594 favorite.setTag(info); 595 favorite.setOnClickListener(this); 596 597 return favorite; 598 } 599 600 /** 601 * Add an application shortcut to the workspace. 602 * 603 * @param data The intent describing the application. 604 * @param cellInfo The position on screen where to create the shortcut. 605 */ 606 void completeAddApplication(Context context, Intent data, CellLayout.CellInfo cellInfo) { 607 cellInfo.screen = mWorkspace.getCurrentScreen(); 608 if (!findSingleSlot(cellInfo)) return; 609 610 final ApplicationInfo info = infoFromApplicationIntent(context, data); 611 if (info != null) { 612 mWorkspace.addApplicationShortcut(info, cellInfo, isWorkspaceLocked()); 613 } 614 } 615 616 private static ApplicationInfo infoFromApplicationIntent(Context context, Intent data) { 617 ComponentName component = data.getComponent(); 618 PackageManager packageManager = context.getPackageManager(); 619 ActivityInfo activityInfo = null; 620 try { 621 activityInfo = packageManager.getActivityInfo(component, 0 /* no flags */); 622 } catch (NameNotFoundException e) { 623 e(LOG_TAG, "Couldn't find ActivityInfo for selected application", e); 624 } 625 626 if (activityInfo != null) { 627 ApplicationInfo itemInfo = new ApplicationInfo(); 628 629 itemInfo.title = activityInfo.loadLabel(packageManager); 630 if (itemInfo.title == null) { 631 itemInfo.title = activityInfo.name; 632 } 633 634 itemInfo.setActivity(component, Intent.FLAG_ACTIVITY_NEW_TASK | 635 Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); 636 itemInfo.icon = activityInfo.loadIcon(packageManager); 637 itemInfo.container = ItemInfo.NO_ID; 638 639 return itemInfo; 640 } 641 642 return null; 643 } 644 645 /** 646 * Add a shortcut to the workspace. 647 * 648 * @param data The intent describing the shortcut. 649 * @param cellInfo The position on screen where to create the shortcut. 650 */ 651 private void completeAddShortcut(Intent data, CellLayout.CellInfo cellInfo) { 652 cellInfo.screen = mWorkspace.getCurrentScreen(); 653 if (!findSingleSlot(cellInfo)) return; 654 655 final ApplicationInfo info = addShortcut(this, data, cellInfo, false); 656 657 if (!mRestoring) { 658 final View view = createShortcut(info); 659 mWorkspace.addInCurrentScreen(view, cellInfo.cellX, cellInfo.cellY, 1, 1, 660 isWorkspaceLocked()); 661 } 662 } 663 664 665 /** 666 * Add a widget to the workspace. 667 * 668 * @param data The intent describing the appWidgetId. 669 * @param cellInfo The position on screen where to create the widget. 670 */ 671 private void completeAddAppWidget(Intent data, CellLayout.CellInfo cellInfo) { 672 Bundle extras = data.getExtras(); 673 int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); 674 675 d(LOG_TAG, "dumping extras content="+extras.toString()); 676 677 AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId); 678 679 // Calculate the grid spans needed to fit this widget 680 CellLayout layout = (CellLayout) mWorkspace.getChildAt(cellInfo.screen); 681 int[] spans = layout.rectToCell(appWidgetInfo.minWidth, appWidgetInfo.minHeight); 682 683 // Try finding open space on Launcher screen 684 final int[] xy = mCellCoordinates; 685 if (!findSlot(cellInfo, xy, spans[0], spans[1])) return; 686 687 // Build Launcher-specific widget info and save to database 688 LauncherAppWidgetInfo launcherInfo = new LauncherAppWidgetInfo(appWidgetId); 689 launcherInfo.spanX = spans[0]; 690 launcherInfo.spanY = spans[1]; 691 692 LauncherModel.addItemToDatabase(this, launcherInfo, 693 LauncherSettings.Favorites.CONTAINER_DESKTOP, 694 mWorkspace.getCurrentScreen(), xy[0], xy[1], false); 695 696 if (!mRestoring) { 697 mDesktopItems.add(launcherInfo); 698 699 // Perform actual inflation because we're live 700 launcherInfo.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo); 701 702 launcherInfo.hostView.setAppWidget(appWidgetId, appWidgetInfo); 703 launcherInfo.hostView.setTag(launcherInfo); 704 705 mWorkspace.addInCurrentScreen(launcherInfo.hostView, xy[0], xy[1], 706 launcherInfo.spanX, launcherInfo.spanY, isWorkspaceLocked()); 707 } 708 } 709 710 public void removeAppWidget(LauncherAppWidgetInfo launcherInfo) { 711 mDesktopItems.remove(launcherInfo); 712 launcherInfo.hostView = null; 713 } 714 715 public LauncherAppWidgetHost getAppWidgetHost() { 716 return mAppWidgetHost; 717 } 718 719 static ApplicationInfo addShortcut(Context context, Intent data, 720 CellLayout.CellInfo cellInfo, boolean notify) { 721 722 final ApplicationInfo info = infoFromShortcutIntent(context, data); 723 LauncherModel.addItemToDatabase(context, info, LauncherSettings.Favorites.CONTAINER_DESKTOP, 724 cellInfo.screen, cellInfo.cellX, cellInfo.cellY, notify); 725 726 return info; 727 } 728 729 private static ApplicationInfo infoFromShortcutIntent(Context context, Intent data) { 730 Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT); 731 String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME); 732 Bitmap bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON); 733 734 Drawable icon = null; 735 boolean filtered = false; 736 boolean customIcon = false; 737 ShortcutIconResource iconResource = null; 738 739 if (bitmap != null) { 740 icon = new FastBitmapDrawable(Utilities.createBitmapThumbnail(bitmap, context)); 741 filtered = true; 742 customIcon = true; 743 } else { 744 Parcelable extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE); 745 if (extra != null && extra instanceof ShortcutIconResource) { 746 try { 747 iconResource = (ShortcutIconResource) extra; 748 final PackageManager packageManager = context.getPackageManager(); 749 Resources resources = packageManager.getResourcesForApplication( 750 iconResource.packageName); 751 final int id = resources.getIdentifier(iconResource.resourceName, null, null); 752 icon = resources.getDrawable(id); 753 } catch (Exception e) { 754 w(LOG_TAG, "Could not load shortcut icon: " + extra); 755 } 756 } 757 } 758 759 if (icon == null) { 760 icon = context.getPackageManager().getDefaultActivityIcon(); 761 } 762 763 final ApplicationInfo info = new ApplicationInfo(); 764 info.icon = icon; 765 info.filtered = filtered; 766 info.title = name; 767 info.intent = intent; 768 info.customIcon = customIcon; 769 info.iconResource = iconResource; 770 771 return info; 772 } 773 774 @Override 775 protected void onNewIntent(Intent intent) { 776 super.onNewIntent(intent); 777 778 // Close the menu 779 if (Intent.ACTION_MAIN.equals(intent.getAction())) { 780 getWindow().closeAllPanels(); 781 782 // Set this flag so that onResume knows to close the search dialog if it's open, 783 // because this was a new intent (thus a press of 'home' or some such) rather than 784 // for example onResume being called when the user pressed the 'back' button. 785 mIsNewIntent = true; 786 787 try { 788 dismissDialog(DIALOG_CREATE_SHORTCUT); 789 // Unlock the workspace if the dialog was showing 790 } catch (Exception e) { 791 // An exception is thrown if the dialog is not visible, which is fine 792 } 793 794 try { 795 dismissDialog(DIALOG_RENAME_FOLDER); 796 // Unlock the workspace if the dialog was showing 797 } catch (Exception e) { 798 // An exception is thrown if the dialog is not visible, which is fine 799 } 800 801 if ((intent.getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 802 Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) { 803 804 if (!mWorkspace.isDefaultScreenShowing()) { 805 mWorkspace.moveToDefaultScreen(); 806 } 807 808 closeAllApps(true); 809 810 final View v = getWindow().peekDecorView(); 811 if (v != null && v.getWindowToken() != null) { 812 InputMethodManager imm = (InputMethodManager)getSystemService( 813 INPUT_METHOD_SERVICE); 814 imm.hideSoftInputFromWindow(v.getWindowToken(), 0); 815 } 816 } else { 817 closeAllApps(false); 818 } 819 } 820 } 821 822 @Override 823 protected void onRestoreInstanceState(Bundle savedInstanceState) { 824 // Do not call super here 825 mSavedInstanceState = savedInstanceState; 826 } 827 828 @Override 829 protected void onSaveInstanceState(Bundle outState) { 830 outState.putInt(RUNTIME_STATE_CURRENT_SCREEN, mWorkspace.getCurrentScreen()); 831 832 final ArrayList<Folder> folders = mWorkspace.getOpenFolders(); 833 if (folders.size() > 0) { 834 final int count = folders.size(); 835 long[] ids = new long[count]; 836 for (int i = 0; i < count; i++) { 837 final FolderInfo info = folders.get(i).getInfo(); 838 ids[i] = info.id; 839 } 840 outState.putLongArray(RUNTIME_STATE_USER_FOLDERS, ids); 841 } else { 842 super.onSaveInstanceState(outState); 843 } 844 845 final boolean isConfigurationChange = getChangingConfigurations() != 0; 846 847 // When the drawer is opened and we are saving the state because of a 848 // configuration change 849 // TODO should not do this if the drawer is currently closing. 850 if (isAllAppsVisible() && isConfigurationChange) { 851 outState.putBoolean(RUNTIME_STATE_ALL_APPS_FOLDER, true); 852 } 853 854 if (mAddItemCellInfo != null && mAddItemCellInfo.valid && mWaitingForResult) { 855 final CellLayout.CellInfo addItemCellInfo = mAddItemCellInfo; 856 final CellLayout layout = (CellLayout) mWorkspace.getChildAt(addItemCellInfo.screen); 857 858 outState.putInt(RUNTIME_STATE_PENDING_ADD_SCREEN, addItemCellInfo.screen); 859 outState.putInt(RUNTIME_STATE_PENDING_ADD_CELL_X, addItemCellInfo.cellX); 860 outState.putInt(RUNTIME_STATE_PENDING_ADD_CELL_Y, addItemCellInfo.cellY); 861 outState.putInt(RUNTIME_STATE_PENDING_ADD_SPAN_X, addItemCellInfo.spanX); 862 outState.putInt(RUNTIME_STATE_PENDING_ADD_SPAN_Y, addItemCellInfo.spanY); 863 outState.putInt(RUNTIME_STATE_PENDING_ADD_COUNT_X, layout.getCountX()); 864 outState.putInt(RUNTIME_STATE_PENDING_ADD_COUNT_Y, layout.getCountY()); 865 outState.putBooleanArray(RUNTIME_STATE_PENDING_ADD_OCCUPIED_CELLS, 866 layout.getOccupiedCells()); 867 } 868 869 if (mFolderInfo != null && mWaitingForResult) { 870 outState.putBoolean(RUNTIME_STATE_PENDING_FOLDER_RENAME, true); 871 outState.putLong(RUNTIME_STATE_PENDING_FOLDER_RENAME_ID, mFolderInfo.id); 872 } 873 } 874 875 @Override 876 public void onDestroy() { 877 super.onDestroy(); 878 879 try { 880 mAppWidgetHost.stopListening(); 881 } catch (NullPointerException ex) { 882 w(LOG_TAG, "problem while stopping AppWidgetHost during Launcher destruction", ex); 883 } 884 885 TextKeyListener.getInstance().release(); 886 887 mModel.stopLoader(); 888 889 unbindDesktopItems(); 890 AppInfoCache.unbindDrawables(); 891 } 892 893 @Override 894 public void startActivityForResult(Intent intent, int requestCode) { 895 if (requestCode >= 0) mWaitingForResult = true; 896 super.startActivityForResult(intent, requestCode); 897 } 898 899 @Override 900 public void startSearch(String initialQuery, boolean selectInitialQuery, 901 Bundle appSearchData, boolean globalSearch) { 902 903 closeAllApps(true); 904 905 // Slide the search widget to the top, if it's on the current screen, 906 // otherwise show the search dialog immediately. 907 Search searchWidget = mWorkspace.findSearchWidgetOnCurrentScreen(); 908 if (searchWidget == null) { 909 showSearchDialog(initialQuery, selectInitialQuery, appSearchData, globalSearch); 910 } else { 911 searchWidget.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch); 912 // show the currently typed text in the search widget while sliding 913 searchWidget.setQuery(getTypedText()); 914 } 915 } 916 917 /** 918 * Show the search dialog immediately, without changing the search widget. 919 * 920 * @see Activity#startSearch(String, boolean, android.os.Bundle, boolean) 921 */ 922 void showSearchDialog(String initialQuery, boolean selectInitialQuery, 923 Bundle appSearchData, boolean globalSearch) { 924 925 if (initialQuery == null) { 926 // Use any text typed in the launcher as the initial query 927 initialQuery = getTypedText(); 928 clearTypedText(); 929 } 930 if (appSearchData == null) { 931 appSearchData = new Bundle(); 932 appSearchData.putString(SearchManager.SOURCE, "launcher-search"); 933 } 934 935 final SearchManager searchManager = 936 (SearchManager) getSystemService(Context.SEARCH_SERVICE); 937 938 final Search searchWidget = mWorkspace.findSearchWidgetOnCurrentScreen(); 939 if (searchWidget != null) { 940 // This gets called when the user leaves the search dialog to go back to 941 // the Launcher. 942 searchManager.setOnCancelListener(new SearchManager.OnCancelListener() { 943 public void onCancel() { 944 searchManager.setOnCancelListener(null); 945 stopSearch(); 946 } 947 }); 948 } 949 950 searchManager.startSearch(initialQuery, selectInitialQuery, getComponentName(), 951 appSearchData, globalSearch); 952 } 953 954 /** 955 * Cancel search dialog if it is open. 956 */ 957 void stopSearch() { 958 // Close search dialog 959 SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE); 960 searchManager.stopSearch(); 961 // Restore search widget to its normal position 962 Search searchWidget = mWorkspace.findSearchWidgetOnCurrentScreen(); 963 if (searchWidget != null) { 964 searchWidget.stopSearch(false); 965 } 966 } 967 968 @Override 969 public boolean onCreateOptionsMenu(Menu menu) { 970 if (isWorkspaceLocked()) { 971 return false; 972 } 973 974 super.onCreateOptionsMenu(menu); 975 menu.add(MENU_GROUP_ADD, MENU_ADD, 0, R.string.menu_add) 976 .setIcon(android.R.drawable.ic_menu_add) 977 .setAlphabeticShortcut('A'); 978 menu.add(0, MENU_WALLPAPER_SETTINGS, 0, R.string.menu_wallpaper) 979 .setIcon(android.R.drawable.ic_menu_gallery) 980 .setAlphabeticShortcut('W'); 981 menu.add(0, MENU_SEARCH, 0, R.string.menu_search) 982 .setIcon(android.R.drawable.ic_search_category_default) 983 .setAlphabeticShortcut(SearchManager.MENU_KEY); 984 menu.add(0, MENU_NOTIFICATIONS, 0, R.string.menu_notifications) 985 .setIcon(com.android.internal.R.drawable.ic_menu_notifications) 986 .setAlphabeticShortcut('N'); 987 988 final Intent settings = new Intent(android.provider.Settings.ACTION_SETTINGS); 989 settings.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | 990 Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); 991 992 menu.add(0, MENU_SETTINGS, 0, R.string.menu_settings) 993 .setIcon(android.R.drawable.ic_menu_preferences).setAlphabeticShortcut('P') 994 .setIntent(settings); 995 996 return true; 997 } 998 999 @Override 1000 public boolean onPrepareOptionsMenu(Menu menu) { 1001 super.onPrepareOptionsMenu(menu); 1002 1003 mMenuAddInfo = mWorkspace.findAllVacantCells(null); 1004 menu.setGroupEnabled(MENU_GROUP_ADD, mMenuAddInfo != null && mMenuAddInfo.valid); 1005 1006 return true; 1007 } 1008 1009 @Override 1010 public boolean onOptionsItemSelected(MenuItem item) { 1011 switch (item.getItemId()) { 1012 case MENU_ADD: 1013 addItems(); 1014 return true; 1015 case MENU_WALLPAPER_SETTINGS: 1016 startWallpaper(); 1017 return true; 1018 case MENU_SEARCH: 1019 onSearchRequested(); 1020 return true; 1021 case MENU_NOTIFICATIONS: 1022 showNotifications(); 1023 return true; 1024 } 1025 1026 return super.onOptionsItemSelected(item); 1027 } 1028 1029 /** 1030 * Indicates that we want global search for this activity by setting the globalSearch 1031 * argument for {@link #startSearch} to true. 1032 */ 1033 1034 @Override 1035 public boolean onSearchRequested() { 1036 startSearch(null, false, null, true); 1037 return true; 1038 } 1039 1040 public boolean isWorkspaceLocked() { 1041 return mWorkspaceLoading || mWaitingForResult; 1042 } 1043 1044 private void addItems() { 1045 showAddDialog(mMenuAddInfo); 1046 } 1047 1048 void addAppWidget(Intent data) { 1049 // TODO: catch bad widget exception when sent 1050 int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); 1051 1052 String customWidget = data.getStringExtra(EXTRA_CUSTOM_WIDGET); 1053 if (SEARCH_WIDGET.equals(customWidget)) { 1054 // We don't need this any more, since this isn't a real app widget. 1055 mAppWidgetHost.deleteAppWidgetId(appWidgetId); 1056 // add the search widget 1057 addSearch(); 1058 } else { 1059 AppWidgetProviderInfo appWidget = mAppWidgetManager.getAppWidgetInfo(appWidgetId); 1060 1061 if (appWidget.configure != null) { 1062 // Launch over to configure widget, if needed 1063 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE); 1064 intent.setComponent(appWidget.configure); 1065 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); 1066 1067 startActivityForResult(intent, REQUEST_CREATE_APPWIDGET); 1068 } else { 1069 // Otherwise just add it 1070 onActivityResult(REQUEST_CREATE_APPWIDGET, Activity.RESULT_OK, data); 1071 } 1072 } 1073 } 1074 1075 void addSearch() { 1076 final Widget info = Widget.makeSearch(); 1077 final CellLayout.CellInfo cellInfo = mAddItemCellInfo; 1078 1079 final int[] xy = mCellCoordinates; 1080 final int spanX = info.spanX; 1081 final int spanY = info.spanY; 1082 1083 if (!findSlot(cellInfo, xy, spanX, spanY)) return; 1084 1085 LauncherModel.addItemToDatabase(this, info, LauncherSettings.Favorites.CONTAINER_DESKTOP, 1086 mWorkspace.getCurrentScreen(), xy[0], xy[1], false); 1087 1088 final View view = mInflater.inflate(info.layoutResource, null); 1089 view.setTag(info); 1090 Search search = (Search) view.findViewById(R.id.widget_search); 1091 search.setLauncher(this); 1092 1093 mWorkspace.addInCurrentScreen(view, xy[0], xy[1], info.spanX, spanY); 1094 } 1095 1096 void processShortcut(Intent intent, int requestCodeApplication, int requestCodeShortcut) { 1097 // Handle case where user selected "Applications" 1098 String applicationName = getResources().getString(R.string.group_applications); 1099 String shortcutName = intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME); 1100 1101 if (applicationName != null && applicationName.equals(shortcutName)) { 1102 Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); 1103 mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); 1104 1105 Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY); 1106 pickIntent.putExtra(Intent.EXTRA_INTENT, mainIntent); 1107 startActivityForResult(pickIntent, requestCodeApplication); 1108 } else { 1109 startActivityForResult(intent, requestCodeShortcut); 1110 } 1111 } 1112 1113 void addLiveFolder(Intent intent) { 1114 // Handle case where user selected "Folder" 1115 String folderName = getResources().getString(R.string.group_folder); 1116 String shortcutName = intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME); 1117 1118 if (folderName != null && folderName.equals(shortcutName)) { 1119 addFolder(); 1120 } else { 1121 startActivityForResult(intent, REQUEST_CREATE_LIVE_FOLDER); 1122 } 1123 } 1124 1125 void addFolder() { 1126 UserFolderInfo folderInfo = new UserFolderInfo(); 1127 folderInfo.title = getText(R.string.folder_name); 1128 1129 CellLayout.CellInfo cellInfo = mAddItemCellInfo; 1130 cellInfo.screen = mWorkspace.getCurrentScreen(); 1131 if (!findSingleSlot(cellInfo)) return; 1132 1133 // Update the model 1134 LauncherModel.addItemToDatabase(this, folderInfo, 1135 LauncherSettings.Favorites.CONTAINER_DESKTOP, 1136 mWorkspace.getCurrentScreen(), cellInfo.cellX, cellInfo.cellY, false); 1137 mFolders.put(folderInfo.id, folderInfo); 1138 1139 // Create the view 1140 FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this, 1141 (ViewGroup) mWorkspace.getChildAt(mWorkspace.getCurrentScreen()), folderInfo); 1142 mWorkspace.addInCurrentScreen(newFolder, 1143 cellInfo.cellX, cellInfo.cellY, 1, 1, isWorkspaceLocked()); 1144 } 1145 1146 void removeFolder(FolderInfo folder) { 1147 mFolders.remove(folder.id); 1148 } 1149 1150 private void completeAddLiveFolder(Intent data, CellLayout.CellInfo cellInfo) { 1151 cellInfo.screen = mWorkspace.getCurrentScreen(); 1152 if (!findSingleSlot(cellInfo)) return; 1153 1154 final LiveFolderInfo info = addLiveFolder(this, data, cellInfo, false); 1155 1156 if (!mRestoring) { 1157 final View view = LiveFolderIcon.fromXml(R.layout.live_folder_icon, this, 1158 (ViewGroup) mWorkspace.getChildAt(mWorkspace.getCurrentScreen()), info); 1159 mWorkspace.addInCurrentScreen(view, cellInfo.cellX, cellInfo.cellY, 1, 1, 1160 isWorkspaceLocked()); 1161 } 1162 } 1163 1164 static LiveFolderInfo addLiveFolder(Context context, Intent data, 1165 CellLayout.CellInfo cellInfo, boolean notify) { 1166 1167 Intent baseIntent = data.getParcelableExtra(LiveFolders.EXTRA_LIVE_FOLDER_BASE_INTENT); 1168 String name = data.getStringExtra(LiveFolders.EXTRA_LIVE_FOLDER_NAME); 1169 1170 Drawable icon = null; 1171 boolean filtered = false; 1172 Intent.ShortcutIconResource iconResource = null; 1173 1174 Parcelable extra = data.getParcelableExtra(LiveFolders.EXTRA_LIVE_FOLDER_ICON); 1175 if (extra != null && extra instanceof Intent.ShortcutIconResource) { 1176 try { 1177 iconResource = (Intent.ShortcutIconResource) extra; 1178 final PackageManager packageManager = context.getPackageManager(); 1179 Resources resources = packageManager.getResourcesForApplication( 1180 iconResource.packageName); 1181 final int id = resources.getIdentifier(iconResource.resourceName, null, null); 1182 icon = resources.getDrawable(id); 1183 } catch (Exception e) { 1184 w(LOG_TAG, "Could not load live folder icon: " + extra); 1185 } 1186 } 1187 1188 if (icon == null) { 1189 icon = context.getResources().getDrawable(R.drawable.ic_launcher_folder); 1190 } 1191 1192 final LiveFolderInfo info = new LiveFolderInfo(); 1193 info.icon = icon; 1194 info.filtered = filtered; 1195 info.title = name; 1196 info.iconResource = iconResource; 1197 info.uri = data.getData(); 1198 info.baseIntent = baseIntent; 1199 info.displayMode = data.getIntExtra(LiveFolders.EXTRA_LIVE_FOLDER_DISPLAY_MODE, 1200 LiveFolders.DISPLAY_MODE_GRID); 1201 1202 LauncherModel.addItemToDatabase(context, info, LauncherSettings.Favorites.CONTAINER_DESKTOP, 1203 cellInfo.screen, cellInfo.cellX, cellInfo.cellY, notify); 1204 mFolders.put(info.id, info); 1205 1206 return info; 1207 } 1208 1209 private boolean findSingleSlot(CellLayout.CellInfo cellInfo) { 1210 final int[] xy = new int[2]; 1211 if (findSlot(cellInfo, xy, 1, 1)) { 1212 cellInfo.cellX = xy[0]; 1213 cellInfo.cellY = xy[1]; 1214 return true; 1215 } 1216 return false; 1217 } 1218 1219 private boolean findSlot(CellLayout.CellInfo cellInfo, int[] xy, int spanX, int spanY) { 1220 if (!cellInfo.findCellForSpan(xy, spanX, spanY)) { 1221 boolean[] occupied = mSavedState != null ? 1222 mSavedState.getBooleanArray(RUNTIME_STATE_PENDING_ADD_OCCUPIED_CELLS) : null; 1223 cellInfo = mWorkspace.findAllVacantCells(occupied); 1224 if (!cellInfo.findCellForSpan(xy, spanX, spanY)) { 1225 Toast.makeText(this, getString(R.string.out_of_space), Toast.LENGTH_SHORT).show(); 1226 return false; 1227 } 1228 } 1229 return true; 1230 } 1231 1232 private void showNotifications() { 1233 final StatusBarManager statusBar = (StatusBarManager) getSystemService(STATUS_BAR_SERVICE); 1234 if (statusBar != null) { 1235 statusBar.expand(); 1236 } 1237 } 1238 1239 private void startWallpaper() { 1240 final Intent pickWallpaper = new Intent(Intent.ACTION_SET_WALLPAPER); 1241 Intent chooser = Intent.createChooser(pickWallpaper, 1242 getText(R.string.chooser_wallpaper)); 1243 WallpaperManager wm = (WallpaperManager) 1244 getSystemService(Context.WALLPAPER_SERVICE); 1245 WallpaperInfo wi = wm.getWallpaperInfo(); 1246 if (wi != null && wi.getSettingsActivity() != null) { 1247 LabeledIntent li = new LabeledIntent(getPackageName(), 1248 R.string.configure_wallpaper, 0); 1249 li.setClassName(wi.getPackageName(), wi.getSettingsActivity()); 1250 chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[] { li }); 1251 } 1252 startActivity(chooser); 1253 } 1254 1255 @Override 1256 public void onWindowFocusChanged(boolean hasFocus) { 1257 super.onWindowFocusChanged(hasFocus); 1258 if (!hasFocus) { 1259 mBackDown = mHomeDown = false; 1260 } 1261 } 1262 1263 @Override 1264 public boolean dispatchKeyEvent(KeyEvent event) { 1265 if (event.getAction() == KeyEvent.ACTION_DOWN) { 1266 switch (event.getKeyCode()) { 1267 case KeyEvent.KEYCODE_BACK: 1268 mBackDown = true; 1269 return true; 1270 case KeyEvent.KEYCODE_HOME: 1271 mHomeDown = true; 1272 return true; 1273 } 1274 } else if (event.getAction() == KeyEvent.ACTION_UP) { 1275 switch (event.getKeyCode()) { 1276 case KeyEvent.KEYCODE_BACK: 1277 if (!event.isCanceled()) { 1278 mWorkspace.dispatchKeyEvent(event); 1279 if (isAllAppsVisible()) { 1280 closeAllApps(true); 1281 } else { 1282 closeFolder(); 1283 } 1284 } 1285 mBackDown = false; 1286 return true; 1287 case KeyEvent.KEYCODE_HOME: 1288 mHomeDown = false; 1289 return true; 1290 } 1291 } 1292 1293 return super.dispatchKeyEvent(event); 1294 } 1295 1296 private void closeFolder() { 1297 Folder folder = mWorkspace.getOpenFolder(); 1298 if (folder != null) { 1299 closeFolder(folder); 1300 } 1301 } 1302 1303 void closeFolder(Folder folder) { 1304 folder.getInfo().opened = false; 1305 ViewGroup parent = (ViewGroup) folder.getParent(); 1306 if (parent != null) { 1307 parent.removeView(folder); 1308 // TODO: this line crashes. 1309 //mDragController.removeDropTarget((DropTarget)folder); 1310 } 1311 folder.onClose(); 1312 } 1313 1314 /** 1315 * Go through the and disconnect any of the callbacks in the drawables and the views or we 1316 * leak the previous Home screen on orientation change. 1317 */ 1318 private void unbindDesktopItems() { 1319 for (ItemInfo item: mDesktopItems) { 1320 item.unbind(); 1321 } 1322 } 1323 1324 /** 1325 * Launches the intent referred by the clicked shortcut. 1326 * 1327 * @param v The view representing the clicked shortcut. 1328 */ 1329 public void onClick(View v) { 1330 Object tag = v.getTag(); 1331 if (tag instanceof ApplicationInfo) { 1332 // Open shortcut 1333 final Intent intent = ((ApplicationInfo) tag).intent; 1334 startActivitySafely(intent); 1335 } else if (tag instanceof FolderInfo) { 1336 handleFolderClick((FolderInfo) tag); 1337 } else if (v == mHandleView) { 1338 Log.d(TAG, "onClick"); 1339 if (isAllAppsVisible()) { 1340 closeAllApps(true); 1341 } else { 1342 showAllApps(); 1343 } 1344 } 1345 } 1346 1347 void startActivitySafely(Intent intent) { 1348 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1349 try { 1350 startActivity(intent); 1351 } catch (ActivityNotFoundException e) { 1352 Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); 1353 } catch (SecurityException e) { 1354 Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); 1355 e(LOG_TAG, "Launcher does not have the permission to launch " + intent + 1356 ". Make sure to create a MAIN intent-filter for the corresponding activity " + 1357 "or use the exported attribute for this activity.", e); 1358 } 1359 } 1360 1361 private void handleFolderClick(FolderInfo folderInfo) { 1362 if (!folderInfo.opened) { 1363 // Close any open folder 1364 closeFolder(); 1365 // Open the requested folder 1366 openFolder(folderInfo); 1367 } else { 1368 // Find the open folder... 1369 Folder openFolder = mWorkspace.getFolderForTag(folderInfo); 1370 int folderScreen; 1371 if (openFolder != null) { 1372 folderScreen = mWorkspace.getScreenForView(openFolder); 1373 // .. and close it 1374 closeFolder(openFolder); 1375 if (folderScreen != mWorkspace.getCurrentScreen()) { 1376 // Close any folder open on the current screen 1377 closeFolder(); 1378 // Pull the folder onto this screen 1379 openFolder(folderInfo); 1380 } 1381 } 1382 } 1383 } 1384 1385 /** 1386 * Opens the user fodler described by the specified tag. The opening of the folder 1387 * is animated relative to the specified View. If the View is null, no animation 1388 * is played. 1389 * 1390 * @param folderInfo The FolderInfo describing the folder to open. 1391 */ 1392 private void openFolder(FolderInfo folderInfo) { 1393 Folder openFolder; 1394 1395 if (folderInfo instanceof UserFolderInfo) { 1396 openFolder = UserFolder.fromXml(this); 1397 } else if (folderInfo instanceof LiveFolderInfo) { 1398 openFolder = com.android.launcher2.LiveFolder.fromXml(this, folderInfo); 1399 } else { 1400 return; 1401 } 1402 1403 openFolder.setDragController(mDragController); 1404 openFolder.setLauncher(this); 1405 1406 openFolder.bind(folderInfo); 1407 folderInfo.opened = true; 1408 1409 mWorkspace.addInScreen(openFolder, folderInfo.screen, 0, 0, 4, 4); 1410 openFolder.onOpen(); 1411 } 1412 1413 public boolean onLongClick(View v) { 1414 if (isWorkspaceLocked()) { 1415 return false; 1416 } 1417 1418 if (!(v instanceof CellLayout)) { 1419 v = (View) v.getParent(); 1420 } 1421 1422 CellLayout.CellInfo cellInfo = (CellLayout.CellInfo) v.getTag(); 1423 1424 // This happens when long clicking an item with the dpad/trackball 1425 if (cellInfo == null) { 1426 return true; 1427 } 1428 1429 if (mWorkspace.allowLongPress()) { 1430 mSwipeController.cancelSwipe(); 1431 if (cellInfo.cell == null) { 1432 if (cellInfo.valid) { 1433 // User long pressed on empty space 1434 mWorkspace.setAllowLongPress(false); 1435 showAddDialog(cellInfo); 1436 } 1437 } else { 1438 if (!(cellInfo.cell instanceof Folder)) { 1439 // User long pressed on an item 1440 mWorkspace.startDrag(cellInfo); 1441 } 1442 } 1443 } 1444 return true; 1445 } 1446 1447 View getDrawerHandle() { 1448 return mHandleView; 1449 } 1450 1451 Workspace getWorkspace() { 1452 return mWorkspace; 1453 } 1454 1455 /* TODO 1456 GridView getApplicationsGrid() { 1457 return mAllAppsGrid; 1458 } 1459 */ 1460 1461 @Override 1462 protected Dialog onCreateDialog(int id) { 1463 switch (id) { 1464 case DIALOG_CREATE_SHORTCUT: 1465 return new CreateShortcut().createDialog(); 1466 case DIALOG_RENAME_FOLDER: 1467 return new RenameFolder().createDialog(); 1468 } 1469 1470 return super.onCreateDialog(id); 1471 } 1472 1473 @Override 1474 protected void onPrepareDialog(int id, Dialog dialog) { 1475 switch (id) { 1476 case DIALOG_CREATE_SHORTCUT: 1477 break; 1478 case DIALOG_RENAME_FOLDER: 1479 if (mFolderInfo != null) { 1480 EditText input = (EditText) dialog.findViewById(R.id.folder_name); 1481 final CharSequence text = mFolderInfo.title; 1482 input.setText(text); 1483 input.setSelection(0, text.length()); 1484 } 1485 break; 1486 } 1487 } 1488 1489 void showRenameDialog(FolderInfo info) { 1490 mFolderInfo = info; 1491 mWaitingForResult = true; 1492 showDialog(DIALOG_RENAME_FOLDER); 1493 } 1494 1495 private void showAddDialog(CellLayout.CellInfo cellInfo) { 1496 mAddItemCellInfo = cellInfo; 1497 mWaitingForResult = true; 1498 showDialog(DIALOG_CREATE_SHORTCUT); 1499 } 1500 1501 private void pickShortcut(int requestCode, int title) { 1502 Bundle bundle = new Bundle(); 1503 1504 ArrayList<String> shortcutNames = new ArrayList<String>(); 1505 shortcutNames.add(getString(R.string.group_applications)); 1506 bundle.putStringArrayList(Intent.EXTRA_SHORTCUT_NAME, shortcutNames); 1507 1508 ArrayList<ShortcutIconResource> shortcutIcons = new ArrayList<ShortcutIconResource>(); 1509 shortcutIcons.add(ShortcutIconResource.fromContext(Launcher.this, 1510 R.drawable.ic_launcher_application)); 1511 bundle.putParcelableArrayList(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, shortcutIcons); 1512 1513 Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY); 1514 pickIntent.putExtra(Intent.EXTRA_INTENT, new Intent(Intent.ACTION_CREATE_SHORTCUT)); 1515 pickIntent.putExtra(Intent.EXTRA_TITLE, getText(title)); 1516 pickIntent.putExtras(bundle); 1517 1518 startActivityForResult(pickIntent, requestCode); 1519 } 1520 1521 private class RenameFolder { 1522 private EditText mInput; 1523 1524 Dialog createDialog() { 1525 mWaitingForResult = true; 1526 final View layout = View.inflate(Launcher.this, R.layout.rename_folder, null); 1527 mInput = (EditText) layout.findViewById(R.id.folder_name); 1528 1529 AlertDialog.Builder builder = new AlertDialog.Builder(Launcher.this); 1530 builder.setIcon(0); 1531 builder.setTitle(getString(R.string.rename_folder_title)); 1532 builder.setCancelable(true); 1533 builder.setOnCancelListener(new Dialog.OnCancelListener() { 1534 public void onCancel(DialogInterface dialog) { 1535 cleanup(); 1536 } 1537 }); 1538 builder.setNegativeButton(getString(R.string.cancel_action), 1539 new Dialog.OnClickListener() { 1540 public void onClick(DialogInterface dialog, int which) { 1541 cleanup(); 1542 } 1543 } 1544 ); 1545 builder.setPositiveButton(getString(R.string.rename_action), 1546 new Dialog.OnClickListener() { 1547 public void onClick(DialogInterface dialog, int which) { 1548 changeFolderName(); 1549 } 1550 } 1551 ); 1552 builder.setView(layout); 1553 1554 final AlertDialog dialog = builder.create(); 1555 dialog.setOnShowListener(new DialogInterface.OnShowListener() { 1556 public void onShow(DialogInterface dialog) { 1557 } 1558 }); 1559 1560 return dialog; 1561 } 1562 1563 private void changeFolderName() { 1564 final String name = mInput.getText().toString(); 1565 if (!TextUtils.isEmpty(name)) { 1566 // Make sure we have the right folder info 1567 mFolderInfo = mFolders.get(mFolderInfo.id); 1568 mFolderInfo.title = name; 1569 LauncherModel.updateItemInDatabase(Launcher.this, mFolderInfo); 1570 1571 if (mWorkspaceLoading) { 1572 lockAllApps(); 1573 mModel.setWorkspaceDirty(); 1574 mModel.startLoader(Launcher.this, false); 1575 } else { 1576 final FolderIcon folderIcon = (FolderIcon) 1577 mWorkspace.getViewForTag(mFolderInfo); 1578 if (folderIcon != null) { 1579 folderIcon.setText(name); 1580 getWorkspace().requestLayout(); 1581 } else { 1582 lockAllApps(); 1583 mModel.setWorkspaceDirty(); 1584 mWorkspaceLoading = true; 1585 mModel.startLoader(Launcher.this, false); 1586 } 1587 } 1588 } 1589 cleanup(); 1590 } 1591 1592 private void cleanup() { 1593 dismissDialog(DIALOG_RENAME_FOLDER); 1594 mWaitingForResult = false; 1595 mFolderInfo = null; 1596 } 1597 } 1598 1599 boolean isAllAppsVisible() { 1600 return mAllAppsGrid.isVisible(); 1601 } 1602 1603 void showAllApps() { 1604 mSwipeController.setMode(SwipeController.MODE_ALL_APPS, true); 1605 //mWorkspace.hide(); 1606 1607 // TODO: fade these two too 1608 mDeleteZone.setVisibility(View.GONE); 1609 //mHandleView.setVisibility(View.GONE); 1610 } 1611 1612 void closeAllApps(boolean animated) { 1613 if (mAllAppsGrid.isVisible()) { 1614 mSwipeController.setMode(SwipeController.MODE_WORKSPACE, animated); 1615 mWorkspace.getChildAt(mWorkspace.getCurrentScreen()).requestFocus(); 1616 1617 // TODO: fade these two too 1618 /* 1619 mDeleteZone.setVisibility(View.VISIBLE); 1620 mHandleView.setVisibility(View.VISIBLE); 1621 */ 1622 } 1623 } 1624 1625 void lockAllApps() { 1626 // TODO 1627 } 1628 1629 void unlockAllApps() { 1630 // TODO 1631 } 1632 1633 /** 1634 * Displays the shortcut creation dialog and launches, if necessary, the 1635 * appropriate activity. 1636 */ 1637 private class CreateShortcut implements DialogInterface.OnClickListener, 1638 DialogInterface.OnCancelListener, DialogInterface.OnDismissListener, 1639 DialogInterface.OnShowListener { 1640 1641 private AddAdapter mAdapter; 1642 1643 Dialog createDialog() { 1644 mWaitingForResult = true; 1645 1646 mAdapter = new AddAdapter(Launcher.this); 1647 1648 final AlertDialog.Builder builder = new AlertDialog.Builder(Launcher.this); 1649 builder.setTitle(getString(R.string.menu_item_add_item)); 1650 builder.setAdapter(mAdapter, this); 1651 1652 builder.setInverseBackgroundForced(true); 1653 1654 AlertDialog dialog = builder.create(); 1655 dialog.setOnCancelListener(this); 1656 dialog.setOnDismissListener(this); 1657 dialog.setOnShowListener(this); 1658 1659 return dialog; 1660 } 1661 1662 public void onCancel(DialogInterface dialog) { 1663 mWaitingForResult = false; 1664 cleanup(); 1665 } 1666 1667 public void onDismiss(DialogInterface dialog) { 1668 } 1669 1670 private void cleanup() { 1671 dismissDialog(DIALOG_CREATE_SHORTCUT); 1672 } 1673 1674 /** 1675 * Handle the action clicked in the "Add to home" dialog. 1676 */ 1677 public void onClick(DialogInterface dialog, int which) { 1678 Resources res = getResources(); 1679 cleanup(); 1680 1681 switch (which) { 1682 case AddAdapter.ITEM_SHORTCUT: { 1683 // Insert extra item to handle picking application 1684 pickShortcut(REQUEST_PICK_SHORTCUT, R.string.title_select_shortcut); 1685 break; 1686 } 1687 1688 case AddAdapter.ITEM_APPWIDGET: { 1689 int appWidgetId = Launcher.this.mAppWidgetHost.allocateAppWidgetId(); 1690 1691 Intent pickIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK); 1692 pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); 1693 // add the search widget 1694 ArrayList<AppWidgetProviderInfo> customInfo = 1695 new ArrayList<AppWidgetProviderInfo>(); 1696 AppWidgetProviderInfo info = new AppWidgetProviderInfo(); 1697 info.provider = new ComponentName(getPackageName(), "XXX.YYY"); 1698 info.label = getString(R.string.group_search); 1699 info.icon = R.drawable.ic_search_widget; 1700 customInfo.add(info); 1701 pickIntent.putParcelableArrayListExtra( 1702 AppWidgetManager.EXTRA_CUSTOM_INFO, customInfo); 1703 ArrayList<Bundle> customExtras = new ArrayList<Bundle>(); 1704 Bundle b = new Bundle(); 1705 b.putString(EXTRA_CUSTOM_WIDGET, SEARCH_WIDGET); 1706 customExtras.add(b); 1707 pickIntent.putParcelableArrayListExtra( 1708 AppWidgetManager.EXTRA_CUSTOM_EXTRAS, customExtras); 1709 // start the pick activity 1710 startActivityForResult(pickIntent, REQUEST_PICK_APPWIDGET); 1711 break; 1712 } 1713 1714 case AddAdapter.ITEM_LIVE_FOLDER: { 1715 // Insert extra item to handle inserting folder 1716 Bundle bundle = new Bundle(); 1717 1718 ArrayList<String> shortcutNames = new ArrayList<String>(); 1719 shortcutNames.add(res.getString(R.string.group_folder)); 1720 bundle.putStringArrayList(Intent.EXTRA_SHORTCUT_NAME, shortcutNames); 1721 1722 ArrayList<ShortcutIconResource> shortcutIcons = 1723 new ArrayList<ShortcutIconResource>(); 1724 shortcutIcons.add(ShortcutIconResource.fromContext(Launcher.this, 1725 R.drawable.ic_launcher_folder)); 1726 bundle.putParcelableArrayList(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, shortcutIcons); 1727 1728 Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY); 1729 pickIntent.putExtra(Intent.EXTRA_INTENT, 1730 new Intent(LiveFolders.ACTION_CREATE_LIVE_FOLDER)); 1731 pickIntent.putExtra(Intent.EXTRA_TITLE, 1732 getText(R.string.title_select_live_folder)); 1733 pickIntent.putExtras(bundle); 1734 1735 startActivityForResult(pickIntent, REQUEST_PICK_LIVE_FOLDER); 1736 break; 1737 } 1738 1739 case AddAdapter.ITEM_WALLPAPER: { 1740 startWallpaper(); 1741 break; 1742 } 1743 } 1744 } 1745 1746 public void onShow(DialogInterface dialog) { 1747 } 1748 } 1749 1750 /** 1751 * Implementation of the method from LauncherModel.Callbacks. 1752 */ 1753 public int getCurrentWorkspaceScreen() { 1754 return mWorkspace.getCurrentScreen(); 1755 } 1756 1757 /** 1758 * Refreshes the shortcuts shown on the workspace. 1759 * 1760 * Implementation of the method from LauncherModel.Callbacks. 1761 */ 1762 public void startBinding() { 1763 final Workspace workspace = mWorkspace; 1764 int count = workspace.getChildCount(); 1765 for (int i = 0; i < count; i++) { 1766 ((ViewGroup) workspace.getChildAt(i)).removeAllViewsInLayout(); 1767 } 1768 1769 if (DEBUG_USER_INTERFACE) { 1770 android.widget.Button finishButton = new android.widget.Button(this); 1771 finishButton.setText("Finish"); 1772 workspace.addInScreen(finishButton, 1, 0, 0, 1, 1); 1773 1774 finishButton.setOnClickListener(new android.widget.Button.OnClickListener() { 1775 public void onClick(View v) { 1776 finish(); 1777 } 1778 }); 1779 } 1780 } 1781 1782 /** 1783 * Bind the items start-end from the list. 1784 * 1785 * Implementation of the method from LauncherModel.Callbacks. 1786 */ 1787 public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end) { 1788 1789 final Workspace workspace = mWorkspace; 1790 1791 for (int i=start; i<end; i++) { 1792 final ItemInfo item = shortcuts.get(i); 1793 mDesktopItems.add(item); 1794 switch (item.itemType) { 1795 case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: 1796 case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: 1797 final View shortcut = createShortcut((ApplicationInfo) item); 1798 workspace.addInScreen(shortcut, item.screen, item.cellX, item.cellY, 1, 1, 1799 false); 1800 break; 1801 case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER: 1802 final FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this, 1803 (ViewGroup) workspace.getChildAt(workspace.getCurrentScreen()), 1804 (UserFolderInfo) item); 1805 workspace.addInScreen(newFolder, item.screen, item.cellX, item.cellY, 1, 1, 1806 false); 1807 break; 1808 case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER: 1809 final FolderIcon newLiveFolder = LiveFolderIcon.fromXml( 1810 R.layout.live_folder_icon, this, 1811 (ViewGroup) workspace.getChildAt(workspace.getCurrentScreen()), 1812 (LiveFolderInfo) item); 1813 workspace.addInScreen(newLiveFolder, item.screen, item.cellX, item.cellY, 1, 1, 1814 false); 1815 break; 1816 case LauncherSettings.Favorites.ITEM_TYPE_WIDGET_SEARCH: 1817 final int screen = workspace.getCurrentScreen(); 1818 final View view = mInflater.inflate(R.layout.widget_search, 1819 (ViewGroup) workspace.getChildAt(screen), false); 1820 1821 Search search = (Search) view.findViewById(R.id.widget_search); 1822 search.setLauncher(this); 1823 1824 final Widget widget = (Widget) item; 1825 view.setTag(widget); 1826 1827 workspace.addWidget(view, widget, false); 1828 break; 1829 } 1830 } 1831 1832 workspace.requestLayout(); 1833 } 1834 1835 /** 1836 * Implementation of the method from LauncherModel.Callbacks. 1837 */ 1838 void bindFolders(HashMap<Long, FolderInfo> folders) { 1839 mFolders.putAll(folders); 1840 } 1841 1842 /** 1843 * Add the views for a widget to the workspace. 1844 * 1845 * Implementation of the method from LauncherModel.Callbacks. 1846 */ 1847 public void bindAppWidget(LauncherAppWidgetInfo item) { 1848 final Workspace workspace = mWorkspace; 1849 1850 final int appWidgetId = item.appWidgetId; 1851 final AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId); 1852 item.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo); 1853 1854 if (true) { 1855 Log.d(LOG_TAG, String.format("about to setAppWidget for id=%d, info=%s", 1856 appWidgetId, appWidgetInfo)); 1857 } 1858 1859 item.hostView.setAppWidget(appWidgetId, appWidgetInfo); 1860 item.hostView.setTag(item); 1861 1862 workspace.addInScreen(item.hostView, item.screen, item.cellX, 1863 item.cellY, item.spanX, item.spanY, false); 1864 1865 workspace.requestLayout(); 1866 1867 mDesktopItems.add(item); 1868 } 1869 1870 /** 1871 * Callback saying that there aren't any more items to bind. 1872 * 1873 * Implementation of the method from LauncherModel.Callbacks. 1874 */ 1875 public void finishBindingItems() { 1876 if (mSavedState != null) { 1877 if (!mWorkspace.hasFocus()) { 1878 mWorkspace.getChildAt(mWorkspace.getCurrentScreen()).requestFocus(); 1879 } 1880 1881 final long[] userFolders = mSavedState.getLongArray(RUNTIME_STATE_USER_FOLDERS); 1882 if (userFolders != null) { 1883 for (long folderId : userFolders) { 1884 final FolderInfo info = mFolders.get(folderId); 1885 if (info != null) { 1886 openFolder(info); 1887 } 1888 } 1889 final Folder openFolder = mWorkspace.getOpenFolder(); 1890 if (openFolder != null) { 1891 openFolder.requestFocus(); 1892 } 1893 } 1894 1895 final boolean allApps = mSavedState.getBoolean(RUNTIME_STATE_ALL_APPS_FOLDER, false); 1896 if (allApps) { 1897 showAllApps(); 1898 } 1899 1900 mSavedState = null; 1901 } 1902 1903 if (mSavedInstanceState != null) { 1904 super.onRestoreInstanceState(mSavedInstanceState); 1905 mSavedInstanceState = null; 1906 } 1907 1908 /* TODO 1909 if (mAllAppsVisible && !mDrawer.hasFocus()) { 1910 mDrawer.requestFocus(); 1911 } 1912 */ 1913 1914 Log.d(TAG, "finishBindingItems done"); 1915 mWorkspaceLoading = false; 1916 } 1917 1918 /** 1919 * Add the icons for all apps. 1920 * 1921 * Implementation of the method from LauncherModel.Callbacks. 1922 */ 1923 public void bindAllApplications(ArrayList<ApplicationInfo> apps) { 1924 Log.d(LOG_TAG, "got info for " + apps.size() + " apps"); 1925 mAllAppsList = apps; 1926 mAllAppsGrid.setApps(mAllAppsList); 1927 } 1928 1929 /** 1930 * A package was installed. 1931 * 1932 * Implementation of the method from LauncherModel.Callbacks. 1933 */ 1934 public void bindPackageAdded(ArrayList<ApplicationInfo> apps) { 1935 removeDialog(DIALOG_CREATE_SHORTCUT); 1936 } 1937 1938 /** 1939 * A package was updated. 1940 * 1941 * Implementation of the method from LauncherModel.Callbacks. 1942 */ 1943 public void bindPackageUpdated(String packageName, ArrayList<ApplicationInfo> apps) { 1944 removeDialog(DIALOG_CREATE_SHORTCUT); 1945 mWorkspace.updateShortcutsForPackage(packageName); 1946 } 1947 1948 /** 1949 * A package was uninstalled. 1950 * 1951 * Implementation of the method from LauncherModel.Callbacks. 1952 */ 1953 public void bindPackageRemoved(String packageName, ArrayList<ApplicationInfo> apps) { 1954 removeDialog(DIALOG_CREATE_SHORTCUT); 1955 mWorkspace.removeShortcutsForPackage(packageName); 1956 } 1957 1958} 1959