Workspace.java revision 0142d49e1378a7155bcca1fb59965d9e73016dbc
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 com.android.launcher.R; 20 21import android.animation.Animatable; 22import android.animation.PropertyAnimator; 23import android.animation.PropertyValuesHolder; 24import android.animation.Sequencer; 25import android.animation.Animatable.AnimatableListener; 26import android.app.WallpaperManager; 27import android.appwidget.AppWidgetManager; 28import android.appwidget.AppWidgetProviderInfo; 29import android.content.ComponentName; 30import android.content.Context; 31import android.content.Intent; 32import android.content.pm.PackageManager; 33import android.content.pm.ProviderInfo; 34import android.content.res.Resources; 35import android.content.res.TypedArray; 36import android.graphics.Canvas; 37import android.graphics.Matrix; 38import android.graphics.Rect; 39import android.graphics.drawable.Drawable; 40import android.net.Uri; 41import android.os.IBinder; 42import android.os.Parcelable; 43import android.util.AttributeSet; 44import android.util.Log; 45import android.view.MotionEvent; 46import android.view.View; 47import android.view.ViewGroup; 48import android.widget.TextView; 49import android.widget.Toast; 50 51import java.util.ArrayList; 52import java.util.HashSet; 53 54/** 55 * The workspace is a wide area with a wallpaper and a finite number of pages. 56 * Each page contains a number of icons, folders or widgets the user can 57 * interact with. A workspace is meant to be used with a fixed width only. 58 */ 59public class Workspace extends SmoothPagedView 60 implements DropTarget, DragSource, DragScroller, View.OnTouchListener { 61 @SuppressWarnings({"UnusedDeclaration"}) 62 private static final String TAG = "Launcher.Workspace"; 63 64 // This is how much the workspace shrinks when we enter all apps or 65 // customization mode 66 private static final float SHRINK_FACTOR = 0.16f; 67 private enum ShrinkPosition { SHRINK_TO_TOP, SHRINK_TO_MIDDLE, SHRINK_TO_BOTTOM }; 68 69 private final WallpaperManager mWallpaperManager; 70 71 private int mDefaultPage; 72 73 private boolean mWaitingToShrinkToBottom = false; 74 75 /** 76 * CellInfo for the cell that is currently being dragged 77 */ 78 private CellLayout.CellInfo mDragInfo; 79 80 /** 81 * Target drop area calculated during last acceptDrop call. 82 */ 83 private int[] mTargetCell = null; 84 85 /** 86 * The CellLayout that is currently being dragged over 87 */ 88 private CellLayout mDragTargetLayout = null; 89 90 private Launcher mLauncher; 91 private IconCache mIconCache; 92 private DragController mDragController; 93 94 95 private int[] mTempCell = new int[2]; 96 private int[] mTempEstimate = new int[2]; 97 private float[] mTempDragCoordinates = new float[2]; 98 private float[] mTempDragBottomRightCoordinates = new float[2]; 99 100 private static final int DEFAULT_CELL_COUNT_X = 4; 101 private static final int DEFAULT_CELL_COUNT_Y = 4; 102 103 private Drawable mPreviousIndicator; 104 private Drawable mNextIndicator; 105 106 // State variable that indicated whether the pages are small (ie when you're 107 // in all apps or customize mode) 108 private boolean mIsSmall; 109 private AnimatableListener mUnshrinkAnimationListener; 110 111 112 /** 113 * Used to inflate the Workspace from XML. 114 * 115 * @param context The application's context. 116 * @param attrs The attributes set containing the Workspace's customization values. 117 */ 118 public Workspace(Context context, AttributeSet attrs) { 119 this(context, attrs, 0); 120 } 121 122 /** 123 * Used to inflate the Workspace from XML. 124 * 125 * @param context The application's context. 126 * @param attrs The attributes set containing the Workspace's customization values. 127 * @param defStyle Unused. 128 */ 129 public Workspace(Context context, AttributeSet attrs, int defStyle) { 130 super(context, attrs, defStyle); 131 mContentIsRefreshable = false; 132 mFadeInAdjacentScreens = false; 133 134 mWallpaperManager = WallpaperManager.getInstance(context); 135 136 TypedArray a = context.obtainStyledAttributes(attrs, 137 R.styleable.Workspace, defStyle, 0); 138 int cellCountX = a.getInt(R.styleable.Workspace_cellCountX, DEFAULT_CELL_COUNT_X); 139 int cellCountY = a.getInt(R.styleable.Workspace_cellCountY, DEFAULT_CELL_COUNT_Y); 140 mDefaultPage = a.getInt(R.styleable.Workspace_defaultScreen, 1); 141 a.recycle(); 142 143 LauncherModel.updateWorkspaceLayoutCells(cellCountX, cellCountY); 144 setHapticFeedbackEnabled(false); 145 146 initWorkspace(); 147 } 148 149 /** 150 * Initializes various states for this workspace. 151 */ 152 protected void initWorkspace() { 153 Context context = getContext(); 154 mCurrentPage = mDefaultPage; 155 Launcher.setScreen(mCurrentPage); 156 LauncherApplication app = (LauncherApplication)context.getApplicationContext(); 157 mIconCache = app.getIconCache(); 158 159 mUnshrinkAnimationListener = new AnimatableListener() { 160 public void onAnimationStart(Animatable animation) {} 161 public void onAnimationEnd(Animatable animation) { 162 mIsSmall = false; 163 } 164 public void onAnimationCancel(Animatable animation) {} 165 public void onAnimationRepeat(Animatable animation) {} 166 }; 167 168 mSnapVelocity = 600; 169 } 170 171 @Override 172 public void addView(View child, int index, LayoutParams params) { 173 if (!(child instanceof CellLayout)) { 174 throw new IllegalArgumentException("A Workspace can only have CellLayout children."); 175 } 176 super.addView(child, index, params); 177 } 178 179 @Override 180 public void addView(View child) { 181 if (!(child instanceof CellLayout)) { 182 throw new IllegalArgumentException("A Workspace can only have CellLayout children."); 183 } 184 super.addView(child); 185 } 186 187 @Override 188 public void addView(View child, int index) { 189 if (!(child instanceof CellLayout)) { 190 throw new IllegalArgumentException("A Workspace can only have CellLayout children."); 191 } 192 super.addView(child, index); 193 } 194 195 @Override 196 public void addView(View child, int width, int height) { 197 if (!(child instanceof CellLayout)) { 198 throw new IllegalArgumentException("A Workspace can only have CellLayout children."); 199 } 200 super.addView(child, width, height); 201 } 202 203 @Override 204 public void addView(View child, LayoutParams params) { 205 if (!(child instanceof CellLayout)) { 206 throw new IllegalArgumentException("A Workspace can only have CellLayout children."); 207 } 208 super.addView(child, params); 209 } 210 211 /** 212 * @return The open folder on the current screen, or null if there is none 213 */ 214 Folder getOpenFolder() { 215 CellLayout currentPage = (CellLayout) getChildAt(mCurrentPage); 216 int count = currentPage.getChildCount(); 217 for (int i = 0; i < count; i++) { 218 View child = currentPage.getChildAt(i); 219 if (child instanceof Folder) { 220 Folder folder = (Folder) child; 221 if (folder.getInfo().opened) 222 return folder; 223 } 224 } 225 return null; 226 } 227 228 ArrayList<Folder> getOpenFolders() { 229 final int screenCount = getChildCount(); 230 ArrayList<Folder> folders = new ArrayList<Folder>(screenCount); 231 232 for (int screen = 0; screen < screenCount; screen++) { 233 CellLayout currentPage = (CellLayout) getChildAt(screen); 234 int count = currentPage.getChildCount(); 235 for (int i = 0; i < count; i++) { 236 View child = currentPage.getChildAt(i); 237 if (child instanceof Folder) { 238 Folder folder = (Folder) child; 239 if (folder.getInfo().opened) 240 folders.add(folder); 241 break; 242 } 243 } 244 } 245 246 return folders; 247 } 248 249 boolean isDefaultPageShowing() { 250 return mCurrentPage == mDefaultPage; 251 } 252 253 /** 254 * Sets the current screen. 255 * 256 * @param currentPage 257 */ 258 @Override 259 void setCurrentPage(int currentPage) { 260 super.setCurrentPage(currentPage); 261 updateWallpaperOffset(mScrollX); 262 } 263 264 /** 265 * Adds the specified child in the current screen. The position and dimension of 266 * the child are defined by x, y, spanX and spanY. 267 * 268 * @param child The child to add in one of the workspace's screens. 269 * @param x The X position of the child in the screen's grid. 270 * @param y The Y position of the child in the screen's grid. 271 * @param spanX The number of cells spanned horizontally by the child. 272 * @param spanY The number of cells spanned vertically by the child. 273 */ 274 void addInCurrentScreen(View child, int x, int y, int spanX, int spanY) { 275 addInScreen(child, mCurrentPage, x, y, spanX, spanY, false); 276 } 277 278 /** 279 * Adds the specified child in the current screen. The position and dimension of 280 * the child are defined by x, y, spanX and spanY. 281 * 282 * @param child The child to add in one of the workspace's screens. 283 * @param x The X position of the child in the screen's grid. 284 * @param y The Y position of the child in the screen's grid. 285 * @param spanX The number of cells spanned horizontally by the child. 286 * @param spanY The number of cells spanned vertically by the child. 287 * @param insert When true, the child is inserted at the beginning of the children list. 288 */ 289 void addInCurrentScreen(View child, int x, int y, int spanX, int spanY, boolean insert) { 290 addInScreen(child, mCurrentPage, x, y, spanX, spanY, insert); 291 } 292 293 /** 294 * Adds the specified child in the specified screen. The position and dimension of 295 * the child are defined by x, y, spanX and spanY. 296 * 297 * @param child The child to add in one of the workspace's screens. 298 * @param screen The screen in which to add the child. 299 * @param x The X position of the child in the screen's grid. 300 * @param y The Y position of the child in the screen's grid. 301 * @param spanX The number of cells spanned horizontally by the child. 302 * @param spanY The number of cells spanned vertically by the child. 303 */ 304 void addInScreen(View child, int screen, int x, int y, int spanX, int spanY) { 305 addInScreen(child, screen, x, y, spanX, spanY, false); 306 } 307 308 void addInFullScreen(View child, int screen) { 309 addInScreen(child, screen, 0, 0, -1, -1); 310 } 311 312 /** 313 * Adds the specified child in the specified screen. The position and dimension of 314 * the child are defined by x, y, spanX and spanY. 315 * 316 * @param child The child to add in one of the workspace's screens. 317 * @param screen The screen in which to add the child. 318 * @param x The X position of the child in the screen's grid. 319 * @param y The Y position of the child in the screen's grid. 320 * @param spanX The number of cells spanned horizontally by the child. 321 * @param spanY The number of cells spanned vertically by the child. 322 * @param insert When true, the child is inserted at the beginning of the children list. 323 */ 324 void addInScreen(View child, int screen, int x, int y, int spanX, int spanY, boolean insert) { 325 if (screen < 0 || screen >= getChildCount()) { 326 Log.e(TAG, "The screen must be >= 0 and < " + getChildCount() 327 + " (was " + screen + "); skipping child"); 328 return; 329 } 330 331 final CellLayout group = (CellLayout) getChildAt(screen); 332 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); 333 if (lp == null) { 334 lp = new CellLayout.LayoutParams(x, y, spanX, spanY); 335 } else { 336 lp.cellX = x; 337 lp.cellY = y; 338 lp.cellHSpan = spanX; 339 lp.cellVSpan = spanY; 340 } 341 342 // Get the canonical child id to uniquely represent this view in this screen 343 int childId = LauncherModel.getCellLayoutChildId(child.getId(), screen, x, y, spanX, spanY); 344 if (!group.addViewToCellLayout(child, insert ? 0 : -1, childId, lp)) { 345 // TODO: This branch occurs when the workspace is adding views 346 // outside of the defined grid 347 // maybe we should be deleting these items from the LauncherModel? 348 Log.w(TAG, "Failed to add to item at (" + lp.cellX + "," + lp.cellY + ") to CellLayout"); 349 } 350 351 if (!(child instanceof Folder)) { 352 child.setHapticFeedbackEnabled(false); 353 child.setOnLongClickListener(mLongClickListener); 354 } 355 if (child instanceof DropTarget) { 356 mDragController.addDropTarget((DropTarget) child); 357 } 358 } 359 360 CellLayout.CellInfo updateOccupiedCellsForCurrentScreen(boolean[] occupied) { 361 CellLayout group = (CellLayout) getChildAt(mCurrentPage); 362 if (group != null) { 363 return group.updateOccupiedCells(occupied, null); 364 } 365 return null; 366 } 367 368 public boolean onTouch(View v, MotionEvent event) { 369 // this is an intercepted event being forwarded from a cell layout 370 if (mIsSmall) { 371 unshrink((CellLayout)v); 372 mLauncher.onWorkspaceUnshrink(); 373 return true; 374 } 375 return false; 376 } 377 378 protected void pageBeginMoving() { 379 if (mNextPage != INVALID_PAGE) { 380 // we're snapping to a particular screen 381 enableChildrenCache(mCurrentPage, mNextPage); 382 } else { 383 // this is when user is actively dragging a particular screen, they might 384 // swipe it either left or right (but we won't advance by more than one screen) 385 enableChildrenCache(mCurrentPage - 1, mCurrentPage + 1); 386 } 387 } 388 389 protected void pageEndMoving() { 390 clearChildrenCache(); 391 } 392 393 @Override 394 protected void notifyPageSwitchListener() { 395 super.notifyPageSwitchListener(); 396 397 if (mPreviousIndicator != null) { 398 // if we know the next page, we show the indication for it right away; it looks 399 // weird if the indicators are lagging 400 int page = mNextPage; 401 if (page == INVALID_PAGE) { 402 page = mCurrentPage; 403 } 404 mPreviousIndicator.setLevel(page); 405 mNextIndicator.setLevel(page); 406 } 407 Launcher.setScreen(mCurrentPage); 408 }; 409 410 private void updateWallpaperOffset() { 411 updateWallpaperOffset(getChildAt(getChildCount() - 1).getRight() - (mRight - mLeft)); 412 } 413 414 private void updateWallpaperOffset(int scrollRange) { 415 final boolean isStaticWallpaper = (mWallpaperManager != null) && 416 (mWallpaperManager.getWallpaperInfo() == null); 417 if (LauncherApplication.isScreenXLarge() && !isStaticWallpaper) { 418 IBinder token = getWindowToken(); 419 if (token != null) { 420 mWallpaperManager.setWallpaperOffsetSteps(1.0f / (getChildCount() - 1), 0 ); 421 mWallpaperManager.setWallpaperOffsets(getWindowToken(), 422 Math.max(0.f, Math.min(mScrollX/(float)scrollRange, 1.f)), 0); 423 } 424 } 425 } 426 427 protected void onAttachedToWindow() { 428 super.onAttachedToWindow(); 429 computeScroll(); 430 mDragController.setWindowToken(getWindowToken()); 431 } 432 433 @Override 434 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 435 super.onLayout(changed, left, top, right, bottom); 436 437 // if shrinkToBottom() is called on initialization, it has to be deferred 438 // until after the first call to onLayout so that it has the correct width 439 if (mWaitingToShrinkToBottom) { 440 shrinkToBottom(false); 441 mWaitingToShrinkToBottom = false; 442 } 443 444 if (LauncherApplication.isInPlaceRotationEnabled()) { 445 // When the device is rotated, the scroll position of the current screen 446 // needs to be refreshed 447 setCurrentPage(getCurrentPage()); 448 } 449 } 450 451 @Override 452 protected void dispatchDraw(Canvas canvas) { 453 if (mIsSmall) { 454 // Draw all the workspaces if we're small 455 final int pageCount = getChildCount(); 456 final long drawingTime = getDrawingTime(); 457 for (int i = 0; i < pageCount; i++) { 458 final View page = (View) getChildAt(i); 459 460 if (page.getAlpha() != 1.0f) { 461 page.setAlpha(1.0f); 462 } 463 drawChild(canvas, page, drawingTime); 464 } 465 } else { 466 super.dispatchDraw(canvas); 467 } 468 } 469 470 @Override 471 protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { 472 if (!mLauncher.isAllAppsVisible()) { 473 final Folder openFolder = getOpenFolder(); 474 if (openFolder != null) { 475 return openFolder.requestFocus(direction, previouslyFocusedRect); 476 } else { 477 return super.onRequestFocusInDescendants(direction, previouslyFocusedRect); 478 } 479 } 480 return false; 481 } 482 483 @Override 484 public void addFocusables(ArrayList<View> views, int direction, int focusableMode) { 485 if (!mLauncher.isAllAppsVisible()) { 486 final Folder openFolder = getOpenFolder(); 487 if (openFolder != null) { 488 openFolder.addFocusables(views, direction); 489 } else { 490 super.addFocusables(views, direction, focusableMode); 491 } 492 } 493 } 494 495 @Override 496 public boolean dispatchTouchEvent(MotionEvent ev) { 497 if (ev.getAction() == MotionEvent.ACTION_DOWN) { 498 // (In XLarge mode, the workspace is shrunken below all apps, and responds to taps 499 // ie when you click on a mini-screen, it zooms back to that screen) 500 if (!LauncherApplication.isScreenXLarge() && mLauncher.isAllAppsVisible()) { 501 return false; 502 } 503 } 504 return super.dispatchTouchEvent(ev); 505 } 506 507 void enableChildrenCache(int fromPage, int toPage) { 508 if (fromPage > toPage) { 509 final int temp = fromPage; 510 fromPage = toPage; 511 toPage = temp; 512 } 513 514 final int screenCount = getChildCount(); 515 516 fromPage = Math.max(fromPage, 0); 517 toPage = Math.min(toPage, screenCount - 1); 518 519 for (int i = fromPage; i <= toPage; i++) { 520 final CellLayout layout = (CellLayout) getChildAt(i); 521 layout.setChildrenDrawnWithCacheEnabled(true); 522 layout.setChildrenDrawingCacheEnabled(true); 523 } 524 } 525 526 void clearChildrenCache() { 527 final int screenCount = getChildCount(); 528 for (int i = 0; i < screenCount; i++) { 529 final CellLayout layout = (CellLayout) getChildAt(i); 530 layout.setChildrenDrawnWithCacheEnabled(false); 531 } 532 } 533 534 @Override 535 public boolean onTouchEvent(MotionEvent ev) { 536 if (mLauncher.isAllAppsVisible()) { 537 // Cancel any scrolling that is in progress. 538 if (!mScroller.isFinished()) { 539 mScroller.abortAnimation(); 540 } 541 snapToPage(mCurrentPage); 542 return false; // We don't want the events. Let them fall through to the all apps view. 543 } 544 545 return super.onTouchEvent(ev); 546 } 547 548 public boolean isSmall() { 549 return mIsSmall; 550 } 551 552 void shrinkToTop(boolean animated) { 553 shrink(ShrinkPosition.SHRINK_TO_TOP, animated); 554 } 555 556 void shrinkToMiddle() { 557 shrink(ShrinkPosition.SHRINK_TO_MIDDLE, true); 558 } 559 560 void shrinkToBottom() { 561 shrinkToBottom(true); 562 } 563 564 void shrinkToBottom(boolean animated) { 565 if (mFirstLayout) { 566 // (mFirstLayout == "first layout has not happened yet") 567 // if we get a call to shrink() as part of our initialization (for example, if 568 // Launcher is started in All Apps mode) then we need to wait for a layout call 569 // to get our width so we can layout the mini-screen views correctly 570 mWaitingToShrinkToBottom = true; 571 } else { 572 shrink(ShrinkPosition.SHRINK_TO_BOTTOM, animated); 573 } 574 } 575 576 // we use this to shrink the workspace for the all apps view and the customize view 577 private void shrink(ShrinkPosition shrinkPosition, boolean animated) { 578 mIsSmall = true; 579 final Resources res = getResources(); 580 final int screenWidth = getWidth(); 581 final int screenHeight = getHeight(); 582 583 // Making the assumption that all pages have the same width as the 0th 584 final int pageWidth = getChildAt(0).getMeasuredWidth(); 585 final int pageHeight = getChildAt(0).getMeasuredHeight(); 586 587 final int scaledPageWidth = (int) (SHRINK_FACTOR * pageWidth); 588 final int scaledPageHeight = (int) (SHRINK_FACTOR * pageHeight); 589 final float scaledSpacing = res.getDimension(R.dimen.smallScreenSpacing); 590 591 final int screenCount = getChildCount(); 592 float totalWidth = screenCount * scaledPageWidth + (screenCount - 1) * scaledSpacing; 593 594 float newY = getResources().getDimension(R.dimen.smallScreenVerticalMargin); 595 if (shrinkPosition == ShrinkPosition.SHRINK_TO_BOTTOM) { 596 newY = screenHeight - newY - scaledPageHeight; 597 } else if (shrinkPosition == ShrinkPosition.SHRINK_TO_MIDDLE) { 598 newY = screenHeight / 2 - scaledPageHeight / 2; 599 } 600 601 // We animate all the screens to the centered position in workspace 602 // At the same time, the screens become greyed/dimmed 603 604 // newX is initialized to the left-most position of the centered screens 605 float newX = mScroller.getFinalX() + screenWidth / 2 - totalWidth / 2; 606 for (int i = 0; i < screenCount; i++) { 607 CellLayout cl = (CellLayout) getChildAt(i); 608 cl.setPivotX(0.0f); 609 cl.setPivotY(0.0f); 610 if (animated) { 611 final int duration = res.getInteger(R.integer.config_workspaceShrinkTime); 612 new PropertyAnimator(duration, cl, 613 new PropertyValuesHolder("x", newX), 614 new PropertyValuesHolder("y", newY), 615 new PropertyValuesHolder("scaleX", SHRINK_FACTOR), 616 new PropertyValuesHolder("scaleY", SHRINK_FACTOR), 617 new PropertyValuesHolder("dimmedBitmapAlpha", 1.0f)).start(); 618 } else { 619 cl.setX((int)newX); 620 cl.setY((int)newY); 621 cl.setScaleX(SHRINK_FACTOR); 622 cl.setScaleY(SHRINK_FACTOR); 623 cl.setDimmedBitmapAlpha(1.0f); 624 } 625 // increment newX for the next screen 626 newX += scaledPageWidth + scaledSpacing; 627 cl.setOnInterceptTouchListener(this); 628 } 629 setChildrenDrawnWithCacheEnabled(true); 630 } 631 632 // We call this when we trigger an unshrink by clicking on the CellLayout cl 633 private void unshrink(CellLayout clThatWasClicked) { 634 int newCurrentPage = mCurrentPage; 635 final int screenCount = getChildCount(); 636 for (int i = 0; i < screenCount; i++) { 637 if (getChildAt(i) == clThatWasClicked) { 638 newCurrentPage = i; 639 } 640 } 641 unshrink(newCurrentPage); 642 } 643 644 private void unshrink(int newCurrentPage) { 645 if (mIsSmall) { 646 int delta = (newCurrentPage - mCurrentPage)*getWidth(); 647 648 final int screenCount = getChildCount(); 649 for (int i = 0; i < screenCount; i++) { 650 CellLayout cl = (CellLayout) getChildAt(i); 651 cl.setX(cl.getX() + delta); 652 } 653 snapToPage(newCurrentPage); 654 unshrink(); 655 656 setCurrentPage(newCurrentPage); 657 } 658 } 659 660 void unshrink() { 661 unshrink(true); 662 } 663 664 void unshrink(boolean animated) { 665 if (mIsSmall) { 666 Sequencer s = new Sequencer(); 667 final int screenCount = getChildCount(); 668 669 final int duration = getResources().getInteger(R.integer.config_workspaceUnshrinkTime); 670 for (int i = 0; i < screenCount; i++) { 671 final CellLayout cl = (CellLayout)getChildAt(i); 672 cl.setPivotX(0.0f); 673 cl.setPivotY(0.0f); 674 if (animated) { 675 s.playTogether( 676 new PropertyAnimator<Float>(duration, cl, "translationX", 0.0f), 677 new PropertyAnimator<Float>(duration, cl, "translationY", 0.0f), 678 new PropertyAnimator<Float>(duration, cl, "scaleX", 1.0f), 679 new PropertyAnimator<Float>(duration, cl, "scaleY", 1.0f), 680 new PropertyAnimator<Float>(duration, cl, "dimmedBitmapAlpha", 0.0f)); 681 } else { 682 cl.setTranslationX(0.0f); 683 cl.setTranslationY(0.0f); 684 cl.setScaleX(1.0f); 685 cl.setScaleY(1.0f); 686 cl.setDimmedBitmapAlpha(0.0f); 687 } 688 } 689 s.addListener(mUnshrinkAnimationListener); 690 s.start(); 691 } 692 } 693 694 void startDrag(CellLayout.CellInfo cellInfo) { 695 View child = cellInfo.cell; 696 697 // Make sure the drag was started by a long press as opposed to a long click. 698 if (!child.isInTouchMode()) { 699 return; 700 } 701 702 mDragInfo = cellInfo; 703 mDragInfo.screen = mCurrentPage; 704 705 CellLayout current = ((CellLayout) getChildAt(mCurrentPage)); 706 707 current.onDragChild(child); 708 mDragController.startDrag(child, this, child.getTag(), DragController.DRAG_ACTION_MOVE); 709 invalidate(); 710 } 711 712 void addApplicationShortcut(ShortcutInfo info, CellLayout.CellInfo cellInfo) { 713 addApplicationShortcut(info, cellInfo, false); 714 } 715 716 void addApplicationShortcut(ShortcutInfo info, CellLayout.CellInfo cellInfo, 717 boolean insertAtFirst) { 718 final CellLayout layout = (CellLayout) getChildAt(cellInfo.screen); 719 final int[] result = new int[2]; 720 721 layout.cellToPoint(cellInfo.cellX, cellInfo.cellY, result); 722 onDropExternal(result[0], result[1], info, layout, insertAtFirst); 723 } 724 725 public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, 726 DragView dragView, Object dragInfo) { 727 CellLayout cellLayout = getCurrentDropLayout(); 728 int originX = x - xOffset; 729 int originY = y - yOffset; 730 if (mIsSmall) { 731 // find out which target layout is over 732 final float[] localXY = mTempDragCoordinates; 733 localXY[0] = originX; 734 localXY[1] = originY; 735 final float[] localBottomRightXY = mTempDragBottomRightCoordinates; 736 // we need to subtract left/top here because DragController already adds 737 // dragRegionLeft/Top to xOffset and yOffset 738 localBottomRightXY[0] = originX + dragView.getDragRegionWidth(); 739 localBottomRightXY[1] = originY + dragView.getDragRegionHeight(); 740 cellLayout = findMatchingPageForDragOver(localXY, localBottomRightXY); 741 if (cellLayout == null) { 742 // cancel the drag if we're not over a mini-screen at time of drop 743 // TODO: maybe add a nice fade here? 744 return; 745 } 746 // localXY will be transformed into the local screen's coordinate space; save that info 747 originX = (int)localXY[0]; 748 originY = (int)localXY[1]; 749 } 750 if (source != this) { 751 onDropExternal(originX, originY, dragInfo, cellLayout); 752 } else { 753 // Move internally 754 if (mDragInfo != null) { 755 final View cell = mDragInfo.cell; 756 int index = mScroller.isFinished() ? mCurrentPage : mNextPage; 757 if (index != mDragInfo.screen) { 758 final CellLayout originalCellLayout = (CellLayout) getChildAt(mDragInfo.screen); 759 originalCellLayout.removeView(cell); 760 addInScreen(cell, index, mDragInfo.cellX, mDragInfo.cellY, 761 mDragInfo.spanX, mDragInfo.spanY); 762 } 763 764 mTargetCell = estimateDropCell(originX, originY, 765 mDragInfo.spanX, mDragInfo.spanY, cell, cellLayout, 766 mTargetCell); 767 cellLayout.onDropChild(cell); 768 769 // update the item's position after drop 770 final ItemInfo info = (ItemInfo) cell.getTag(); 771 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell 772 .getLayoutParams(); 773 lp.cellX = mTargetCell[0]; 774 lp.cellY = mTargetCell[1]; 775 776 LauncherModel.moveItemInDatabase(mLauncher, info, 777 LauncherSettings.Favorites.CONTAINER_DESKTOP, index, 778 lp.cellX, lp.cellY); 779 } 780 } 781 } 782 783 public void onDragEnter(DragSource source, int x, int y, int xOffset, 784 int yOffset, DragView dragView, Object dragInfo) { 785 } 786 787 public DropTarget getDropTargetDelegate(DragSource source, int x, int y, int xOffset, int yOffset, 788 DragView dragView, Object dragInfo) { 789 790 // We may need to delegate the drag to a child view. If a 1x1 item 791 // would land in a cell occupied by a DragTarget (e.g. a Folder), 792 // then drag events should be handled by that child. 793 794 ItemInfo item = (ItemInfo)dragInfo; 795 CellLayout currentLayout = getCurrentDropLayout(); 796 797 int dragPointX, dragPointY; 798 if (item.spanX == 1 && item.spanY == 1) { 799 // For a 1x1, calculate the drop cell exactly as in onDragOver 800 dragPointX = x - xOffset; 801 dragPointY = y - yOffset; 802 } else { 803 // Otherwise, use the exact drag coordinates 804 dragPointX = x; 805 dragPointY = y; 806 } 807 808 // If we are dragging over a cell that contains a DropTarget that will 809 // accept the drop, delegate to that DropTarget. 810 final int[] cellXY = mTempCell; 811 currentLayout.estimateDropCell(dragPointX, dragPointY, item.spanX, item.spanY, cellXY); 812 View child = currentLayout.getChildAt(cellXY[0], cellXY[1]); 813 if (child instanceof DropTarget) { 814 DropTarget target = (DropTarget)child; 815 if (target.acceptDrop(source, x, y, xOffset, yOffset, dragView, dragInfo)) { 816 return target; 817 } 818 } 819 return null; 820 } 821 822 // xy = upper left corner of item being dragged 823 // bottomRightXy = lower right corner of item being dragged 824 // This method will see which mini-screen is most overlapped by the item being dragged, and 825 // return it. It will also transform the parameters xy and bottomRightXy into the local 826 // coordinate space of the returned screen 827 private CellLayout findMatchingPageForDragOver(float[] xy, float[] bottomRightXy) { 828 float x = xy[0]; 829 float y = xy[1]; 830 float right = bottomRightXy[0]; 831 float bottom = bottomRightXy[1]; 832 833 float bestX = 0; 834 float bestY = 0; 835 float bestRight = 0; 836 float bestBottom = 0; 837 838 Matrix inverseMatrix = new Matrix(); 839 840 // We loop through all the screens (ie CellLayouts) and see which one overlaps the most 841 // with the item being dragged. 842 final int screenCount = getChildCount(); 843 CellLayout bestMatchingScreen = null; 844 float bestOverlapSoFar = 0; 845 for (int i = 0; i < screenCount; i++) { 846 CellLayout cl = (CellLayout)getChildAt(i); 847 // Transform the coordinates of the item being dragged to the CellLayout's coordinates 848 float left = cl.getLeft(); 849 float top = cl.getTop(); 850 xy[0] = x + mScrollX - left; 851 xy[1] = y + mScrollY - top; 852 cl.getMatrix().invert(inverseMatrix); 853 854 bottomRightXy[0] = right + mScrollX - left; 855 bottomRightXy[1] = bottom + mScrollY - top; 856 857 inverseMatrix.mapPoints(xy); 858 inverseMatrix.mapPoints(bottomRightXy); 859 860 float dragRegionX = xy[0]; 861 float dragRegionY = xy[1]; 862 float dragRegionRight = bottomRightXy[0]; 863 float dragRegionBottom = bottomRightXy[1]; 864 865 // Find the overlapping region 866 float overlapLeft = Math.max(0f, dragRegionX); 867 float overlapTop = Math.max(0f, dragRegionY); 868 float overlapBottom = Math.min(cl.getHeight(), dragRegionBottom); 869 float overlapRight = Math.min(cl.getWidth(), dragRegionRight); 870 871 if (overlapRight >= 0 && overlapLeft <= cl.getWidth() && 872 overlapTop >= 0 && overlapBottom <= cl.getHeight()) { 873 // Calculate the size of the overlapping region 874 float overlap = (overlapRight - overlapLeft) * (overlapBottom - overlapTop); 875 if (overlap > bestOverlapSoFar) { 876 bestOverlapSoFar = overlap; 877 bestMatchingScreen = cl; 878 bestX = xy[0]; 879 bestY = xy[1]; 880 bestRight = bottomRightXy[0]; 881 bestBottom = bottomRightXy[1]; 882 } 883 } 884 } 885 if (bestMatchingScreen != null && bestMatchingScreen != mDragTargetLayout) { 886 if (mDragTargetLayout != null) { 887 mDragTargetLayout.onDragComplete(); 888 } 889 mDragTargetLayout = bestMatchingScreen; 890 } 891 xy[0] = bestX; 892 xy[1] = bestY; 893 bottomRightXy[0] = bestRight; 894 bottomRightXy[1] = bestBottom; 895 return bestMatchingScreen; 896 } 897 898 public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset, 899 DragView dragView, Object dragInfo) { 900 901 final ItemInfo item = (ItemInfo)dragInfo; 902 CellLayout currentLayout = getCurrentDropLayout(); 903 904 if (dragInfo instanceof LauncherAppWidgetInfo) { 905 LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo)dragInfo; 906 907 if (widgetInfo.spanX == -1) { 908 // Calculate the grid spans needed to fit this widget 909 int[] spans = currentLayout.rectToCell(widgetInfo.minWidth, widgetInfo.minHeight, null); 910 item.spanX = spans[0]; 911 item.spanY = spans[1]; 912 } 913 } 914 int originX = x - xOffset; 915 int originY = y - yOffset; 916 if (mIsSmall) { 917 // find out which mini screen the dragged item is over 918 final float[] localXY = mTempDragCoordinates; 919 localXY[0] = originX; 920 localXY[1] = originY; 921 final float[] localBottomRightXY = mTempDragBottomRightCoordinates; 922 923 localBottomRightXY[0] = originX + dragView.getDragRegionWidth(); 924 localBottomRightXY[1] = originY + dragView.getDragRegionHeight(); 925 currentLayout = findMatchingPageForDragOver(localXY, localBottomRightXY); 926 if (currentLayout != null) { 927 currentLayout.setHover(true); 928 } 929 930 originX = (int)localXY[0]; 931 originY = (int)localXY[1]; 932 } 933 934 if (source != this) { 935 // This is a hack to fix the point used to determine which cell an icon from the all 936 // apps screen is over 937 if (item != null && item.spanX == 1 && currentLayout != null) { 938 int dragRegionLeft = (dragView.getWidth() - currentLayout.getCellWidth()) / 2; 939 940 originX += dragRegionLeft - dragView.getDragRegionLeft(); 941 if (dragView.getDragRegionWidth() != currentLayout.getCellWidth()) { 942 dragView.setDragRegion(dragView.getDragRegionLeft(), dragView.getDragRegionTop(), 943 currentLayout.getCellWidth(), dragView.getDragRegionHeight()); 944 } 945 } 946 } 947 if (currentLayout != mDragTargetLayout) { 948 if (mDragTargetLayout != null) { 949 mDragTargetLayout.onDragComplete(); 950 } 951 mDragTargetLayout = currentLayout; 952 } 953 954 // only visualize the drop locations for moving icons within the home screen on tablet 955 // on phone, we also visualize icons dragged in from All Apps 956 if ((!LauncherApplication.isScreenXLarge() || source == this) 957 && mDragTargetLayout != null) { 958 final View child = (mDragInfo == null) ? null : mDragInfo.cell; 959 mDragTargetLayout.visualizeDropLocation( 960 child, originX, originY, item.spanX, item.spanY); 961 } 962 } 963 964 public void onDragExit(DragSource source, int x, int y, int xOffset, 965 int yOffset, DragView dragView, Object dragInfo) { 966 if (mDragTargetLayout != null) { 967 mDragTargetLayout.onDragComplete(); 968 mDragTargetLayout = null; 969 } 970 } 971 972 private void onDropExternal(int x, int y, Object dragInfo, 973 CellLayout cellLayout) { 974 onDropExternal(x, y, dragInfo, cellLayout, false); 975 } 976 977 private void onDropExternal(int x, int y, Object dragInfo, 978 CellLayout cellLayout, boolean insertAtFirst) { 979 // Drag from somewhere else 980 ItemInfo info = (ItemInfo) dragInfo; 981 982 View view = null; 983 984 switch (info.itemType) { 985 case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: 986 case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: 987 if (info.container == NO_ID && info instanceof ApplicationInfo) { 988 // Came from all apps -- make a copy 989 info = new ShortcutInfo((ApplicationInfo) info); 990 } 991 view = mLauncher.createShortcut(R.layout.application, cellLayout, 992 (ShortcutInfo) info); 993 break; 994 case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER: 995 view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher, 996 (ViewGroup) getChildAt(mCurrentPage), 997 ((UserFolderInfo) info)); 998 break; 999 case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: 1000 cellLayout.setTagToCellInfoForPoint(x, y); 1001 int[] position = new int[2]; 1002 position[0] = x; 1003 position[1] = y; 1004 mLauncher.addAppWidgetFromDrop(((LauncherAppWidgetInfo)dragInfo).providerName, 1005 cellLayout.getTag(), position); 1006 break; 1007 default: 1008 throw new IllegalStateException("Unknown item type: " 1009 + info.itemType); 1010 } 1011 1012 // If the view is null, it has already been added. 1013 if (view == null) { 1014 cellLayout.onDragComplete(); 1015 } else { 1016 mTargetCell = estimateDropCell(x, y, 1, 1, view, cellLayout, mTargetCell); 1017 addInScreen(view, indexOfChild(cellLayout), mTargetCell[0], 1018 mTargetCell[1], info.spanX, info.spanY, insertAtFirst); 1019 cellLayout.onDropChild(view); 1020 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams(); 1021 1022 LauncherModel.addOrMoveItemInDatabase(mLauncher, info, 1023 LauncherSettings.Favorites.CONTAINER_DESKTOP, mCurrentPage, 1024 lp.cellX, lp.cellY); 1025 } 1026 } 1027 1028 /** 1029 * Return the current {@link CellLayout}, correctly picking the destination 1030 * screen while a scroll is in progress. 1031 */ 1032 private CellLayout getCurrentDropLayout() { 1033 int index = mScroller.isFinished() ? mCurrentPage : mNextPage; 1034 return (CellLayout) getChildAt(index); 1035 } 1036 1037 /** 1038 * {@inheritDoc} 1039 */ 1040 public boolean acceptDrop(DragSource source, int x, int y, 1041 int xOffset, int yOffset, DragView dragView, Object dragInfo) { 1042 final CellLayout layout = getCurrentDropLayout(); 1043 final CellLayout.CellInfo dragCellInfo = mDragInfo; 1044 final int spanX = dragCellInfo == null ? 1 : dragCellInfo.spanX; 1045 final int spanY = dragCellInfo == null ? 1 : dragCellInfo.spanY; 1046 1047 final View ignoreView = dragCellInfo == null ? null : dragCellInfo.cell; 1048 final CellLayout.CellInfo cellInfo = layout.updateOccupiedCells(null, ignoreView); 1049 1050 if (cellInfo.findCellForSpan(mTempEstimate, spanX, spanY)) { 1051 return true; 1052 } else { 1053 Toast.makeText(getContext(), getContext().getString(R.string.out_of_space), Toast.LENGTH_SHORT).show(); 1054 return false; 1055 } 1056 } 1057 1058 /** 1059 * {@inheritDoc} 1060 */ 1061 public Rect estimateDropLocation(DragSource source, int x, int y, 1062 int xOffset, int yOffset, DragView dragView, Object dragInfo, Rect recycle) { 1063 final CellLayout layout = getCurrentDropLayout(); 1064 1065 final CellLayout.CellInfo cellInfo = mDragInfo; 1066 final int spanX = cellInfo == null ? 1 : cellInfo.spanX; 1067 final int spanY = cellInfo == null ? 1 : cellInfo.spanY; 1068 final View ignoreView = cellInfo == null ? null : cellInfo.cell; 1069 1070 final Rect location = recycle != null ? recycle : new Rect(); 1071 1072 // Find drop cell and convert into rectangle 1073 int[] dropCell = estimateDropCell(x - xOffset, y - yOffset, spanX, 1074 spanY, ignoreView, layout, mTempCell); 1075 1076 if (dropCell == null) { 1077 return null; 1078 } 1079 1080 layout.cellToPoint(dropCell[0], dropCell[1], mTempEstimate); 1081 location.left = mTempEstimate[0]; 1082 location.top = mTempEstimate[1]; 1083 1084 layout.cellToPoint(dropCell[0] + spanX, dropCell[1] + spanY, mTempEstimate); 1085 location.right = mTempEstimate[0]; 1086 location.bottom = mTempEstimate[1]; 1087 1088 return location; 1089 } 1090 1091 /** 1092 * Calculate the nearest cell where the given object would be dropped. 1093 */ 1094 private int[] estimateDropCell(int pixelX, int pixelY, 1095 int spanX, int spanY, View ignoreView, CellLayout layout, int[] recycle) { 1096 1097 final int[] cellXY = mTempCell; 1098 layout.estimateDropCell(pixelX, pixelY, spanX, spanY, cellXY); 1099 layout.cellToPoint(cellXY[0], cellXY[1], mTempEstimate); 1100 1101 final CellLayout.CellInfo cellInfo = layout.updateOccupiedCells(null, ignoreView); 1102 // Find the best target drop location 1103 return layout.findNearestVacantArea(mTempEstimate[0], mTempEstimate[1], spanX, spanY, cellInfo, recycle); 1104 } 1105 1106 /** 1107 * Estimate the size that a child with the given dimensions will take in the current screen. 1108 */ 1109 void estimateChildSize(int minWidth, int minHeight, int[] result) { 1110 ((CellLayout)getChildAt(mCurrentPage)).estimateChildSize(minWidth, minHeight, result); 1111 } 1112 1113 void setLauncher(Launcher launcher) { 1114 mLauncher = launcher; 1115 } 1116 1117 public void setDragController(DragController dragController) { 1118 mDragController = dragController; 1119 } 1120 1121 public void onDropCompleted(View target, boolean success) { 1122 if (success) { 1123 if (target != this && mDragInfo != null) { 1124 final CellLayout cellLayout = (CellLayout) getChildAt(mDragInfo.screen); 1125 cellLayout.removeView(mDragInfo.cell); 1126 if (mDragInfo.cell instanceof DropTarget) { 1127 mDragController.removeDropTarget((DropTarget)mDragInfo.cell); 1128 } 1129 // final Object tag = mDragInfo.cell.getTag(); 1130 } 1131 } else { 1132 if (mDragInfo != null) { 1133 final CellLayout cellLayout = (CellLayout) getChildAt(mDragInfo.screen); 1134 cellLayout.onDropAborted(mDragInfo.cell); 1135 } 1136 } 1137 1138 mDragInfo = null; 1139 } 1140 1141 @Override 1142 protected void onRestoreInstanceState(Parcelable state) { 1143 super.onRestoreInstanceState(state); 1144 Launcher.setScreen(mCurrentPage); 1145 } 1146 1147 @Override 1148 public void scrollLeft() { 1149 if (!mIsSmall) { 1150 super.scrollLeft(); 1151 } 1152 } 1153 1154 @Override 1155 public void scrollRight() { 1156 if (!mIsSmall) { 1157 super.scrollRight(); 1158 } 1159 } 1160 1161 public Folder getFolderForTag(Object tag) { 1162 final int screenCount = getChildCount(); 1163 for (int screen = 0; screen < screenCount; screen++) { 1164 CellLayout currentScreen = ((CellLayout) getChildAt(screen)); 1165 int count = currentScreen.getChildCount(); 1166 for (int i = 0; i < count; i++) { 1167 View child = currentScreen.getChildAt(i); 1168 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); 1169 if (lp.cellHSpan == 4 && lp.cellVSpan == 4 && child instanceof Folder) { 1170 Folder f = (Folder) child; 1171 if (f.getInfo() == tag && f.getInfo().opened) { 1172 return f; 1173 } 1174 } 1175 } 1176 } 1177 return null; 1178 } 1179 1180 public View getViewForTag(Object tag) { 1181 int screenCount = getChildCount(); 1182 for (int screen = 0; screen < screenCount; screen++) { 1183 CellLayout currentScreen = ((CellLayout) getChildAt(screen)); 1184 int count = currentScreen.getChildCount(); 1185 for (int i = 0; i < count; i++) { 1186 View child = currentScreen.getChildAt(i); 1187 if (child.getTag() == tag) { 1188 return child; 1189 } 1190 } 1191 } 1192 return null; 1193 } 1194 1195 1196 void removeItems(final ArrayList<ApplicationInfo> apps) { 1197 final int screenCount = getChildCount(); 1198 final PackageManager manager = getContext().getPackageManager(); 1199 final AppWidgetManager widgets = AppWidgetManager.getInstance(getContext()); 1200 1201 final HashSet<String> packageNames = new HashSet<String>(); 1202 final int appCount = apps.size(); 1203 for (int i = 0; i < appCount; i++) { 1204 packageNames.add(apps.get(i).componentName.getPackageName()); 1205 } 1206 1207 for (int i = 0; i < screenCount; i++) { 1208 final CellLayout layout = (CellLayout) getChildAt(i); 1209 1210 // Avoid ANRs by treating each screen separately 1211 post(new Runnable() { 1212 public void run() { 1213 final ArrayList<View> childrenToRemove = new ArrayList<View>(); 1214 childrenToRemove.clear(); 1215 1216 int childCount = layout.getChildCount(); 1217 for (int j = 0; j < childCount; j++) { 1218 final View view = layout.getChildAt(j); 1219 Object tag = view.getTag(); 1220 1221 if (tag instanceof ShortcutInfo) { 1222 final ShortcutInfo info = (ShortcutInfo) tag; 1223 final Intent intent = info.intent; 1224 final ComponentName name = intent.getComponent(); 1225 1226 if (Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) { 1227 for (String packageName: packageNames) { 1228 if (packageName.equals(name.getPackageName())) { 1229 // TODO: This should probably be done on a worker thread 1230 LauncherModel.deleteItemFromDatabase(mLauncher, info); 1231 childrenToRemove.add(view); 1232 } 1233 } 1234 } 1235 } else if (tag instanceof UserFolderInfo) { 1236 final UserFolderInfo info = (UserFolderInfo) tag; 1237 final ArrayList<ShortcutInfo> contents = info.contents; 1238 final ArrayList<ShortcutInfo> toRemove = new ArrayList<ShortcutInfo>(1); 1239 final int contentsCount = contents.size(); 1240 boolean removedFromFolder = false; 1241 1242 for (int k = 0; k < contentsCount; k++) { 1243 final ShortcutInfo appInfo = contents.get(k); 1244 final Intent intent = appInfo.intent; 1245 final ComponentName name = intent.getComponent(); 1246 1247 if (Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) { 1248 for (String packageName: packageNames) { 1249 if (packageName.equals(name.getPackageName())) { 1250 toRemove.add(appInfo); 1251 // TODO: This should probably be done on a worker thread 1252 LauncherModel.deleteItemFromDatabase( 1253 mLauncher, appInfo); 1254 removedFromFolder = true; 1255 } 1256 } 1257 } 1258 } 1259 1260 contents.removeAll(toRemove); 1261 if (removedFromFolder) { 1262 final Folder folder = getOpenFolder(); 1263 if (folder != null) 1264 folder.notifyDataSetChanged(); 1265 } 1266 } else if (tag instanceof LiveFolderInfo) { 1267 final LiveFolderInfo info = (LiveFolderInfo) tag; 1268 final Uri uri = info.uri; 1269 final ProviderInfo providerInfo = manager.resolveContentProvider( 1270 uri.getAuthority(), 0); 1271 1272 if (providerInfo != null) { 1273 for (String packageName: packageNames) { 1274 if (packageName.equals(providerInfo.packageName)) { 1275 // TODO: This should probably be done on a worker thread 1276 LauncherModel.deleteItemFromDatabase(mLauncher, info); 1277 childrenToRemove.add(view); 1278 } 1279 } 1280 } 1281 } else if (tag instanceof LauncherAppWidgetInfo) { 1282 final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) tag; 1283 final AppWidgetProviderInfo provider = 1284 widgets.getAppWidgetInfo(info.appWidgetId); 1285 if (provider != null) { 1286 for (String packageName: packageNames) { 1287 if (packageName.equals(provider.provider.getPackageName())) { 1288 // TODO: This should probably be done on a worker thread 1289 LauncherModel.deleteItemFromDatabase(mLauncher, info); 1290 childrenToRemove.add(view); 1291 } 1292 } 1293 } 1294 } 1295 } 1296 1297 childCount = childrenToRemove.size(); 1298 for (int j = 0; j < childCount; j++) { 1299 View child = childrenToRemove.get(j); 1300 layout.removeViewInLayout(child); 1301 if (child instanceof DropTarget) { 1302 mDragController.removeDropTarget((DropTarget)child); 1303 } 1304 } 1305 1306 if (childCount > 0) { 1307 layout.requestLayout(); 1308 layout.invalidate(); 1309 } 1310 } 1311 }); 1312 } 1313 } 1314 1315 void updateShortcuts(ArrayList<ApplicationInfo> apps) { 1316 final PackageManager pm = mLauncher.getPackageManager(); 1317 1318 final int screenCount = getChildCount(); 1319 for (int i = 0; i < screenCount; i++) { 1320 final CellLayout layout = (CellLayout) getChildAt(i); 1321 int childCount = layout.getChildCount(); 1322 for (int j = 0; j < childCount; j++) { 1323 final View view = layout.getChildAt(j); 1324 Object tag = view.getTag(); 1325 if (tag instanceof ShortcutInfo) { 1326 ShortcutInfo info = (ShortcutInfo)tag; 1327 // We need to check for ACTION_MAIN otherwise getComponent() might 1328 // return null for some shortcuts (for instance, for shortcuts to 1329 // web pages.) 1330 final Intent intent = info.intent; 1331 final ComponentName name = intent.getComponent(); 1332 if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION && 1333 Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) { 1334 final int appCount = apps.size(); 1335 for (int k = 0; k < appCount; k++) { 1336 ApplicationInfo app = apps.get(k); 1337 if (app.componentName.equals(name)) { 1338 info.setIcon(mIconCache.getIcon(info.intent)); 1339 ((TextView)view).setCompoundDrawablesWithIntrinsicBounds(null, 1340 new FastBitmapDrawable(info.getIcon(mIconCache)), 1341 null, null); 1342 } 1343 } 1344 } 1345 } 1346 } 1347 } 1348 } 1349 1350 void moveToDefaultScreen(boolean animate) { 1351 if (animate) { 1352 if (mIsSmall) { 1353 unshrink(mDefaultPage); 1354 } else { 1355 snapToPage(mDefaultPage); 1356 } 1357 } else { 1358 setCurrentPage(mDefaultPage); 1359 } 1360 getChildAt(mDefaultPage).requestFocus(); 1361 } 1362 1363 void setIndicators(Drawable previous, Drawable next) { 1364 mPreviousIndicator = previous; 1365 mNextIndicator = next; 1366 previous.setLevel(mCurrentPage); 1367 next.setLevel(mCurrentPage); 1368 } 1369 1370 @Override 1371 public void syncPages() { 1372 } 1373 1374 @Override 1375 public void syncPageItems(int page) { 1376 } 1377 1378} 1379