Workspace.java revision 8e58e916061cbe2623697efac0924f2aa3753a92
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.Animator; 22import android.animation.Animator.AnimatorListener; 23import android.animation.AnimatorListenerAdapter; 24import android.animation.AnimatorSet; 25import android.animation.ObjectAnimator; 26import android.animation.PropertyValuesHolder; 27import android.app.WallpaperManager; 28import android.appwidget.AppWidgetManager; 29import android.appwidget.AppWidgetProviderInfo; 30import android.content.ComponentName; 31import android.content.Context; 32import android.content.Intent; 33import android.content.pm.PackageManager; 34import android.content.pm.ProviderInfo; 35import android.content.res.Resources; 36import android.content.res.TypedArray; 37import android.graphics.Bitmap; 38import android.graphics.Canvas; 39import android.graphics.Matrix; 40import android.graphics.Rect; 41import android.graphics.Region.Op; 42import android.graphics.drawable.Drawable; 43import android.net.Uri; 44import android.os.IBinder; 45import android.os.Parcelable; 46import android.util.AttributeSet; 47import android.util.Log; 48import android.view.MotionEvent; 49import android.view.View; 50import android.widget.TextView; 51 52import java.util.ArrayList; 53import java.util.HashSet; 54 55/** 56 * The workspace is a wide area with a wallpaper and a finite number of pages. 57 * Each page contains a number of icons, folders or widgets the user can 58 * interact with. A workspace is meant to be used with a fixed width only. 59 */ 60public class Workspace extends SmoothPagedView 61 implements DropTarget, DragSource, DragScroller, View.OnTouchListener { 62 @SuppressWarnings({"UnusedDeclaration"}) 63 private static final String TAG = "Launcher.Workspace"; 64 65 // This is how much the workspace shrinks when we enter all apps or 66 // customization mode 67 private static final float SHRINK_FACTOR = 0.16f; 68 69 // Y rotation to apply to the workspace screens 70 private static final float WORKSPACE_ROTATION = 12.5f; 71 72 // These are extra scale factors to apply to the mini home screens 73 // so as to achieve the desired transform 74 private static final float EXTRA_SCALE_FACTOR_0 = 0.97f; 75 private static final float EXTRA_SCALE_FACTOR_1 = 1.0f; 76 private static final float EXTRA_SCALE_FACTOR_2 = 1.08f; 77 78 private static final int BACKGROUND_FADE_OUT_DELAY = 300; 79 private static final int BACKGROUND_FADE_OUT_DURATION = 300; 80 private static final int BACKGROUND_FADE_IN_DURATION = 100; 81 82 // These animators are used to fade the background 83 private ObjectAnimator mBackgroundFadeInAnimation; 84 private ObjectAnimator mBackgroundFadeOutAnimation; 85 private float mBackgroundAlpha = 0; 86 87 private final WallpaperManager mWallpaperManager; 88 89 private int mDefaultPage; 90 91 private boolean mWaitingToShrinkToBottom = false; 92 93 private boolean mPageMoving = false; 94 95 /** 96 * CellInfo for the cell that is currently being dragged 97 */ 98 private CellLayout.CellInfo mDragInfo; 99 100 /** 101 * Target drop area calculated during last acceptDrop call. 102 */ 103 private int[] mTargetCell = null; 104 105 /** 106 * The CellLayout that is currently being dragged over 107 */ 108 private CellLayout mDragTargetLayout = null; 109 110 private Launcher mLauncher; 111 private IconCache mIconCache; 112 private DragController mDragController; 113 114 // These are temporary variables to prevent having to allocate a new object just to 115 // return an (x, y) value from helper functions. Do NOT use them to maintain other state. 116 private int[] mTempCell = new int[2]; 117 private int[] mTempEstimate = new int[2]; 118 private float[] mTempOriginXY = new float[2]; 119 private float[] mTempDragCoordinates = new float[2]; 120 private float[] mTempTouchCoordinates = new float[2]; 121 private float[] mTempCellLayoutCenterCoordinates = new float[2]; 122 private float[] mTempDragBottomRightCoordinates = new float[2]; 123 private Matrix mTempInverseMatrix = new Matrix(); 124 125 private static final int DEFAULT_CELL_COUNT_X = 4; 126 private static final int DEFAULT_CELL_COUNT_Y = 4; 127 128 private Drawable mPreviousIndicator; 129 private Drawable mNextIndicator; 130 131 // State variable that indicates whether the pages are small (ie when you're 132 // in all apps or customize mode) 133 private boolean mIsSmall = false; 134 private boolean mIsInUnshrinkAnimation = false; 135 private AnimatorListener mUnshrinkAnimationListener; 136 private enum ShrinkPosition { 137 SHRINK_TO_TOP, SHRINK_TO_MIDDLE, SHRINK_TO_BOTTOM_HIDDEN, SHRINK_TO_BOTTOM_VISIBLE }; 138 private ShrinkPosition mShrunkenState; 139 140 private boolean mInScrollArea = false; 141 142 private final HolographicOutlineHelper mOutlineHelper = new HolographicOutlineHelper(); 143 private Bitmap mDragOutline = null; 144 private final Rect mTempRect = new Rect(); 145 private final int[] mTempXY = new int[2]; 146 147 /** 148 * Used to inflate the Workspace from XML. 149 * 150 * @param context The application's context. 151 * @param attrs The attributes set containing the Workspace's customization values. 152 */ 153 public Workspace(Context context, AttributeSet attrs) { 154 this(context, attrs, 0); 155 } 156 157 /** 158 * Used to inflate the Workspace from XML. 159 * 160 * @param context The application's context. 161 * @param attrs The attributes set containing the Workspace's customization values. 162 * @param defStyle Unused. 163 */ 164 public Workspace(Context context, AttributeSet attrs, int defStyle) { 165 super(context, attrs, defStyle); 166 mContentIsRefreshable = false; 167 168 if (!LauncherApplication.isScreenXLarge()) { 169 mFadeInAdjacentScreens = false; 170 } 171 172 mWallpaperManager = WallpaperManager.getInstance(context); 173 174 TypedArray a = context.obtainStyledAttributes(attrs, 175 R.styleable.Workspace, defStyle, 0); 176 int cellCountX = a.getInt(R.styleable.Workspace_cellCountX, DEFAULT_CELL_COUNT_X); 177 int cellCountY = a.getInt(R.styleable.Workspace_cellCountY, DEFAULT_CELL_COUNT_Y); 178 mDefaultPage = a.getInt(R.styleable.Workspace_defaultScreen, 1); 179 a.recycle(); 180 181 LauncherModel.updateWorkspaceLayoutCells(cellCountX, cellCountY); 182 setHapticFeedbackEnabled(false); 183 184 initWorkspace(); 185 } 186 187 /** 188 * Initializes various states for this workspace. 189 */ 190 protected void initWorkspace() { 191 Context context = getContext(); 192 mCurrentPage = mDefaultPage; 193 Launcher.setScreen(mCurrentPage); 194 LauncherApplication app = (LauncherApplication)context.getApplicationContext(); 195 mIconCache = app.getIconCache(); 196 197 mUnshrinkAnimationListener = new AnimatorListenerAdapter() { 198 public void onAnimationStart(Animator animation) { 199 mIsInUnshrinkAnimation = true; 200 } 201 public void onAnimationEnd(Animator animation) { 202 mIsInUnshrinkAnimation = false; 203 } 204 }; 205 206 mSnapVelocity = 600; 207 } 208 209 @Override 210 protected int getScrollMode() { 211 if (LauncherApplication.isScreenXLarge()) { 212 return SmoothPagedView.QUINTIC_MODE; 213 } else { 214 return SmoothPagedView.OVERSHOOT_MODE; 215 } 216 } 217 218 @Override 219 public void addView(View child, int index, LayoutParams params) { 220 if (!(child instanceof CellLayout)) { 221 throw new IllegalArgumentException("A Workspace can only have CellLayout children."); 222 } 223 ((CellLayout) child).setOnInterceptTouchListener(this); 224 super.addView(child, index, params); 225 } 226 227 @Override 228 public void addView(View child) { 229 if (!(child instanceof CellLayout)) { 230 throw new IllegalArgumentException("A Workspace can only have CellLayout children."); 231 } 232 ((CellLayout) child).setOnInterceptTouchListener(this); 233 super.addView(child); 234 } 235 236 @Override 237 public void addView(View child, int index) { 238 if (!(child instanceof CellLayout)) { 239 throw new IllegalArgumentException("A Workspace can only have CellLayout children."); 240 } 241 ((CellLayout) child).setOnInterceptTouchListener(this); 242 super.addView(child, index); 243 } 244 245 @Override 246 public void addView(View child, int width, int height) { 247 if (!(child instanceof CellLayout)) { 248 throw new IllegalArgumentException("A Workspace can only have CellLayout children."); 249 } 250 ((CellLayout) child).setOnInterceptTouchListener(this); 251 super.addView(child, width, height); 252 } 253 254 @Override 255 public void addView(View child, LayoutParams params) { 256 if (!(child instanceof CellLayout)) { 257 throw new IllegalArgumentException("A Workspace can only have CellLayout children."); 258 } 259 ((CellLayout) child).setOnInterceptTouchListener(this); 260 super.addView(child, params); 261 } 262 263 /** 264 * @return The open folder on the current screen, or null if there is none 265 */ 266 Folder getOpenFolder() { 267 CellLayout currentPage = (CellLayout) getChildAt(mCurrentPage); 268 int count = currentPage.getChildCount(); 269 for (int i = 0; i < count; i++) { 270 View child = currentPage.getChildAt(i); 271 if (child instanceof Folder) { 272 Folder folder = (Folder) child; 273 if (folder.getInfo().opened) 274 return folder; 275 } 276 } 277 return null; 278 } 279 280 ArrayList<Folder> getOpenFolders() { 281 final int screenCount = getChildCount(); 282 ArrayList<Folder> folders = new ArrayList<Folder>(screenCount); 283 284 for (int screen = 0; screen < screenCount; screen++) { 285 CellLayout currentPage = (CellLayout) getChildAt(screen); 286 int count = currentPage.getChildCount(); 287 for (int i = 0; i < count; i++) { 288 View child = currentPage.getChildAt(i); 289 if (child instanceof Folder) { 290 Folder folder = (Folder) child; 291 if (folder.getInfo().opened) 292 folders.add(folder); 293 break; 294 } 295 } 296 } 297 298 return folders; 299 } 300 301 boolean isDefaultPageShowing() { 302 return mCurrentPage == mDefaultPage; 303 } 304 305 /** 306 * Sets the current screen. 307 * 308 * @param currentPage 309 */ 310 @Override 311 void setCurrentPage(int currentPage) { 312 super.setCurrentPage(currentPage); 313 updateWallpaperOffset(mScrollX); 314 } 315 316 /** 317 * Adds the specified child in the specified screen. The position and dimension of 318 * the child are defined by x, y, spanX and spanY. 319 * 320 * @param child The child to add in one of the workspace's screens. 321 * @param screen The screen in which to add the child. 322 * @param x The X position of the child in the screen's grid. 323 * @param y The Y position of the child in the screen's grid. 324 * @param spanX The number of cells spanned horizontally by the child. 325 * @param spanY The number of cells spanned vertically by the child. 326 */ 327 void addInScreen(View child, int screen, int x, int y, int spanX, int spanY) { 328 addInScreen(child, screen, x, y, spanX, spanY, false); 329 } 330 331 void addInFullScreen(View child, int screen) { 332 addInScreen(child, screen, 0, 0, -1, -1); 333 } 334 335 /** 336 * Adds the specified child in the specified screen. The position and dimension of 337 * the child are defined by x, y, spanX and spanY. 338 * 339 * @param child The child to add in one of the workspace's screens. 340 * @param screen The screen in which to add the child. 341 * @param x The X position of the child in the screen's grid. 342 * @param y The Y position of the child in the screen's grid. 343 * @param spanX The number of cells spanned horizontally by the child. 344 * @param spanY The number of cells spanned vertically by the child. 345 * @param insert When true, the child is inserted at the beginning of the children list. 346 */ 347 void addInScreen(View child, int screen, int x, int y, int spanX, int spanY, boolean insert) { 348 if (screen < 0 || screen >= getChildCount()) { 349 Log.e(TAG, "The screen must be >= 0 and < " + getChildCount() 350 + " (was " + screen + "); skipping child"); 351 return; 352 } 353 354 final CellLayout group = (CellLayout) getChildAt(screen); 355 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); 356 if (lp == null) { 357 lp = new CellLayout.LayoutParams(x, y, spanX, spanY); 358 } else { 359 lp.cellX = x; 360 lp.cellY = y; 361 lp.cellHSpan = spanX; 362 lp.cellVSpan = spanY; 363 } 364 365 // Get the canonical child id to uniquely represent this view in this screen 366 int childId = LauncherModel.getCellLayoutChildId(-1, screen, x, y, spanX, spanY); 367 if (!group.addViewToCellLayout(child, insert ? 0 : -1, childId, lp)) { 368 // TODO: This branch occurs when the workspace is adding views 369 // outside of the defined grid 370 // maybe we should be deleting these items from the LauncherModel? 371 Log.w(TAG, "Failed to add to item at (" + lp.cellX + "," + lp.cellY + ") to CellLayout"); 372 } 373 374 if (!(child instanceof Folder)) { 375 child.setHapticFeedbackEnabled(false); 376 child.setOnLongClickListener(mLongClickListener); 377 } 378 if (child instanceof DropTarget) { 379 mDragController.addDropTarget((DropTarget) child); 380 } 381 } 382 383 public boolean onTouch(View v, MotionEvent event) { 384 // this is an intercepted event being forwarded from a cell layout 385 if (mIsSmall || mIsInUnshrinkAnimation) { 386 mLauncher.onWorkspaceClick((CellLayout) v); 387 return true; 388 } else if (!mPageMoving) { 389 if (v == getChildAt(mCurrentPage - 1)) { 390 snapToPage(mCurrentPage - 1); 391 return true; 392 } else if (v == getChildAt(mCurrentPage + 1)) { 393 snapToPage(mCurrentPage + 1); 394 return true; 395 } 396 } 397 return false; 398 } 399 400 @Override 401 public boolean dispatchUnhandledMove(View focused, int direction) { 402 if (mIsSmall || mIsInUnshrinkAnimation) { 403 // when the home screens are shrunken, shouldn't allow side-scrolling 404 return false; 405 } 406 return super.dispatchUnhandledMove(focused, direction); 407 } 408 409 @Override 410 public boolean onInterceptTouchEvent(MotionEvent ev) { 411 if (mIsSmall || mIsInUnshrinkAnimation) { 412 // when the home screens are shrunken, shouldn't allow side-scrolling 413 return false; 414 } 415 return super.onInterceptTouchEvent(ev); 416 } 417 418 @Override 419 protected void determineScrollingStart(MotionEvent ev) { 420 if (!mIsSmall && !mIsInUnshrinkAnimation) super.determineScrollingStart(ev); 421 } 422 423 protected void onPageBeginMoving() { 424 if (mNextPage != INVALID_PAGE) { 425 // we're snapping to a particular screen 426 enableChildrenCache(mCurrentPage, mNextPage); 427 } else { 428 // this is when user is actively dragging a particular screen, they might 429 // swipe it either left or right (but we won't advance by more than one screen) 430 enableChildrenCache(mCurrentPage - 1, mCurrentPage + 1); 431 } 432 showOutlines(); 433 mPageMoving = true; 434 } 435 436 protected void onPageEndMoving() { 437 clearChildrenCache(); 438 // Hide the outlines, as long as we're not dragging 439 if (!mDragController.dragging()) { 440 hideOutlines(); 441 } 442 mPageMoving = false; 443 } 444 445 @Override 446 protected void notifyPageSwitchListener() { 447 super.notifyPageSwitchListener(); 448 449 if (mPreviousIndicator != null) { 450 // if we know the next page, we show the indication for it right away; it looks 451 // weird if the indicators are lagging 452 int page = mNextPage; 453 if (page == INVALID_PAGE) { 454 page = mCurrentPage; 455 } 456 mPreviousIndicator.setLevel(page); 457 mNextIndicator.setLevel(page); 458 } 459 Launcher.setScreen(mCurrentPage); 460 }; 461 462 private void updateWallpaperOffset() { 463 updateWallpaperOffset(getChildAt(getChildCount() - 1).getRight() - (mRight - mLeft)); 464 } 465 466 private void updateWallpaperOffset(int scrollRange) { 467 final boolean isStaticWallpaper = (mWallpaperManager != null) && 468 (mWallpaperManager.getWallpaperInfo() == null); 469 if (LauncherApplication.isScreenXLarge() && !isStaticWallpaper) { 470 IBinder token = getWindowToken(); 471 if (token != null) { 472 mWallpaperManager.setWallpaperOffsetSteps(1.0f / (getChildCount() - 1), 0 ); 473 mWallpaperManager.setWallpaperOffsets(getWindowToken(), 474 Math.max(0.f, Math.min(mScrollX/(float)scrollRange, 1.f)), 0); 475 } 476 } 477 } 478 479 public void showOutlines() { 480 if (!mIsSmall && !mIsInUnshrinkAnimation) { 481 if (mBackgroundFadeOutAnimation != null) mBackgroundFadeOutAnimation.cancel(); 482 if (mBackgroundFadeInAnimation != null) mBackgroundFadeInAnimation.cancel(); 483 mBackgroundFadeInAnimation = ObjectAnimator.ofFloat(this, "backgroundAlpha", 1.0f); 484 mBackgroundFadeInAnimation.setDuration(BACKGROUND_FADE_IN_DURATION); 485 mBackgroundFadeInAnimation.start(); 486 } 487 } 488 489 public void hideOutlines() { 490 if (!mIsSmall && !mIsInUnshrinkAnimation) { 491 if (mBackgroundFadeInAnimation != null) mBackgroundFadeInAnimation.cancel(); 492 if (mBackgroundFadeOutAnimation != null) mBackgroundFadeOutAnimation.cancel(); 493 mBackgroundFadeOutAnimation = ObjectAnimator.ofFloat(this, "backgroundAlpha", 0.0f); 494 mBackgroundFadeOutAnimation.setDuration(BACKGROUND_FADE_OUT_DURATION); 495 mBackgroundFadeOutAnimation.setStartDelay(BACKGROUND_FADE_OUT_DELAY); 496 mBackgroundFadeOutAnimation.start(); 497 } 498 } 499 500 public void setBackgroundAlpha(float alpha) { 501 mBackgroundAlpha = alpha; 502 for (int i = 0; i < getChildCount(); i++) { 503 CellLayout cl = (CellLayout) getChildAt(i); 504 cl.setBackgroundAlpha(alpha); 505 } 506 } 507 508 public float getBackgroundAlpha() { 509 return mBackgroundAlpha; 510 } 511 512 @Override 513 protected void screenScrolled(int screenCenter) { 514 final int halfScreenSize = getMeasuredWidth() / 2; 515 for (int i = 0; i < getChildCount(); i++) { 516 View v = getChildAt(i); 517 if (v != null) { 518 int totalDistance = v.getMeasuredWidth() + mPageSpacing; 519 int delta = screenCenter - (getChildOffset(i) - 520 getRelativeChildOffset(i) + halfScreenSize); 521 522 float scrollProgress = delta/(totalDistance*1.0f); 523 scrollProgress = Math.min(scrollProgress, 1.0f); 524 scrollProgress = Math.max(scrollProgress, -1.0f); 525 526 float rotation = WORKSPACE_ROTATION * scrollProgress; 527 v.setRotationY(rotation); 528 } 529 } 530 } 531 532 protected void onAttachedToWindow() { 533 super.onAttachedToWindow(); 534 computeScroll(); 535 mDragController.setWindowToken(getWindowToken()); 536 } 537 538 @Override 539 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 540 super.onLayout(changed, left, top, right, bottom); 541 542 // if shrinkToBottom() is called on initialization, it has to be deferred 543 // until after the first call to onLayout so that it has the correct width 544 if (mWaitingToShrinkToBottom) { 545 shrinkToBottom(false); 546 mWaitingToShrinkToBottom = false; 547 } 548 549 if (LauncherApplication.isInPlaceRotationEnabled()) { 550 // When the device is rotated, the scroll position of the current screen 551 // needs to be refreshed 552 setCurrentPage(getCurrentPage()); 553 } 554 } 555 556 @Override 557 protected void dispatchDraw(Canvas canvas) { 558 if (mIsSmall || mIsInUnshrinkAnimation) { 559 // Draw all the workspaces if we're small 560 final int pageCount = getChildCount(); 561 final long drawingTime = getDrawingTime(); 562 for (int i = 0; i < pageCount; i++) { 563 final View page = (View) getChildAt(i); 564 565 drawChild(canvas, page, drawingTime); 566 } 567 } else { 568 super.dispatchDraw(canvas); 569 } 570 } 571 572 @Override 573 protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { 574 if (!mLauncher.isAllAppsVisible()) { 575 final Folder openFolder = getOpenFolder(); 576 if (openFolder != null) { 577 return openFolder.requestFocus(direction, previouslyFocusedRect); 578 } else { 579 return super.onRequestFocusInDescendants(direction, previouslyFocusedRect); 580 } 581 } 582 return false; 583 } 584 585 @Override 586 public void addFocusables(ArrayList<View> views, int direction, int focusableMode) { 587 if (!mLauncher.isAllAppsVisible()) { 588 final Folder openFolder = getOpenFolder(); 589 if (openFolder != null) { 590 openFolder.addFocusables(views, direction); 591 } else { 592 super.addFocusables(views, direction, focusableMode); 593 } 594 } 595 } 596 597 @Override 598 public boolean dispatchTouchEvent(MotionEvent ev) { 599 if (ev.getAction() == MotionEvent.ACTION_DOWN) { 600 // (In XLarge mode, the workspace is shrunken below all apps, and responds to taps 601 // ie when you click on a mini-screen, it zooms back to that screen) 602 if (!LauncherApplication.isScreenXLarge() && mLauncher.isAllAppsVisible()) { 603 return false; 604 } 605 } 606 return super.dispatchTouchEvent(ev); 607 } 608 609 void enableChildrenCache(int fromPage, int toPage) { 610 if (fromPage > toPage) { 611 final int temp = fromPage; 612 fromPage = toPage; 613 toPage = temp; 614 } 615 616 final int screenCount = getChildCount(); 617 618 fromPage = Math.max(fromPage, 0); 619 toPage = Math.min(toPage, screenCount - 1); 620 621 for (int i = fromPage; i <= toPage; i++) { 622 final CellLayout layout = (CellLayout) getChildAt(i); 623 layout.setChildrenDrawnWithCacheEnabled(true); 624 layout.setChildrenDrawingCacheEnabled(true); 625 } 626 } 627 628 void clearChildrenCache() { 629 final int screenCount = getChildCount(); 630 for (int i = 0; i < screenCount; i++) { 631 final CellLayout layout = (CellLayout) getChildAt(i); 632 layout.setChildrenDrawnWithCacheEnabled(false); 633 } 634 } 635 636 @Override 637 public boolean onTouchEvent(MotionEvent ev) { 638 if (mLauncher.isAllAppsVisible()) { 639 // Cancel any scrolling that is in progress. 640 if (!mScroller.isFinished()) { 641 mScroller.abortAnimation(); 642 } 643 setCurrentPage(mCurrentPage); 644 return false; // We don't want the events. Let them fall through to the all apps view. 645 } 646 647 return super.onTouchEvent(ev); 648 } 649 650 public boolean isSmall() { 651 return mIsSmall; 652 } 653 654 void shrinkToTop(boolean animated) { 655 shrink(ShrinkPosition.SHRINK_TO_TOP, animated); 656 } 657 658 void shrinkToMiddle() { 659 shrink(ShrinkPosition.SHRINK_TO_MIDDLE, true); 660 } 661 662 void shrinkToBottom() { 663 shrinkToBottom(true); 664 } 665 666 void shrinkToBottom(boolean animated) { 667 if (mFirstLayout) { 668 // (mFirstLayout == "first layout has not happened yet") 669 // if we get a call to shrink() as part of our initialization (for example, if 670 // Launcher is started in All Apps mode) then we need to wait for a layout call 671 // to get our width so we can layout the mini-screen views correctly 672 mWaitingToShrinkToBottom = true; 673 } else { 674 shrink(ShrinkPosition.SHRINK_TO_BOTTOM_HIDDEN, animated); 675 } 676 } 677 678 private float getYScaleForScreen(int screen) { 679 int x = Math.abs(screen - 2); 680 681 // TODO: This should be generalized for use with arbitrary rotation angles. 682 switch(x) { 683 case 0: return EXTRA_SCALE_FACTOR_0; 684 case 1: return EXTRA_SCALE_FACTOR_1; 685 case 2: return EXTRA_SCALE_FACTOR_2; 686 } 687 return 1.0f; 688 } 689 690 // we use this to shrink the workspace for the all apps view and the customize view 691 private void shrink(ShrinkPosition shrinkPosition, boolean animated) { 692 mIsSmall = true; 693 mShrunkenState = shrinkPosition; 694 695 // Stop any scrolling, move to the current page right away 696 setCurrentPage(mCurrentPage); 697 updateWhichPagesAcceptDrops(mShrunkenState); 698 699 // we intercept and reject all touch events when we're small, so be sure to reset the state 700 mTouchState = TOUCH_STATE_REST; 701 mActivePointerId = INVALID_POINTER; 702 703 final Resources res = getResources(); 704 final int screenWidth = getWidth(); 705 final int screenHeight = getHeight(); 706 707 // Making the assumption that all pages have the same width as the 0th 708 final int pageWidth = getChildAt(0).getMeasuredWidth(); 709 final int pageHeight = getChildAt(0).getMeasuredHeight(); 710 711 final int scaledPageWidth = (int) (SHRINK_FACTOR * pageWidth); 712 final int scaledPageHeight = (int) (SHRINK_FACTOR * pageHeight); 713 final float extraScaledSpacing = res.getDimension(R.dimen.smallScreenExtraSpacing); 714 715 final int screenCount = getChildCount(); 716 float totalWidth = screenCount * scaledPageWidth + (screenCount - 1) * extraScaledSpacing; 717 718 float newY = getResources().getDimension(R.dimen.smallScreenVerticalMargin); 719 float finalAlpha = 1.0f; 720 float extraShrinkFactor = 1.0f; 721 if (shrinkPosition == ShrinkPosition.SHRINK_TO_BOTTOM_VISIBLE) { 722 newY = screenHeight - newY - scaledPageHeight; 723 } else if (shrinkPosition == ShrinkPosition.SHRINK_TO_BOTTOM_HIDDEN) { 724 725 // We shrink and disappear to nothing in the case of all apps 726 // (which is when we shrink to the bottom) 727 newY = screenHeight - newY - scaledPageHeight; 728 finalAlpha = 0.0f; 729 extraShrinkFactor = 0.1f; 730 } else if (shrinkPosition == ShrinkPosition.SHRINK_TO_MIDDLE) { 731 newY = screenHeight / 2 - scaledPageHeight / 2; 732 finalAlpha = 1.0f; 733 } else if (shrinkPosition == ShrinkPosition.SHRINK_TO_TOP) { 734 newY = screenHeight / 10; 735 } 736 737 // We animate all the screens to the centered position in workspace 738 // At the same time, the screens become greyed/dimmed 739 740 // newX is initialized to the left-most position of the centered screens 741 float newX = mScroller.getFinalX() + screenWidth / 2 - totalWidth / 2; 742 743 // We are going to scale about the center of the view, so we need to adjust the positions 744 // of the views accordingly 745 newX -= (pageWidth - scaledPageWidth) / 2.0f; 746 newY -= (pageHeight - scaledPageHeight) / 2.0f; 747 for (int i = 0; i < screenCount; i++) { 748 CellLayout cl = (CellLayout) getChildAt(i); 749 750 float rotation = (-i + 2) * WORKSPACE_ROTATION; 751 float rotationScaleX = (float) (1.0f / Math.cos(Math.PI * rotation / 180.0f)); 752 float rotationScaleY = getYScaleForScreen(i); 753 754 if (animated) { 755 final int duration = res.getInteger(R.integer.config_workspaceShrinkTime); 756 ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(cl, 757 PropertyValuesHolder.ofFloat("x", newX), 758 PropertyValuesHolder.ofFloat("y", newY), 759 PropertyValuesHolder.ofFloat("scaleX", 760 SHRINK_FACTOR * rotationScaleX * extraShrinkFactor), 761 PropertyValuesHolder.ofFloat("scaleY", 762 SHRINK_FACTOR * rotationScaleY * extraShrinkFactor), 763 PropertyValuesHolder.ofFloat("backgroundAlpha", finalAlpha), 764 PropertyValuesHolder.ofFloat("alpha", finalAlpha), 765 PropertyValuesHolder.ofFloat("rotationY", rotation)); 766 anim.setDuration(duration); 767 anim.start(); 768 } else { 769 cl.setX((int)newX); 770 cl.setY((int)newY); 771 cl.setScaleX(SHRINK_FACTOR * rotationScaleX); 772 cl.setScaleY(SHRINK_FACTOR * rotationScaleY); 773 cl.setBackgroundAlpha(1.0f); 774 cl.setAlpha(finalAlpha); 775 cl.setRotationY(rotation); 776 } 777 // increment newX for the next screen 778 newX += scaledPageWidth + extraScaledSpacing; 779 } 780 setChildrenDrawnWithCacheEnabled(true); 781 } 782 783 784 private void updateWhichPagesAcceptDrops(ShrinkPosition state) { 785 updateWhichPagesAcceptDropsHelper(state, false, 1, 1); 786 } 787 788 789 private void updateWhichPagesAcceptDropsDuringDrag(ShrinkPosition state, int spanX, int spanY) { 790 updateWhichPagesAcceptDropsHelper(state, true, spanX, spanY); 791 } 792 793 private void updateWhichPagesAcceptDropsHelper( 794 ShrinkPosition state, boolean isDragHappening, int spanX, int spanY) { 795 final int screenCount = getChildCount(); 796 for (int i = 0; i < screenCount; i++) { 797 CellLayout cl = (CellLayout) getChildAt(i); 798 799 switch (state) { 800 case SHRINK_TO_TOP: 801 if (!isDragHappening) { 802 boolean showDropHighlight = i == mCurrentPage; 803 cl.setAcceptsDrops(showDropHighlight); 804 break; 805 } 806 // otherwise, fall through below and mark non-full screens as accepting drops 807 case SHRINK_TO_BOTTOM_HIDDEN: 808 case SHRINK_TO_BOTTOM_VISIBLE: 809 if (!isDragHappening) { 810 // even if a drag isn't happening, we don't want to show a screen as 811 // accepting drops if it doesn't have at least one free cell 812 spanX = 1; 813 spanY = 1; 814 } 815 // the page accepts drops if we can find at least one empty spot 816 cl.setAcceptsDrops(cl.findCellForSpan(null, spanX, spanY)); 817 break; 818 default: 819 throw new RuntimeException( 820 "updateWhichPagesAcceptDropsHelper passed an unhandled ShrinkPosition"); 821 } 822 } 823 } 824 825 /* 826 * 827 * We call these methods (onDragStartedWithItemSpans/onDragStartedWithItemMinSize) whenever we 828 * start a drag in Launcher, regardless of whether the drag has ever entered the Workspace 829 * 830 * These methods mark the appropriate pages as accepting drops (which alters their visual 831 * appearance) and, if the pages are hidden, makes them visible. 832 * 833 */ 834 public void onDragStartedWithItemSpans(int spanX, int spanY) { 835 updateWhichPagesAcceptDropsDuringDrag(mShrunkenState, spanX, spanY); 836 if (mShrunkenState == ShrinkPosition.SHRINK_TO_BOTTOM_HIDDEN) { 837 shrink(ShrinkPosition.SHRINK_TO_BOTTOM_VISIBLE, true); 838 } 839 } 840 841 public void onDragStartedWithItemMinSize(int minWidth, int minHeight) { 842 int[] spanXY = CellLayout.rectToCell(getResources(), minWidth, minHeight, null); 843 onDragStartedWithItemSpans(spanXY[0], spanXY[1]); 844 } 845 846 // we call this method whenever a drag and drop in Launcher finishes, even if Workspace was 847 // never dragged over 848 public void onDragStopped() { 849 updateWhichPagesAcceptDrops(mShrunkenState); 850 if (mShrunkenState == ShrinkPosition.SHRINK_TO_BOTTOM_VISIBLE) { 851 shrink(ShrinkPosition.SHRINK_TO_BOTTOM_HIDDEN, true); 852 } 853 } 854 855 // We call this when we trigger an unshrink by clicking on the CellLayout cl 856 public void unshrink(CellLayout clThatWasClicked) { 857 int newCurrentPage = mCurrentPage; 858 final int screenCount = getChildCount(); 859 for (int i = 0; i < screenCount; i++) { 860 if (getChildAt(i) == clThatWasClicked) { 861 newCurrentPage = i; 862 } 863 } 864 unshrink(newCurrentPage); 865 } 866 867 @Override 868 protected boolean handlePagingClicks() { 869 return true; 870 } 871 872 private void unshrink(int newCurrentPage) { 873 if (mIsSmall) { 874 int newX = getChildOffset(newCurrentPage) - getRelativeChildOffset(newCurrentPage); 875 int delta = newX - mScrollX; 876 877 final int screenCount = getChildCount(); 878 for (int i = 0; i < screenCount; i++) { 879 CellLayout cl = (CellLayout) getChildAt(i); 880 cl.setX(cl.getX() + delta); 881 } 882 setCurrentPage(newCurrentPage); 883 unshrink(); 884 } 885 } 886 887 void unshrink() { 888 unshrink(true); 889 } 890 891 void unshrink(boolean animated) { 892 if (mIsSmall) { 893 mIsSmall = false; 894 AnimatorSet s = new AnimatorSet(); 895 final int screenCount = getChildCount(); 896 897 final int duration = getResources().getInteger(R.integer.config_workspaceUnshrinkTime); 898 for (int i = 0; i < screenCount; i++) { 899 final CellLayout cl = (CellLayout)getChildAt(i); 900 float finalAlphaValue = (i == mCurrentPage) ? 1.0f : 0.0f; 901 float rotation = 0.0f; 902 903 if (i < mCurrentPage) { 904 rotation = WORKSPACE_ROTATION; 905 } else if (i > mCurrentPage) { 906 rotation = -WORKSPACE_ROTATION; 907 } 908 909 if (animated) { 910 911 s.playTogether( 912 ObjectAnimator.ofFloat(cl, "translationX", 0.0f).setDuration(duration), 913 ObjectAnimator.ofFloat(cl, "translationY", 0.0f).setDuration(duration), 914 ObjectAnimator.ofFloat(cl, "scaleX", 1.0f).setDuration(duration), 915 ObjectAnimator.ofFloat(cl, "scaleY", 1.0f).setDuration(duration), 916 ObjectAnimator.ofFloat(cl, "backgroundAlpha", 0.0f).setDuration(duration), 917 ObjectAnimator.ofFloat(cl, "alpha", finalAlphaValue).setDuration(duration), 918 ObjectAnimator.ofFloat(cl, "rotationY", rotation).setDuration(duration)); 919 } else { 920 cl.setTranslationX(0.0f); 921 cl.setTranslationY(0.0f); 922 cl.setScaleX(1.0f); 923 cl.setScaleY(1.0f); 924 cl.setBackgroundAlpha(0.0f); 925 cl.setAlpha(finalAlphaValue); 926 cl.setRotationY(rotation); 927 } 928 } 929 if (animated) { 930 // If we call this when we're not animated, onAnimationEnd is never called on 931 // the listener; make sure we only use the listener when we're actually animating 932 s.addListener(mUnshrinkAnimationListener); 933 s.start(); 934 } 935 } 936 } 937 938 /** 939 * Draw the View v into the given Canvas. 940 * 941 * @param v the view to draw 942 * @param destCanvas the canvas to draw on 943 * @param padding the horizontal and vertical padding to use when drawing 944 */ 945 private void drawDragView(View v, Canvas destCanvas, int padding) { 946 final Rect clipRect = mTempRect; 947 v.getDrawingRect(clipRect); 948 949 // For a TextView, adjust the clip rect so that we don't include the text label 950 if (v instanceof TextView) { 951 final int iconHeight = ((TextView)v).getCompoundPaddingTop() - v.getPaddingTop(); 952 clipRect.bottom = clipRect.top + iconHeight; 953 } 954 955 // Draw the View into the bitmap. 956 // The translate of scrollX and scrollY is necessary when drawing TextViews, because 957 // they set scrollX and scrollY to large values to achieve centered text 958 959 destCanvas.save(); 960 destCanvas.translate(-v.getScrollX() + padding / 2, -v.getScrollY() + padding / 2); 961 destCanvas.clipRect(clipRect, Op.REPLACE); 962 v.draw(destCanvas); 963 destCanvas.restore(); 964 } 965 966 /** 967 * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location. 968 * Responsibility for the bitmap is transferred to the caller. 969 */ 970 private Bitmap createDragOutline(View v, Canvas canvas, int padding) { 971 final int outlineColor = getResources().getColor(R.color.drag_outline_color); 972 final Bitmap b = Bitmap.createBitmap( 973 v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888); 974 975 canvas.setBitmap(b); 976 drawDragView(v, canvas, padding); 977 mOutlineHelper.applyExpensiveOuterOutline(b, canvas, outlineColor, true); 978 979 return b; 980 } 981 982 /** 983 * Returns a new bitmap to show when the given View is being dragged around. 984 * Responsibility for the bitmap is transferred to the caller. 985 */ 986 private Bitmap createDragBitmap(View v, Canvas canvas, int padding) { 987 final int outlineColor = getResources().getColor(R.color.drag_outline_color); 988 final Bitmap b = Bitmap.createBitmap( 989 mDragOutline.getWidth(), mDragOutline.getHeight(), Bitmap.Config.ARGB_8888); 990 991 canvas.setBitmap(b); 992 canvas.drawBitmap(mDragOutline, 0, 0, null); 993 drawDragView(v, canvas, padding); 994 mOutlineHelper.applyOuterBlur(b, canvas, outlineColor); 995 996 return b; 997 } 998 999 void startDrag(CellLayout.CellInfo cellInfo) { 1000 View child = cellInfo.cell; 1001 1002 // Make sure the drag was started by a long press as opposed to a long click. 1003 if (!child.isInTouchMode()) { 1004 return; 1005 } 1006 1007 mDragInfo = cellInfo; 1008 mDragInfo.screen = mCurrentPage; 1009 1010 CellLayout current = getCurrentDropLayout(); 1011 1012 current.onDragChild(child); 1013 1014 child.clearFocus(); 1015 child.setPressed(false); 1016 1017 final Canvas canvas = new Canvas(); 1018 1019 // We need to add extra padding to the bitmap to make room for the glow effect 1020 final int bitmapPadding = HolographicOutlineHelper.OUTER_BLUR_RADIUS; 1021 1022 // The outline is used to visualize where the item will land if dropped 1023 mDragOutline = createDragOutline(child, canvas, bitmapPadding); 1024 1025 // The drag bitmap follows the touch point around on the screen 1026 final Bitmap b = createDragBitmap(child, canvas, bitmapPadding); 1027 1028 final int bmpWidth = b.getWidth(); 1029 final int bmpHeight = b.getHeight(); 1030 child.getLocationOnScreen(mTempXY); 1031 final int screenX = (int) mTempXY[0] + (child.getWidth() - bmpWidth) / 2; 1032 final int screenY = (int) mTempXY[1] + (child.getHeight() - bmpHeight) / 2; 1033 mDragController.startDrag(b, screenX, screenY, 0, 0, bmpWidth, bmpHeight, this, 1034 child.getTag(), DragController.DRAG_ACTION_MOVE, null); 1035 b.recycle(); 1036 } 1037 1038 void addApplicationShortcut(ShortcutInfo info, int screen, int cellX, int cellY, 1039 boolean insertAtFirst, int intersectX, int intersectY) { 1040 final CellLayout cellLayout = (CellLayout) getChildAt(screen); 1041 View view = mLauncher.createShortcut(R.layout.application, cellLayout, (ShortcutInfo) info); 1042 1043 final int[] cellXY = new int[2]; 1044 cellLayout.findCellForSpanThatIntersects(cellXY, 1, 1, intersectX, intersectY); 1045 addInScreen(view, screen, cellXY[0], cellXY[1], 1, 1, insertAtFirst); 1046 LauncherModel.addOrMoveItemInDatabase(mLauncher, info, 1047 LauncherSettings.Favorites.CONTAINER_DESKTOP, screen, 1048 cellXY[0], cellXY[1]); 1049 } 1050 1051 private void setPositionForDropAnimation( 1052 View dragView, int dragViewX, int dragViewY, View parent, View child) { 1053 final CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); 1054 1055 // Based on the position of the drag view, find the top left of the original view 1056 int viewX = dragViewX + (dragView.getWidth() - child.getWidth()) / 2; 1057 int viewY = dragViewY + (dragView.getHeight() - child.getHeight()) / 2; 1058 viewX -= getResources().getInteger(R.integer.config_dragViewOffsetX); 1059 viewY -= getResources().getInteger(R.integer.config_dragViewOffsetY); 1060 1061 // Set its old pos (in the new parent's coordinates); the CellLayout will 1062 // animate it from this position during the next layout pass 1063 lp.oldX = viewX - (parent.getLeft() - mScrollX); 1064 lp.oldY = viewY - (parent.getTop() - mScrollY); 1065 } 1066 1067 public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, 1068 DragView dragView, Object dragInfo) { 1069 1070 int originX = x - xOffset; 1071 int originY = y - yOffset; 1072 1073 if (mDragTargetLayout == null) { 1074 // Cancel the drag if we're not over a screen at time of drop 1075 if (mDragInfo != null) { 1076 // Set its position so the parent can animate it back 1077 final View parent = getChildAt(mDragInfo.screen); 1078 setPositionForDropAnimation(dragView, originX, originY, parent, mDragInfo.cell); 1079 } 1080 return; 1081 } 1082 1083 if (mIsSmall || mIsInUnshrinkAnimation) { 1084 // get originX and originY in the local coordinate system of the screen 1085 mTempOriginXY[0] = originX; 1086 mTempOriginXY[1] = originY; 1087 mapPointFromSelfToChild(mDragTargetLayout, mTempOriginXY); 1088 originX = (int)mTempOriginXY[0]; 1089 originY = (int)mTempOriginXY[1]; 1090 } 1091 1092 if (source != this) { 1093 onDropExternal(originX, originY, dragInfo, mDragTargetLayout); 1094 } else if (mDragInfo != null) { 1095 // Move internally 1096 final View cell = mDragInfo.cell; 1097 mTargetCell = findNearestVacantArea(originX, originY, 1098 mDragInfo.spanX, mDragInfo.spanY, cell, mDragTargetLayout, 1099 mTargetCell); 1100 1101 int screen = indexOfChild(mDragTargetLayout); 1102 if (screen != mDragInfo.screen) { 1103 final CellLayout originalCellLayout = (CellLayout) getChildAt(mDragInfo.screen); 1104 originalCellLayout.removeView(cell); 1105 addInScreen(cell, screen, mTargetCell[0], mTargetCell[1], 1106 mDragInfo.spanX, mDragInfo.spanY); 1107 } 1108 mDragTargetLayout.onDropChild(cell); 1109 1110 // update the item's position after drop 1111 final ItemInfo info = (ItemInfo) cell.getTag(); 1112 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams(); 1113 mDragTargetLayout.onMove(cell, mTargetCell[0], mTargetCell[1]); 1114 lp.cellX = mTargetCell[0]; 1115 lp.cellY = mTargetCell[1]; 1116 cell.setId(LauncherModel.getCellLayoutChildId(-1, mDragInfo.screen, 1117 mTargetCell[0], mTargetCell[1], mDragInfo.spanX, mDragInfo.spanY)); 1118 1119 LauncherModel.moveItemInDatabase(mLauncher, info, 1120 LauncherSettings.Favorites.CONTAINER_DESKTOP, screen, 1121 lp.cellX, lp.cellY); 1122 1123 // Prepare it to be animated into its new position 1124 // This must be called after the view has been re-parented 1125 setPositionForDropAnimation(dragView, originX, originY, mDragTargetLayout, cell); 1126 } 1127 } 1128 1129 public void onDragEnter(DragSource source, int x, int y, int xOffset, 1130 int yOffset, DragView dragView, Object dragInfo) { 1131 mDragTargetLayout = null; // Reset the drag state 1132 1133 if (!mIsSmall) { 1134 mDragTargetLayout = getCurrentDropLayout(); 1135 mDragTargetLayout.onDragEnter(dragView); 1136 showOutlines(); 1137 } 1138 } 1139 1140 public DropTarget getDropTargetDelegate(DragSource source, int x, int y, 1141 int xOffset, int yOffset, DragView dragView, Object dragInfo) { 1142 1143 if (mIsSmall || mIsInUnshrinkAnimation) { 1144 // If we're shrunken, don't let anyone drag on folders/etc that are on the mini-screens 1145 return null; 1146 } 1147 // We may need to delegate the drag to a child view. If a 1x1 item 1148 // would land in a cell occupied by a DragTarget (e.g. a Folder), 1149 // then drag events should be handled by that child. 1150 1151 ItemInfo item = (ItemInfo)dragInfo; 1152 CellLayout currentLayout = getCurrentDropLayout(); 1153 1154 int dragPointX, dragPointY; 1155 if (item.spanX == 1 && item.spanY == 1) { 1156 // For a 1x1, calculate the drop cell exactly as in onDragOver 1157 dragPointX = x - xOffset; 1158 dragPointY = y - yOffset; 1159 } else { 1160 // Otherwise, use the exact drag coordinates 1161 dragPointX = x; 1162 dragPointY = y; 1163 } 1164 dragPointX += mScrollX - currentLayout.getLeft(); 1165 dragPointY += mScrollY - currentLayout.getTop(); 1166 1167 // If we are dragging over a cell that contains a DropTarget that will 1168 // accept the drop, delegate to that DropTarget. 1169 final int[] cellXY = mTempCell; 1170 currentLayout.estimateDropCell(dragPointX, dragPointY, item.spanX, item.spanY, cellXY); 1171 View child = currentLayout.getChildAt(cellXY[0], cellXY[1]); 1172 if (child instanceof DropTarget) { 1173 DropTarget target = (DropTarget)child; 1174 if (target.acceptDrop(source, x, y, xOffset, yOffset, dragView, dragInfo)) { 1175 return target; 1176 } 1177 } 1178 return null; 1179 } 1180 1181 /* 1182 * 1183 * Convert the 2D coordinate xy from the parent View's coordinate space to this CellLayout's 1184 * coordinate space. The argument xy is modified with the return result. 1185 * 1186 */ 1187 void mapPointFromSelfToChild(View v, float[] xy) { 1188 mapPointFromSelfToChild(v, xy, null); 1189 } 1190 1191 /* 1192 * 1193 * Convert the 2D coordinate xy from the parent View's coordinate space to this CellLayout's 1194 * coordinate space. The argument xy is modified with the return result. 1195 * 1196 * if cachedInverseMatrix is not null, this method will just use that matrix instead of 1197 * computing it itself; we use this to avoid redundant matrix inversions in 1198 * findMatchingPageForDragOver 1199 * 1200 */ 1201 void mapPointFromSelfToChild(View v, float[] xy, Matrix cachedInverseMatrix) { 1202 if (cachedInverseMatrix == null) { 1203 v.getMatrix().invert(mTempInverseMatrix); 1204 cachedInverseMatrix = mTempInverseMatrix; 1205 } 1206 xy[0] = xy[0] + mScrollX - v.getLeft(); 1207 xy[1] = xy[1] + mScrollY - v.getTop(); 1208 cachedInverseMatrix.mapPoints(xy); 1209 } 1210 1211 /* 1212 * 1213 * Convert the 2D coordinate xy from this CellLayout's coordinate space to 1214 * the parent View's coordinate space. The argument xy is modified with the return result. 1215 * 1216 */ 1217 void mapPointFromChildToSelf(View v, float[] xy) { 1218 v.getMatrix().mapPoints(xy); 1219 xy[0] -= (mScrollX - v.getLeft()); 1220 xy[1] -= (mScrollY - v.getTop()); 1221 } 1222 1223 static private float squaredDistance(float[] point1, float[] point2) { 1224 float distanceX = point1[0] - point2[0]; 1225 float distanceY = point2[1] - point2[1]; 1226 return distanceX * distanceX + distanceY * distanceY; 1227 } 1228 1229 /* 1230 * 1231 * Returns true if the passed CellLayout cl overlaps with dragView 1232 * 1233 */ 1234 boolean overlaps(CellLayout cl, DragView dragView, 1235 int dragViewX, int dragViewY, Matrix cachedInverseMatrix) { 1236 // Transform the coordinates of the item being dragged to the CellLayout's coordinates 1237 final float[] draggedItemTopLeft = mTempDragCoordinates; 1238 draggedItemTopLeft[0] = dragViewX + dragView.getScaledDragRegionXOffset(); 1239 draggedItemTopLeft[1] = dragViewY + dragView.getScaledDragRegionYOffset(); 1240 final float[] draggedItemBottomRight = mTempDragBottomRightCoordinates; 1241 draggedItemBottomRight[0] = draggedItemTopLeft[0] + dragView.getScaledDragRegionWidth(); 1242 draggedItemBottomRight[1] = draggedItemTopLeft[1] + dragView.getScaledDragRegionHeight(); 1243 1244 // Transform the dragged item's top left coordinates 1245 // to the CellLayout's local coordinates 1246 mapPointFromSelfToChild(cl, draggedItemTopLeft, cachedInverseMatrix); 1247 float overlapRegionLeft = Math.max(0f, draggedItemTopLeft[0]); 1248 float overlapRegionTop = Math.max(0f, draggedItemTopLeft[1]); 1249 1250 if (overlapRegionLeft <= cl.getWidth() && overlapRegionTop >= 0) { 1251 // Transform the dragged item's bottom right coordinates 1252 // to the CellLayout's local coordinates 1253 mapPointFromSelfToChild(cl, draggedItemBottomRight, cachedInverseMatrix); 1254 float overlapRegionRight = Math.min(cl.getWidth(), draggedItemBottomRight[0]); 1255 float overlapRegionBottom = Math.min(cl.getHeight(), draggedItemBottomRight[1]); 1256 1257 if (overlapRegionRight >= 0 && overlapRegionBottom <= cl.getHeight()) { 1258 float overlap = (overlapRegionRight - overlapRegionLeft) * 1259 (overlapRegionBottom - overlapRegionTop); 1260 if (overlap > 0) { 1261 return true; 1262 } 1263 } 1264 } 1265 return false; 1266 } 1267 1268 /* 1269 * 1270 * This method returns the CellLayout that is currently being dragged to. In order to drag 1271 * to a CellLayout, either the touch point must be directly over the CellLayout, or as a second 1272 * strategy, we see if the dragView is overlapping any CellLayout and choose the closest one 1273 * 1274 * Return null if no CellLayout is currently being dragged over 1275 * 1276 */ 1277 private CellLayout findMatchingPageForDragOver( 1278 DragView dragView, int originX, int originY, int offsetX, int offsetY) { 1279 // We loop through all the screens (ie CellLayouts) and see which ones overlap 1280 // with the item being dragged and then choose the one that's closest to the touch point 1281 final int screenCount = getChildCount(); 1282 CellLayout bestMatchingScreen = null; 1283 float smallestDistSoFar = Float.MAX_VALUE; 1284 1285 for (int i = 0; i < screenCount; i++) { 1286 CellLayout cl = (CellLayout)getChildAt(i); 1287 1288 final float[] touchXy = mTempTouchCoordinates; 1289 touchXy[0] = originX + offsetX; 1290 touchXy[1] = originY + offsetY; 1291 1292 // Transform the touch coordinates to the CellLayout's local coordinates 1293 // If the touch point is within the bounds of the cell layout, we can return immediately 1294 cl.getMatrix().invert(mTempInverseMatrix); 1295 mapPointFromSelfToChild(cl, touchXy, mTempInverseMatrix); 1296 1297 if (touchXy[0] >= 0 && touchXy[0] <= cl.getWidth() && 1298 touchXy[1] >= 0 && touchXy[1] <= cl.getHeight()) { 1299 return cl; 1300 } 1301 1302 if (overlaps(cl, dragView, originX, originY, mTempInverseMatrix)) { 1303 // Get the center of the cell layout in screen coordinates 1304 final float[] cellLayoutCenter = mTempCellLayoutCenterCoordinates; 1305 cellLayoutCenter[0] = cl.getWidth()/2; 1306 cellLayoutCenter[1] = cl.getHeight()/2; 1307 mapPointFromChildToSelf(cl, cellLayoutCenter); 1308 1309 touchXy[0] = originX + offsetX; 1310 touchXy[1] = originY + offsetY; 1311 1312 // Calculate the distance between the center of the CellLayout 1313 // and the touch point 1314 float dist = squaredDistance(touchXy, cellLayoutCenter); 1315 1316 if (dist < smallestDistSoFar) { 1317 smallestDistSoFar = dist; 1318 bestMatchingScreen = cl; 1319 } 1320 } 1321 } 1322 return bestMatchingScreen; 1323 } 1324 1325 public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset, 1326 DragView dragView, Object dragInfo) { 1327 // When touch is inside the scroll area, skip dragOver actions for the current screen 1328 if (!mInScrollArea) { 1329 CellLayout layout; 1330 int originX = x - xOffset; 1331 int originY = y - yOffset; 1332 if (mIsSmall || mIsInUnshrinkAnimation) { 1333 layout = findMatchingPageForDragOver( 1334 dragView, originX, originY, xOffset, yOffset); 1335 1336 if (layout != mDragTargetLayout) { 1337 if (mDragTargetLayout != null) { 1338 mDragTargetLayout.setHover(false); 1339 } 1340 mDragTargetLayout = layout; 1341 if (mDragTargetLayout != null) { 1342 mDragTargetLayout.setHover(true); 1343 } 1344 } 1345 } else { 1346 layout = getCurrentDropLayout(); 1347 1348 final ItemInfo item = (ItemInfo)dragInfo; 1349 if (dragInfo instanceof LauncherAppWidgetInfo) { 1350 LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo)dragInfo; 1351 1352 if (widgetInfo.spanX == -1) { 1353 // Calculate the grid spans needed to fit this widget 1354 int[] spans = layout.rectToCell( 1355 widgetInfo.minWidth, widgetInfo.minHeight, null); 1356 item.spanX = spans[0]; 1357 item.spanY = spans[1]; 1358 } 1359 } 1360 1361 if (source instanceof AllAppsPagedView) { 1362 // This is a hack to fix the point used to determine which cell an icon from 1363 // the all apps screen is over 1364 if (item != null && item.spanX == 1 && layout != null) { 1365 int dragRegionLeft = (dragView.getWidth() - layout.getCellWidth()) / 2; 1366 1367 originX += dragRegionLeft - dragView.getDragRegionLeft(); 1368 if (dragView.getDragRegionWidth() != layout.getCellWidth()) { 1369 dragView.setDragRegion(dragView.getDragRegionLeft(), 1370 dragView.getDragRegionTop(), 1371 layout.getCellWidth(), 1372 dragView.getDragRegionHeight()); 1373 } 1374 } 1375 } 1376 1377 if (layout != mDragTargetLayout) { 1378 if (mDragTargetLayout != null) { 1379 mDragTargetLayout.onDragExit(); 1380 } 1381 layout.onDragEnter(dragView); 1382 mDragTargetLayout = layout; 1383 } 1384 1385 // only visualize the drop locations for moving icons within the home screen on 1386 // tablet on phone, we also visualize icons dragged in from All Apps 1387 if ((!LauncherApplication.isScreenXLarge() || source == this) 1388 && mDragTargetLayout != null) { 1389 final View child = (mDragInfo == null) ? null : mDragInfo.cell; 1390 int localOriginX = originX - (mDragTargetLayout.getLeft() - mScrollX); 1391 int localOriginY = originY - (mDragTargetLayout.getTop() - mScrollY); 1392 mDragTargetLayout.visualizeDropLocation(child, mDragOutline, 1393 localOriginX, localOriginY, item.spanX, item.spanY); 1394 } 1395 } 1396 } 1397 } 1398 1399 public void onDragExit(DragSource source, int x, int y, int xOffset, 1400 int yOffset, DragView dragView, Object dragInfo) { 1401 if (mDragTargetLayout != null) { 1402 mDragTargetLayout.onDragExit(); 1403 } 1404 if (!mIsPageMoving) { 1405 hideOutlines(); 1406 } 1407 clearAllHovers(); 1408 } 1409 1410 private void onDropExternal(int x, int y, Object dragInfo, 1411 CellLayout cellLayout) { 1412 onDropExternal(x, y, dragInfo, cellLayout, false); 1413 } 1414 1415 /** 1416 * Add the item specified by dragInfo to the given layout. 1417 * This is basically the equivalent of onDropExternal, except it's not initiated 1418 * by drag and drop. 1419 * @return true if successful 1420 */ 1421 public boolean addExternalItemToScreen(Object dragInfo, View layout) { 1422 CellLayout cl = (CellLayout) layout; 1423 ItemInfo info = (ItemInfo) dragInfo; 1424 1425 if (cl.findCellForSpan(mTempEstimate, info.spanX, info.spanY)) { 1426 onDropExternal(0, 0, dragInfo, cl, false); 1427 return true; 1428 } 1429 mLauncher.showOutOfSpaceMessage(); 1430 return false; 1431 } 1432 1433 // Drag from somewhere else 1434 // NOTE: This can also be called when we are outside of a drag event, when we want 1435 // to add an item to one of the workspace screens. 1436 private void onDropExternal(int x, int y, Object dragInfo, 1437 CellLayout cellLayout, boolean insertAtFirst) { 1438 int screen = indexOfChild(cellLayout); 1439 if (dragInfo instanceof PendingAddItemInfo) { 1440 PendingAddItemInfo info = (PendingAddItemInfo) dragInfo; 1441 // When dragging and dropping from customization tray, we deal with creating 1442 // widgets/shortcuts/folders in a slightly different way 1443 int[] touchXY = new int[2]; 1444 touchXY[0] = x; 1445 touchXY[1] = y; 1446 switch (info.itemType) { 1447 case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: 1448 mLauncher.addAppWidgetFromDrop(info.componentName, screen, touchXY); 1449 break; 1450 case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER: 1451 mLauncher.addLiveFolderFromDrop(info.componentName, screen, touchXY); 1452 break; 1453 case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: 1454 mLauncher.processShortcutFromDrop(info.componentName, screen, touchXY); 1455 break; 1456 default: 1457 throw new IllegalStateException("Unknown item type: " + info.itemType); 1458 } 1459 cellLayout.onDragExit(); 1460 cellLayout.animateDrop(); 1461 return; 1462 } 1463 1464 // This is for other drag/drop cases, like dragging from All Apps 1465 ItemInfo info = (ItemInfo) dragInfo; 1466 1467 View view = null; 1468 1469 switch (info.itemType) { 1470 case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: 1471 case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: 1472 if (info.container == NO_ID && info instanceof ApplicationInfo) { 1473 // Came from all apps -- make a copy 1474 info = new ShortcutInfo((ApplicationInfo) info); 1475 } 1476 view = mLauncher.createShortcut(R.layout.application, cellLayout, 1477 (ShortcutInfo) info); 1478 break; 1479 case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER: 1480 view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher, 1481 cellLayout, ((UserFolderInfo) info)); 1482 break; 1483 default: 1484 throw new IllegalStateException("Unknown item type: " + info.itemType); 1485 } 1486 1487 // If the view is null, it has already been added. 1488 if (view == null) { 1489 cellLayout.onDragExit(); 1490 } else { 1491 mTargetCell = findNearestVacantArea(x, y, 1, 1, null, cellLayout, mTargetCell); 1492 addInScreen(view, indexOfChild(cellLayout), mTargetCell[0], 1493 mTargetCell[1], info.spanX, info.spanY, insertAtFirst); 1494 cellLayout.onDropChild(view); 1495 cellLayout.animateDrop(); 1496 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams(); 1497 1498 LauncherModel.addOrMoveItemInDatabase(mLauncher, info, 1499 LauncherSettings.Favorites.CONTAINER_DESKTOP, screen, 1500 lp.cellX, lp.cellY); 1501 } 1502 } 1503 1504 /** 1505 * Return the current {@link CellLayout}, correctly picking the destination 1506 * screen while a scroll is in progress. 1507 */ 1508 private CellLayout getCurrentDropLayout() { 1509 // if we're currently small, use findMatchingPageForDragOver instead 1510 if (mIsSmall) return null; 1511 int index = mScroller.isFinished() ? mCurrentPage : mNextPage; 1512 return (CellLayout) getChildAt(index); 1513 } 1514 1515 /** 1516 * Return the current CellInfo describing our current drag; this method exists 1517 * so that Launcher can sync this object with the correct info when the activity is created/ 1518 * destroyed 1519 * 1520 */ 1521 public CellLayout.CellInfo getDragInfo() { 1522 return mDragInfo; 1523 } 1524 1525 /** 1526 * {@inheritDoc} 1527 */ 1528 public boolean acceptDrop(DragSource source, int x, int y, 1529 int xOffset, int yOffset, DragView dragView, Object dragInfo) { 1530 if (mDragTargetLayout == null) { 1531 // cancel the drag if we're not over a screen at time of drop 1532 return false; 1533 } 1534 1535 final CellLayout.CellInfo dragCellInfo = mDragInfo; 1536 final int spanX = dragCellInfo == null ? 1 : dragCellInfo.spanX; 1537 final int spanY = dragCellInfo == null ? 1 : dragCellInfo.spanY; 1538 1539 final View ignoreView = dragCellInfo == null ? null : dragCellInfo.cell; 1540 1541 if (mDragTargetLayout.findCellForSpanIgnoring(null, spanX, spanY, ignoreView)) { 1542 return true; 1543 } else { 1544 mLauncher.showOutOfSpaceMessage(); 1545 return false; 1546 } 1547 } 1548 1549 /** 1550 * Calculate the nearest cell where the given object would be dropped. 1551 */ 1552 private int[] findNearestVacantArea(int pixelX, int pixelY, 1553 int spanX, int spanY, View ignoreView, CellLayout layout, int[] recycle) { 1554 1555 int localPixelX = pixelX - (layout.getLeft() - mScrollX); 1556 int localPixelY = pixelY - (layout.getTop() - mScrollY); 1557 1558 // Find the best target drop location 1559 return layout.findNearestVacantArea( 1560 localPixelX, localPixelY, spanX, spanY, ignoreView, recycle); 1561 } 1562 1563 /** 1564 * Estimate the size that a child with the given dimensions will take in the current screen. 1565 */ 1566 void estimateChildSize(int minWidth, int minHeight, int[] result) { 1567 ((CellLayout)getChildAt(mCurrentPage)).estimateChildSize(minWidth, minHeight, result); 1568 } 1569 1570 void setLauncher(Launcher launcher) { 1571 mLauncher = launcher; 1572 } 1573 1574 public void setDragController(DragController dragController) { 1575 mDragController = dragController; 1576 } 1577 1578 public void onDropCompleted(View target, boolean success) { 1579 if (success) { 1580 if (target != this && mDragInfo != null) { 1581 final CellLayout cellLayout = (CellLayout) getChildAt(mDragInfo.screen); 1582 cellLayout.removeView(mDragInfo.cell); 1583 if (mDragInfo.cell instanceof DropTarget) { 1584 mDragController.removeDropTarget((DropTarget)mDragInfo.cell); 1585 } 1586 // final Object tag = mDragInfo.cell.getTag(); 1587 } 1588 } else if (mDragInfo != null) { 1589 ((CellLayout) getChildAt(mDragInfo.screen)).onDropAborted(mDragInfo.cell); 1590 } 1591 1592 mDragOutline = null; 1593 mDragInfo = null; 1594 } 1595 1596 public boolean isDropEnabled() { 1597 return true; 1598 } 1599 1600 @Override 1601 protected void onRestoreInstanceState(Parcelable state) { 1602 super.onRestoreInstanceState(state); 1603 Launcher.setScreen(mCurrentPage); 1604 } 1605 1606 @Override 1607 public void scrollLeft() { 1608 if (!mIsSmall && !mIsInUnshrinkAnimation) { 1609 super.scrollLeft(); 1610 } 1611 } 1612 1613 @Override 1614 public void scrollRight() { 1615 if (!mIsSmall && !mIsInUnshrinkAnimation) { 1616 super.scrollRight(); 1617 } 1618 } 1619 1620 @Override 1621 public void onEnterScrollArea(int direction) { 1622 if (!mIsSmall && !mIsInUnshrinkAnimation) { 1623 mInScrollArea = true; 1624 final int screen = getCurrentPage() + ((direction == DragController.SCROLL_LEFT) ? -1 : 1); 1625 if (0 <= screen && screen < getChildCount()) { 1626 ((CellLayout) getChildAt(screen)).setHover(true); 1627 } 1628 1629 if (mDragTargetLayout != null) { 1630 mDragTargetLayout.onDragExit(); 1631 mDragTargetLayout = null; 1632 } 1633 } 1634 } 1635 1636 private void clearAllHovers() { 1637 final int childCount = getChildCount(); 1638 for (int i = 0; i < childCount; i++) { 1639 ((CellLayout) getChildAt(i)).setHover(false); 1640 } 1641 } 1642 1643 @Override 1644 public void onExitScrollArea() { 1645 if (mInScrollArea) { 1646 mInScrollArea = false; 1647 clearAllHovers(); 1648 } 1649 } 1650 1651 public Folder getFolderForTag(Object tag) { 1652 final int screenCount = getChildCount(); 1653 for (int screen = 0; screen < screenCount; screen++) { 1654 CellLayout currentScreen = ((CellLayout) getChildAt(screen)); 1655 int count = currentScreen.getChildCount(); 1656 for (int i = 0; i < count; i++) { 1657 View child = currentScreen.getChildAt(i); 1658 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); 1659 if (lp.cellHSpan == 4 && lp.cellVSpan == 4 && child instanceof Folder) { 1660 Folder f = (Folder) child; 1661 if (f.getInfo() == tag && f.getInfo().opened) { 1662 return f; 1663 } 1664 } 1665 } 1666 } 1667 return null; 1668 } 1669 1670 public View getViewForTag(Object tag) { 1671 int screenCount = getChildCount(); 1672 for (int screen = 0; screen < screenCount; screen++) { 1673 CellLayout currentScreen = ((CellLayout) getChildAt(screen)); 1674 int count = currentScreen.getChildCount(); 1675 for (int i = 0; i < count; i++) { 1676 View child = currentScreen.getChildAt(i); 1677 if (child.getTag() == tag) { 1678 return child; 1679 } 1680 } 1681 } 1682 return null; 1683 } 1684 1685 1686 void removeItems(final ArrayList<ApplicationInfo> apps) { 1687 final int screenCount = getChildCount(); 1688 final PackageManager manager = getContext().getPackageManager(); 1689 final AppWidgetManager widgets = AppWidgetManager.getInstance(getContext()); 1690 1691 final HashSet<String> packageNames = new HashSet<String>(); 1692 final int appCount = apps.size(); 1693 for (int i = 0; i < appCount; i++) { 1694 packageNames.add(apps.get(i).componentName.getPackageName()); 1695 } 1696 1697 for (int i = 0; i < screenCount; i++) { 1698 final CellLayout layout = (CellLayout) getChildAt(i); 1699 1700 // Avoid ANRs by treating each screen separately 1701 post(new Runnable() { 1702 public void run() { 1703 final ArrayList<View> childrenToRemove = new ArrayList<View>(); 1704 childrenToRemove.clear(); 1705 1706 int childCount = layout.getChildCount(); 1707 for (int j = 0; j < childCount; j++) { 1708 final View view = layout.getChildAt(j); 1709 Object tag = view.getTag(); 1710 1711 if (tag instanceof ShortcutInfo) { 1712 final ShortcutInfo info = (ShortcutInfo) tag; 1713 final Intent intent = info.intent; 1714 final ComponentName name = intent.getComponent(); 1715 1716 if (Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) { 1717 for (String packageName: packageNames) { 1718 if (packageName.equals(name.getPackageName())) { 1719 LauncherModel.deleteItemFromDatabase(mLauncher, info); 1720 childrenToRemove.add(view); 1721 } 1722 } 1723 } 1724 } else if (tag instanceof UserFolderInfo) { 1725 final UserFolderInfo info = (UserFolderInfo) tag; 1726 final ArrayList<ShortcutInfo> contents = info.contents; 1727 final ArrayList<ShortcutInfo> toRemove = new ArrayList<ShortcutInfo>(1); 1728 final int contentsCount = contents.size(); 1729 boolean removedFromFolder = false; 1730 1731 for (int k = 0; k < contentsCount; k++) { 1732 final ShortcutInfo appInfo = contents.get(k); 1733 final Intent intent = appInfo.intent; 1734 final ComponentName name = intent.getComponent(); 1735 1736 if (Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) { 1737 for (String packageName: packageNames) { 1738 if (packageName.equals(name.getPackageName())) { 1739 toRemove.add(appInfo); 1740 LauncherModel.deleteItemFromDatabase(mLauncher, appInfo); 1741 removedFromFolder = true; 1742 } 1743 } 1744 } 1745 } 1746 1747 contents.removeAll(toRemove); 1748 if (removedFromFolder) { 1749 final Folder folder = getOpenFolder(); 1750 if (folder != null) 1751 folder.notifyDataSetChanged(); 1752 } 1753 } else if (tag instanceof LiveFolderInfo) { 1754 final LiveFolderInfo info = (LiveFolderInfo) tag; 1755 final Uri uri = info.uri; 1756 final ProviderInfo providerInfo = manager.resolveContentProvider( 1757 uri.getAuthority(), 0); 1758 1759 if (providerInfo != null) { 1760 for (String packageName: packageNames) { 1761 if (packageName.equals(providerInfo.packageName)) { 1762 LauncherModel.deleteItemFromDatabase(mLauncher, info); 1763 childrenToRemove.add(view); 1764 } 1765 } 1766 } 1767 } else if (tag instanceof LauncherAppWidgetInfo) { 1768 final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) tag; 1769 final AppWidgetProviderInfo provider = 1770 widgets.getAppWidgetInfo(info.appWidgetId); 1771 if (provider != null) { 1772 for (String packageName: packageNames) { 1773 if (packageName.equals(provider.provider.getPackageName())) { 1774 LauncherModel.deleteItemFromDatabase(mLauncher, info); 1775 childrenToRemove.add(view); 1776 } 1777 } 1778 } 1779 } 1780 } 1781 1782 childCount = childrenToRemove.size(); 1783 for (int j = 0; j < childCount; j++) { 1784 View child = childrenToRemove.get(j); 1785 layout.removeViewInLayout(child); 1786 if (child instanceof DropTarget) { 1787 mDragController.removeDropTarget((DropTarget)child); 1788 } 1789 } 1790 1791 if (childCount > 0) { 1792 layout.requestLayout(); 1793 layout.invalidate(); 1794 } 1795 } 1796 }); 1797 } 1798 } 1799 1800 void updateShortcuts(ArrayList<ApplicationInfo> apps) { 1801 final int screenCount = getChildCount(); 1802 for (int i = 0; i < screenCount; i++) { 1803 final CellLayout layout = (CellLayout) getChildAt(i); 1804 int childCount = layout.getChildCount(); 1805 for (int j = 0; j < childCount; j++) { 1806 final View view = layout.getChildAt(j); 1807 Object tag = view.getTag(); 1808 if (tag instanceof ShortcutInfo) { 1809 ShortcutInfo info = (ShortcutInfo)tag; 1810 // We need to check for ACTION_MAIN otherwise getComponent() might 1811 // return null for some shortcuts (for instance, for shortcuts to 1812 // web pages.) 1813 final Intent intent = info.intent; 1814 final ComponentName name = intent.getComponent(); 1815 if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION && 1816 Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) { 1817 final int appCount = apps.size(); 1818 for (int k = 0; k < appCount; k++) { 1819 ApplicationInfo app = apps.get(k); 1820 if (app.componentName.equals(name)) { 1821 info.setIcon(mIconCache.getIcon(info.intent)); 1822 ((TextView)view).setCompoundDrawablesWithIntrinsicBounds(null, 1823 new FastBitmapDrawable(info.getIcon(mIconCache)), 1824 null, null); 1825 } 1826 } 1827 } 1828 } 1829 } 1830 } 1831 } 1832 1833 void moveToDefaultScreen(boolean animate) { 1834 if (mIsSmall || mIsInUnshrinkAnimation) { 1835 mLauncher.showWorkspace(animate, (CellLayout)getChildAt(mDefaultPage)); 1836 } else if (animate) { 1837 snapToPage(mDefaultPage); 1838 } else { 1839 setCurrentPage(mDefaultPage); 1840 } 1841 getChildAt(mDefaultPage).requestFocus(); 1842 } 1843 1844 void setIndicators(Drawable previous, Drawable next) { 1845 mPreviousIndicator = previous; 1846 mNextIndicator = next; 1847 previous.setLevel(mCurrentPage); 1848 next.setLevel(mCurrentPage); 1849 } 1850 1851 @Override 1852 public void syncPages() { 1853 } 1854 1855 @Override 1856 public void syncPageItems(int page) { 1857 } 1858 1859} 1860