AllAppsView.java revision 4700fed72b619a09a0d9cac93e86625b95c730dc
1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.launcher2; 18 19import android.content.ComponentName; 20import android.content.Context; 21import android.content.res.Resources; 22import android.graphics.Bitmap; 23import android.graphics.Canvas; 24import android.graphics.PixelFormat; 25import android.graphics.Rect; 26import android.os.SystemClock; 27import android.renderscript.Allocation; 28import android.renderscript.Dimension; 29import android.renderscript.Element; 30import android.renderscript.ProgramFragment; 31import android.renderscript.ProgramStore; 32import android.renderscript.ProgramVertex; 33import android.renderscript.RSSurfaceView; 34import android.renderscript.RenderScript; 35import android.renderscript.Sampler; 36import android.renderscript.Script; 37import android.renderscript.ScriptC; 38import android.renderscript.SimpleMesh; 39import android.renderscript.Type; 40import android.util.AttributeSet; 41import android.util.Log; 42import android.view.KeyEvent; 43import android.view.MotionEvent; 44import android.view.SoundEffectConstants; 45import android.view.SurfaceHolder; 46import android.view.VelocityTracker; 47import android.view.View; 48import android.view.ViewConfiguration; 49import android.view.accessibility.AccessibilityEvent; 50 51import java.util.ArrayList; 52import java.util.Arrays; 53import java.util.Collections; 54import java.util.Comparator; 55 56 57public class AllAppsView extends RSSurfaceView 58 implements View.OnClickListener, View.OnLongClickListener, DragSource { 59 private static final String TAG = "Launcher.AllAppsView"; 60 61 /** Bit for mLocks for when there are icons being loaded. */ 62 private static final int LOCK_ICONS_PENDING = 1; 63 64 private static final int TRACKING_NONE = 0; 65 private static final int TRACKING_FLING = 1; 66 private static final int TRACKING_HOME = 2; 67 68 private static final int SELECTED_NONE = 0; 69 private static final int SELECTED_FOCUSED = 1; 70 private static final int SELECTED_PRESSED = 2; 71 72 private static final int SELECTION_NONE = 0; 73 private static final int SELECTION_ICONS = 1; 74 private static final int SELECTION_HOME = 2; 75 76 private Launcher mLauncher; 77 private DragController mDragController; 78 79 /** When this is 0, modifications are allowed, when it's not, they're not. 80 * TODO: What about scrolling? */ 81 private int mLocks = LOCK_ICONS_PENDING; 82 83 private int mSlop; 84 private int mMaxFlingVelocity; 85 86 private Defines mDefines = new Defines(); 87 private RenderScript mRS; 88 private RolloRS mRollo; 89 private ArrayList<ApplicationInfo> mAllAppsList; 90 91 /** 92 * True when we are using arrow keys or trackball to drive navigation 93 */ 94 private boolean mArrowNavigation = false; 95 private boolean mStartedScrolling; 96 97 /** 98 * Used to keep track of the selection when AllAppsView loses window focus. 99 * One of the SELECTION_ constants. 100 */ 101 private int mLastSelection; 102 103 /** 104 * Used to keep track of the selection when AllAppsView loses window focus 105 */ 106 private int mLastSelectedIcon; 107 108 private VelocityTracker mVelocityTracker; 109 private int mTouchTracking; 110 private int mMotionDownRawX; 111 private int mMotionDownRawY; 112 private int mDownIconIndex = -1; 113 private int mCurrentIconIndex = -1; 114 115 private boolean mShouldGainFocus; 116 117 private boolean mHaveSurface = false; 118 private boolean mZoomDirty = false; 119 private boolean mAnimateNextZoom; 120 private float mNextZoom; 121 private float mZoom; 122 private float mPosX; 123 private float mVelocity; 124 private AAMessage mMessageProc; 125 126 static class Defines { 127 public static final int ALLOC_PARAMS = 0; 128 public static final int ALLOC_STATE = 1; 129 public static final int ALLOC_ICON_IDS = 3; 130 public static final int ALLOC_LABEL_IDS = 4; 131 public static final int ALLOC_VP_CONSTANTS = 5; 132 133 public static final int COLUMNS_PER_PAGE = 4; 134 public static final int ROWS_PER_PAGE = 4; 135 136 public static final int ICON_WIDTH_PX = 64; 137 public static final int ICON_TEXTURE_WIDTH_PX = 74; 138 public static final int SELECTION_TEXTURE_WIDTH_PX = 74 + 20; 139 140 public static final int ICON_HEIGHT_PX = 64; 141 public static final int ICON_TEXTURE_HEIGHT_PX = 74; 142 public static final int SELECTION_TEXTURE_HEIGHT_PX = 74 + 20; 143 } 144 145 public AllAppsView(Context context, AttributeSet attrs) { 146 super(context, attrs); 147 setFocusable(true); 148 setSoundEffectsEnabled(false); 149 getHolder().setFormat(PixelFormat.TRANSLUCENT); 150 final ViewConfiguration config = ViewConfiguration.get(context); 151 mSlop = config.getScaledTouchSlop(); 152 mMaxFlingVelocity = config.getScaledMaximumFlingVelocity(); 153 154 setOnClickListener(this); 155 setOnLongClickListener(this); 156 setZOrderOnTop(true); 157 getHolder().setFormat(PixelFormat.TRANSLUCENT); 158 159 mRS = createRenderScript(true); 160 } 161 162 /** 163 * Note that this implementation prohibits this view from ever being reattached. 164 */ 165 @Override 166 protected void onDetachedFromWindow() { 167 destroyRenderScript(); 168 mRS.mMessageCallback = null; 169 mRS = null; 170 } 171 172 /** 173 * If you have an attached click listener, View always plays the click sound!?!? 174 * Deal with sound effects by hand. 175 */ 176 public void reallyPlaySoundEffect(int sound) { 177 boolean old = isSoundEffectsEnabled(); 178 setSoundEffectsEnabled(true); 179 playSoundEffect(sound); 180 setSoundEffectsEnabled(old); 181 } 182 183 public AllAppsView(Context context, AttributeSet attrs, int defStyle) { 184 this(context, attrs); 185 } 186 187 public void setLauncher(Launcher launcher) { 188 mLauncher = launcher; 189 } 190 191 @Override 192 public void surfaceDestroyed(SurfaceHolder holder) { 193 super.surfaceDestroyed(holder); 194 // Without this, we leak mMessageCallback which leaks the context. 195 mRS.mMessageCallback = null; 196 // We may lose any callbacks that are pending, so make sure that we re-sync that 197 // on the next surfaceChanged. 198 mZoomDirty = true; 199 mHaveSurface = false; 200 } 201 202 @Override 203 public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { 204 //long startTime = SystemClock.uptimeMillis(); 205 206 super.surfaceChanged(holder, format, w, h); 207 208 mHaveSurface = true; 209 210 if (mRollo == null) { 211 mRollo = new RolloRS(); 212 mRollo.init(getResources(), w, h); 213 if (mAllAppsList != null) { 214 mRollo.setApps(mAllAppsList); 215 } 216 if (mShouldGainFocus) { 217 gainFocus(); 218 mShouldGainFocus = false; 219 } 220 } 221 mRollo.dirtyCheck(); 222 mRollo.resize(w, h); 223 224 if (mRS != null) { 225 mRS.mMessageCallback = mMessageProc = new AAMessage(); 226 } 227 228 Resources res = getContext().getResources(); 229 int barHeight = (int)res.getDimension(R.dimen.button_bar_height); 230 231 232 if (mRollo.mUniformAlloc != null) { 233 float tf[] = new float[] {72.f, 72.f, 234 120.f, 120.f, 0.f, 0.f, 235 120.f, 680.f, 236 (2.f / 480.f), 0, -((float)w / 2) - 0.25f, -380.25f}; 237 if (w > h) { 238 tf[6] = 40.f; 239 tf[7] = h - 40.f; 240 tf[9] = 1.f; 241 tf[10] = -((float)w / 2) - 0.25f; 242 tf[11] = -((float)h / 2) - 0.25f; 243 } 244 245 mRollo.mUniformAlloc.data(tf); 246 } 247 248 //long endTime = SystemClock.uptimeMillis(); 249 //Log.d(TAG, "surfaceChanged took " + (endTime-startTime) + "ms"); 250 } 251 252 @Override 253 public void onWindowFocusChanged(boolean hasWindowFocus) { 254 super.onWindowFocusChanged(hasWindowFocus); 255 if (mArrowNavigation) { 256 if (!hasWindowFocus) { 257 // Clear selection when we lose window focus 258 mLastSelectedIcon = mRollo.mState.selectedIconIndex; 259 mRollo.setHomeSelected(SELECTED_NONE); 260 mRollo.clearSelectedIcon(); 261 mRollo.mState.save(); 262 } else if (hasWindowFocus) { 263 if (mRollo.mState.iconCount > 0) { 264 if (mLastSelection == SELECTION_ICONS) { 265 int selection = mLastSelectedIcon; 266 final int firstIcon = Math.round(mPosX) * 267 Defines.COLUMNS_PER_PAGE; 268 if (selection < 0 || // No selection 269 selection < firstIcon || // off the top of the screen 270 selection >= mRollo.mState.iconCount || // past last icon 271 selection >= firstIcon + // past last icon on screen 272 (Defines.COLUMNS_PER_PAGE * Defines.ROWS_PER_PAGE)) { 273 selection = firstIcon; 274 } 275 276 // Select the first icon when we gain window focus 277 mRollo.selectIcon(selection, SELECTED_FOCUSED); 278 mRollo.mState.save(); 279 } else if (mLastSelection == SELECTION_HOME) { 280 mRollo.setHomeSelected(SELECTED_FOCUSED); 281 mRollo.mState.save(); 282 } 283 } 284 } 285 } 286 } 287 288 @Override 289 protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) { 290 super.onFocusChanged(gainFocus, direction, previouslyFocusedRect); 291 292 if (!isVisible()) { 293 return; 294 } 295 296 if (gainFocus) { 297 if (mRollo != null) { 298 gainFocus(); 299 } else { 300 mShouldGainFocus = true; 301 } 302 } else { 303 if (mRollo != null) { 304 if (mArrowNavigation) { 305 // Clear selection when we lose focus 306 mRollo.clearSelectedIcon(); 307 mRollo.setHomeSelected(SELECTED_NONE); 308 mRollo.mState.save(); 309 mArrowNavigation = false; 310 } 311 } else { 312 mShouldGainFocus = false; 313 } 314 } 315 } 316 317 private void gainFocus() { 318 if (!mArrowNavigation && mRollo.mState.iconCount > 0) { 319 // Select the first icon when we gain keyboard focus 320 mArrowNavigation = true; 321 mRollo.selectIcon(Math.round(mPosX) * Defines.COLUMNS_PER_PAGE, 322 SELECTED_FOCUSED); 323 mRollo.mState.save(); 324 } 325 } 326 327 @Override 328 public boolean onKeyDown(int keyCode, KeyEvent event) { 329 330 boolean handled = false; 331 332 if (!isVisible()) { 333 return false; 334 } 335 final int iconCount = mRollo.mState.iconCount; 336 337 if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_ENTER) { 338 if (mArrowNavigation) { 339 if (mLastSelection == SELECTION_HOME) { 340 reallyPlaySoundEffect(SoundEffectConstants.CLICK); 341 mLauncher.closeAllApps(true); 342 } else { 343 int whichApp = mRollo.mState.selectedIconIndex; 344 if (whichApp >= 0) { 345 ApplicationInfo app = mAllAppsList.get(whichApp); 346 mLauncher.startActivitySafely(app.intent); 347 handled = true; 348 } 349 } 350 } 351 } 352 353 if (iconCount > 0) { 354 mArrowNavigation = true; 355 356 int currentSelection = mRollo.mState.selectedIconIndex; 357 int currentTopRow = Math.round(mPosX); 358 359 // The column of the current selection, in the range 0..COLUMNS_PER_PAGE-1 360 final int currentPageCol = currentSelection % Defines.COLUMNS_PER_PAGE; 361 362 // The row of the current selection, in the range 0..ROWS_PER_PAGE-1 363 final int currentPageRow = (currentSelection - (currentTopRow*Defines.COLUMNS_PER_PAGE)) 364 / Defines.ROWS_PER_PAGE; 365 366 int newSelection = currentSelection; 367 368 switch (keyCode) { 369 case KeyEvent.KEYCODE_DPAD_UP: 370 if (mLastSelection == SELECTION_HOME) { 371 mRollo.setHomeSelected(SELECTED_NONE); 372 int lastRowCount = iconCount % Defines.COLUMNS_PER_PAGE; 373 if (lastRowCount == 0) { 374 lastRowCount = Defines.COLUMNS_PER_PAGE; 375 } 376 newSelection = iconCount - lastRowCount + (Defines.COLUMNS_PER_PAGE / 2); 377 if (newSelection >= iconCount) { 378 newSelection = iconCount-1; 379 } 380 int target = (newSelection / Defines.COLUMNS_PER_PAGE) 381 - (Defines.ROWS_PER_PAGE - 1); 382 if (target < 0) { 383 target = 0; 384 } 385 if (currentTopRow != target) { 386 mRollo.moveTo(target); 387 } 388 } else { 389 if (currentPageRow > 0) { 390 newSelection = currentSelection - Defines.COLUMNS_PER_PAGE; 391 } else if (currentTopRow > 0) { 392 newSelection = currentSelection - Defines.COLUMNS_PER_PAGE; 393 mRollo.moveTo(newSelection / Defines.COLUMNS_PER_PAGE); 394 } else if (currentPageRow != 0) { 395 newSelection = currentTopRow * Defines.ROWS_PER_PAGE; 396 } 397 } 398 handled = true; 399 break; 400 401 case KeyEvent.KEYCODE_DPAD_DOWN: { 402 final int rowCount = iconCount / Defines.COLUMNS_PER_PAGE 403 + (iconCount % Defines.COLUMNS_PER_PAGE == 0 ? 0 : 1); 404 final int currentRow = currentSelection / Defines.COLUMNS_PER_PAGE; 405 if (mLastSelection != SELECTION_HOME) { 406 if (currentRow < rowCount-1) { 407 mRollo.setHomeSelected(SELECTED_NONE); 408 if (currentSelection < 0) { 409 newSelection = 0; 410 } else { 411 newSelection = currentSelection + Defines.COLUMNS_PER_PAGE; 412 } 413 if (newSelection >= iconCount) { 414 // Go from D to G in this arrangement: 415 // A B C D 416 // E F G 417 newSelection = iconCount - 1; 418 } 419 if (currentPageRow >= Defines.ROWS_PER_PAGE - 1) { 420 mRollo.moveTo((newSelection / Defines.COLUMNS_PER_PAGE) - 421 Defines.ROWS_PER_PAGE + 1); 422 } 423 } else { 424 newSelection = -1; 425 mRollo.setHomeSelected(SELECTED_FOCUSED); 426 } 427 } 428 handled = true; 429 break; 430 } 431 case KeyEvent.KEYCODE_DPAD_LEFT: 432 if (mLastSelection != SELECTION_HOME) { 433 if (currentPageCol > 0) { 434 newSelection = currentSelection - 1; 435 } 436 } 437 handled = true; 438 break; 439 case KeyEvent.KEYCODE_DPAD_RIGHT: 440 if (mLastSelection != SELECTION_HOME) { 441 if ((currentPageCol < Defines.COLUMNS_PER_PAGE - 1) && 442 (currentSelection < iconCount - 1)) { 443 newSelection = currentSelection + 1; 444 } 445 } 446 handled = true; 447 break; 448 } 449 if (newSelection != currentSelection) { 450 mRollo.selectIcon(newSelection, SELECTED_FOCUSED); 451 mRollo.mState.save(); 452 } 453 } 454 return handled; 455 } 456 457 @Override 458 public boolean onTouchEvent(MotionEvent ev) 459 { 460 mArrowNavigation = false; 461 462 if (!isVisible()) { 463 return true; 464 } 465 466 if (mLocks != 0) { 467 return true; 468 } 469 470 super.onTouchEvent(ev); 471 472 int x = (int)ev.getX(); 473 int y = (int)ev.getY(); 474 475 int action = ev.getAction(); 476 switch (action) { 477 case MotionEvent.ACTION_DOWN: 478 if (y > mRollo.mTouchYBorders[mRollo.mTouchYBorders.length-1]) { 479 mTouchTracking = TRACKING_HOME; 480 mRollo.setHomeSelected(SELECTED_PRESSED); 481 mRollo.mState.save(); 482 mCurrentIconIndex = -1; 483 } else { 484 mTouchTracking = TRACKING_FLING; 485 486 mMotionDownRawX = (int)ev.getRawX(); 487 mMotionDownRawY = (int)ev.getRawY(); 488 489 mRollo.mState.newPositionX = ev.getRawY() / getHeight(); 490 mRollo.mState.newTouchDown = 1; 491 492 if (!mRollo.checkClickOK()) { 493 mRollo.clearSelectedIcon(); 494 } else { 495 mDownIconIndex = mCurrentIconIndex 496 = mRollo.selectIcon(x, y, mPosX, SELECTED_PRESSED); 497 if (mDownIconIndex < 0) { 498 // if nothing was selected, no long press. 499 cancelLongPress(); 500 } 501 } 502 mRollo.mState.save(); 503 mRollo.move(); 504 mVelocityTracker = VelocityTracker.obtain(); 505 mVelocityTracker.addMovement(ev); 506 mStartedScrolling = false; 507 } 508 break; 509 case MotionEvent.ACTION_MOVE: 510 case MotionEvent.ACTION_OUTSIDE: 511 if (mTouchTracking == TRACKING_HOME) { 512 mRollo.setHomeSelected(y > mRollo.mTouchYBorders[mRollo.mTouchYBorders.length-1] 513 ? SELECTED_PRESSED : SELECTED_NONE); 514 mRollo.mState.save(); 515 } else if (mTouchTracking == TRACKING_FLING) { 516 int rawX = (int)ev.getRawX(); 517 int rawY = (int)ev.getRawY(); 518 int slop; 519 slop = Math.abs(rawY - mMotionDownRawY); 520 521 if (!mStartedScrolling && slop < mSlop) { 522 // don't update anything so when we do start scrolling 523 // below, we get the right delta. 524 mCurrentIconIndex = mRollo.chooseTappedIcon(x, y, mPosX); 525 if (mDownIconIndex != mCurrentIconIndex) { 526 // If a different icon is selected, don't allow it to be picked up. 527 // This handles off-axis dragging. 528 cancelLongPress(); 529 mCurrentIconIndex = -1; 530 } 531 } else { 532 if (!mStartedScrolling) { 533 cancelLongPress(); 534 mCurrentIconIndex = -1; 535 } 536 mRollo.mState.newPositionX = ev.getRawY() / getHeight(); 537 mRollo.mState.newTouchDown = 1; 538 mRollo.move(); 539 540 mStartedScrolling = true; 541 mRollo.clearSelectedIcon(); 542 mVelocityTracker.addMovement(ev); 543 mRollo.mState.save(); 544 } 545 } 546 break; 547 case MotionEvent.ACTION_UP: 548 case MotionEvent.ACTION_CANCEL: 549 if (mTouchTracking == TRACKING_HOME) { 550 if (action == MotionEvent.ACTION_UP) { 551 if (y > mRollo.mTouchYBorders[mRollo.mTouchYBorders.length-1]) { 552 reallyPlaySoundEffect(SoundEffectConstants.CLICK); 553 mLauncher.closeAllApps(true); 554 } 555 mRollo.setHomeSelected(SELECTED_NONE); 556 mRollo.mState.save(); 557 } 558 mCurrentIconIndex = -1; 559 } else if (mTouchTracking == TRACKING_FLING) { 560 mRollo.mState.newTouchDown = 0; 561 mRollo.mState.newPositionX = ev.getRawY() / getHeight(); 562 563 mVelocityTracker.computeCurrentVelocity(1000 /* px/sec */, mMaxFlingVelocity); 564 mRollo.mState.flingVelocity = mVelocityTracker.getYVelocity() / getHeight(); 565 mRollo.clearSelectedIcon(); 566 mRollo.mState.save(); 567 mRollo.fling(); 568 569 if (mVelocityTracker != null) { 570 mVelocityTracker.recycle(); 571 mVelocityTracker = null; 572 } 573 } 574 mTouchTracking = TRACKING_NONE; 575 break; 576 } 577 578 return true; 579 } 580 581 public void onClick(View v) { 582 if (mLocks != 0 || !isVisible()) { 583 return; 584 } 585 if (mRollo.checkClickOK() && mCurrentIconIndex == mDownIconIndex 586 && mCurrentIconIndex >= 0 && mCurrentIconIndex < mAllAppsList.size()) { 587 reallyPlaySoundEffect(SoundEffectConstants.CLICK); 588 ApplicationInfo app = mAllAppsList.get(mCurrentIconIndex); 589 mLauncher.startActivitySafely(app.intent); 590 } 591 } 592 593 public boolean onLongClick(View v) { 594 if (mLocks != 0 || !isVisible()) { 595 return true; 596 } 597 if (mRollo.checkClickOK() && mCurrentIconIndex == mDownIconIndex 598 && mCurrentIconIndex >= 0 && mCurrentIconIndex < mAllAppsList.size()) { 599 ApplicationInfo app = mAllAppsList.get(mCurrentIconIndex); 600 601 Bitmap bmp = app.iconBitmap; 602 final int w = bmp.getWidth(); 603 final int h = bmp.getHeight(); 604 605 // We don't really have an accurate location to use. This will do. 606 int screenX = mMotionDownRawX - (w / 2); 607 int screenY = mMotionDownRawY - h; 608 609 int left = (mDefines.ICON_TEXTURE_WIDTH_PX - mDefines.ICON_WIDTH_PX) / 2; 610 int top = (mDefines.ICON_TEXTURE_HEIGHT_PX - mDefines.ICON_HEIGHT_PX) / 2; 611 mDragController.startDrag(bmp, screenX, screenY, 612 0, 0, w, h, this, app, DragController.DRAG_ACTION_COPY); 613 614 mLauncher.closeAllApps(true); 615 } 616 return true; 617 } 618 619 @Override 620 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 621 if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SELECTED) { 622 if (!isVisible()) { 623 return false; 624 } 625 String text = null; 626 int index; 627 int count = mAllAppsList.size() + 1; // +1 is home 628 int pos = -1; 629 switch (mLastSelection) { 630 case SELECTION_ICONS: 631 index = mRollo.mState.selectedIconIndex; 632 if (index >= 0) { 633 ApplicationInfo info = mAllAppsList.get(index); 634 if (info.title != null) { 635 text = info.title.toString(); 636 pos = index; 637 } 638 } 639 break; 640 case SELECTION_HOME: 641 text = getContext().getString(R.string.all_apps_home_button_label); 642 pos = count; 643 break; 644 } 645 if (text != null) { 646 event.setEnabled(true); 647 event.getText().add(text); 648 //event.setContentDescription(text); 649 event.setItemCount(count); 650 event.setCurrentItemIndex(pos); 651 } 652 } 653 return false; 654 } 655 656 public void setDragController(DragController dragger) { 657 mDragController = dragger; 658 } 659 660 public void onDropCompleted(View target, boolean success) { 661 } 662 663 /** 664 * Zoom to the specifed level. 665 * 666 * @param zoom [0..1] 0 is hidden, 1 is open 667 */ 668 public void zoom(float zoom, boolean animate) { 669 cancelLongPress(); 670 mNextZoom = zoom; 671 mAnimateNextZoom = animate; 672 // if we do setZoom while we don't have a surface, we won't 673 // get the callbacks that actually set mZoom. 674 if (mRollo == null || !mHaveSurface) { 675 mZoomDirty = true; 676 mZoom = zoom; 677 return; 678 } else { 679 mRollo.setZoom(zoom, animate); 680 } 681 } 682 683 public boolean isVisible() { 684 return mZoom > 0.001f; 685 } 686 687 public boolean isOpaque() { 688 return mZoom > 0.999f; 689 } 690 691 public void setApps(ArrayList<ApplicationInfo> list) { 692 if (mRS == null) { 693 // We've been removed from the window. Don't bother with all this. 694 return; 695 } 696 697 mAllAppsList = list; 698 if (mRollo != null) { 699 mRollo.setApps(list); 700 } 701 mLocks &= ~LOCK_ICONS_PENDING; 702 } 703 704 public void addApps(ArrayList<ApplicationInfo> list) { 705 if (mAllAppsList == null) { 706 // Not done loading yet. We'll find out about it later. 707 return; 708 } 709 if (mRS == null) { 710 // We've been removed from the window. Don't bother with all this. 711 return; 712 } 713 714 final int N = list.size(); 715 if (mRollo != null) { 716 mRollo.reallocAppsList(mRollo.mState.iconCount + N); 717 } 718 719 for (int i=0; i<N; i++) { 720 final ApplicationInfo item = list.get(i); 721 int index = Collections.binarySearch(mAllAppsList, item, 722 LauncherModel.APP_NAME_COMPARATOR); 723 if (index < 0) { 724 index = -(index+1); 725 } 726 mAllAppsList.add(index, item); 727 if (mRollo != null) { 728 mRollo.addApp(index, item); 729 } 730 } 731 732 if (mRollo != null) { 733 mRollo.saveAppsList(); 734 } 735 } 736 737 public void removeApps(ArrayList<ApplicationInfo> list) { 738 if (mAllAppsList == null) { 739 // Not done loading yet. We'll find out about it later. 740 return; 741 } 742 743 final int N = list.size(); 744 for (int i=0; i<N; i++) { 745 final ApplicationInfo item = list.get(i); 746 int index = findAppByComponent(mAllAppsList, item); 747 if (index >= 0) { 748 int ic = mRollo != null ? mRollo.mState.iconCount : 666; 749 mAllAppsList.remove(index); 750 if (mRollo != null) { 751 mRollo.removeApp(index); 752 } 753 } else { 754 Log.w(TAG, "couldn't find a match for item \"" + item + "\""); 755 // Try to recover. This should keep us from crashing for now. 756 } 757 } 758 759 if (mRollo != null) { 760 mRollo.saveAppsList(); 761 } 762 } 763 764 public void updateApps(String packageName, ArrayList<ApplicationInfo> list) { 765 // Just remove and add, because they may need to be re-sorted. 766 removeApps(list); 767 addApps(list); 768 } 769 770 private static int findAppByComponent(ArrayList<ApplicationInfo> list, ApplicationInfo item) { 771 ComponentName component = item.intent.getComponent(); 772 final int N = list.size(); 773 for (int i=0; i<N; i++) { 774 ApplicationInfo x = list.get(i); 775 if (x.intent.getComponent().equals(component)) { 776 return i; 777 } 778 } 779 return -1; 780 } 781 782 private static int countPages(int iconCount) { 783 int iconsPerPage = Defines.COLUMNS_PER_PAGE * Defines.ROWS_PER_PAGE; 784 int pages = iconCount / iconsPerPage; 785 if (pages*iconsPerPage != iconCount) { 786 pages++; 787 } 788 return pages; 789 } 790 791 class AAMessage extends RenderScript.RSMessage { 792 public void run() { 793 mPosX = ((float)mData[0]) / (1 << 16); 794 mVelocity = ((float)mData[1]) / (1 << 16); 795 mZoom = ((float)mData[2]) / (1 << 16); 796 mZoomDirty = false; 797 } 798 } 799 800 public class RolloRS { 801 802 // Allocations ====== 803 private int mWidth; 804 private int mHeight; 805 806 private Resources mRes; 807 private Script mScript; 808 private Script.Invokable mInvokeMove; 809 private Script.Invokable mInvokeMoveTo; 810 private Script.Invokable mInvokeFling; 811 private Script.Invokable mInvokeResetWAR; 812 private Script.Invokable mInvokeSetZoom; 813 814 private ProgramStore mPSIcons; 815 private ProgramFragment mPFTexMip; 816 private ProgramFragment mPFTexMipAlpha; 817 private ProgramFragment mPFTexNearest; 818 private ProgramVertex mPV; 819 private ProgramVertex mPVCurve; 820 private SimpleMesh mMesh; 821 private ProgramVertex.MatrixAllocation mPVA; 822 823 private Allocation mUniformAlloc; 824 825 private Allocation mHomeButtonNormal; 826 private Allocation mHomeButtonFocused; 827 private Allocation mHomeButtonPressed; 828 829 private Allocation[] mIcons; 830 private int[] mIconIds; 831 private Allocation mAllocIconIds; 832 833 private Allocation[] mLabels; 834 private int[] mLabelIds; 835 private Allocation mAllocLabelIds; 836 private Allocation mSelectedIcon; 837 838 private int[] mTouchYBorders; 839 private int[] mTouchXBorders; 840 841 private Bitmap mSelectionBitmap; 842 private Canvas mSelectionCanvas; 843 844 Params mParams; 845 State mState; 846 847 class BaseAlloc { 848 Allocation mAlloc; 849 Type mType; 850 851 void save() { 852 mAlloc.data(this); 853 } 854 } 855 856 private boolean checkClickOK() { 857 return (Math.abs(mVelocity) < 0.4f) && 858 (Math.abs(mPosX - Math.round(mPosX)) < 0.4f); 859 } 860 861 class Params extends BaseAlloc { 862 Params() { 863 mType = Type.createFromClass(mRS, Params.class, 1, "ParamsClass"); 864 mAlloc = Allocation.createTyped(mRS, mType); 865 save(); 866 } 867 public int bubbleWidth; 868 public int bubbleHeight; 869 public int bubbleBitmapWidth; 870 public int bubbleBitmapHeight; 871 872 public int homeButtonWidth; 873 public int homeButtonHeight; 874 public int homeButtonTextureWidth; 875 public int homeButtonTextureHeight; 876 } 877 878 class State extends BaseAlloc { 879 public float newPositionX; 880 public int newTouchDown; 881 public float flingVelocity; 882 public int iconCount; 883 public int selectedIconIndex = -1; 884 public int selectedIconTexture; 885 public float zoomTarget; 886 public int homeButtonId; 887 public float targetPos; 888 889 State() { 890 mType = Type.createFromClass(mRS, State.class, 1, "StateClass"); 891 mAlloc = Allocation.createTyped(mRS, mType); 892 save(); 893 } 894 } 895 896 public RolloRS() { 897 } 898 899 public void init(Resources res, int width, int height) { 900 mRes = res; 901 mWidth = width; 902 mHeight = height; 903 initProgramVertex(); 904 initProgramFragment(); 905 initProgramStore(); 906 initGl(); 907 initData(); 908 initTouchState(); 909 initRs(); 910 } 911 912 public void initMesh() { 913 SimpleMesh.TriangleMeshBuilder tm = new SimpleMesh.TriangleMeshBuilder(mRS, 2, 0); 914 915 for (int ct=0; ct < 16; ct++) { 916 float pos = (1.f / (16.f - 1)) * ct; 917 tm.addVertex(0.0f, pos); 918 tm.addVertex(1.0f, pos); 919 } 920 for (int ct=0; ct < (16 * 2 - 2); ct+= 2) { 921 tm.addTriangle(ct, ct+1, ct+2); 922 tm.addTriangle(ct+1, ct+3, ct+2); 923 } 924 mMesh = tm.create(); 925 mMesh.setName("SMCell"); 926 } 927 928 void resize(int w, int h) { 929 mPVA.setupProjectionNormalized(w, h); 930 mWidth = w; 931 mHeight = h; 932 } 933 934 private void initProgramVertex() { 935 mPVA = new ProgramVertex.MatrixAllocation(mRS); 936 resize(mWidth, mHeight); 937 938 ProgramVertex.Builder pvb = new ProgramVertex.Builder(mRS, null, null); 939 pvb.setTextureMatrixEnable(true); 940 mPV = pvb.create(); 941 mPV.setName("PV"); 942 mPV.bindAllocation(mPVA); 943 944 Element.Builder eb = new Element.Builder(mRS); 945 eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 2), "ImgSize"); 946 eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 4), "Position"); 947 eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 2), "BendPos"); 948 eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 4), "ScaleOffset"); 949 Element e = eb.create(); 950 951 mUniformAlloc = Allocation.createSized(mRS, e, 1); 952 953 initMesh(); 954 ProgramVertex.ShaderBuilder sb = new ProgramVertex.ShaderBuilder(mRS); 955 String t = new String("void main() {\n" + 956 // Animation 957 " float ani = UNI_Position.z;\n" + 958 959 " float bendY1 = UNI_BendPos.x;\n" + 960 " float bendY2 = UNI_BendPos.y;\n" + 961 " float bendAngle = 47.0 * (3.14 / 180.0);\n" + 962 " float bendDistance = bendY1 * 0.4;\n" + 963 " float distanceDimLevel = 0.6;\n" + 964 965 " float bendStep = (bendAngle / bendDistance) * (bendAngle * 0.5);\n" + 966 " float aDy = cos(bendAngle);\n" + 967 " float aDz = sin(bendAngle);\n" + 968 969 " float scale = (2.0 / 480.0);\n" + 970 " float x = UNI_Position.x + UNI_ImgSize.x * (1.0 - ani) * (ATTRIB_position.x - 0.5);\n" + 971 " float ys= UNI_Position.y + UNI_ImgSize.y * (1.0 - ani) * ATTRIB_position.y;\n" + 972 " float y = 0.0;\n" + 973 " float z = 0.0;\n" + 974 " float lum = 1.0;\n" + 975 976 " float cv = min(ys, bendY1 - bendDistance) - (bendY1 - bendDistance);\n" + 977 " y += cv * aDy;\n" + 978 " z += -cv * aDz;\n" + 979 " cv = clamp(ys, bendY1 - bendDistance, bendY1) - bendY1;\n" + // curve range 980 " lum += cv / bendDistance * distanceDimLevel;\n" + 981 " y += cv * cos(cv * bendStep);\n" + 982 " z += cv * sin(cv * bendStep);\n" + 983 984 " cv = max(ys, bendY2 + bendDistance) - (bendY2 + bendDistance);\n" + 985 " y += cv * aDy;\n" + 986 " z += cv * aDz;\n" + 987 " cv = clamp(ys, bendY2, bendY2 + bendDistance) - bendY2;\n" + 988 " lum -= cv / bendDistance * distanceDimLevel;\n" + 989 " y += cv * cos(cv * bendStep);\n" + 990 " z += cv * sin(cv * bendStep);\n" + 991 992 " y += clamp(ys, bendY1, bendY2);\n" + 993 994 " vec4 pos;\n" + 995 " pos.x = (x + UNI_ScaleOffset.z) * UNI_ScaleOffset.x;\n" + 996 " pos.y = (y + UNI_ScaleOffset.w) * UNI_ScaleOffset.x;\n" + 997 " pos.z = z * UNI_ScaleOffset.x;\n" + 998 " pos.w = 1.0;\n" + 999 1000 " pos.x *= 1.0 + ani * 4.0;\n" + 1001 " pos.y *= 1.0 + ani * 4.0;\n" + 1002 " pos.z -= ani * 1.5;\n" + 1003 " lum *= 1.0 - ani;\n" + 1004 1005 " gl_Position = UNI_MVP * pos;\n" + 1006 " varColor.rgba = vec4(lum, lum, lum, 1.0);\n" + 1007 " varTex0.xy = ATTRIB_position;\n" + 1008 " varTex0.y = 1.0 - varTex0.y;\n" + 1009 " varTex0.zw = vec2(0.0, 0.0);\n" + 1010 "}\n"); 1011 sb.setShader(t); 1012 sb.addConstant(mUniformAlloc.getType()); 1013 sb.addInput(mMesh.getVertexType(0).getElement()); 1014 mPVCurve = sb.create(); 1015 mPVCurve.setName("PVCurve"); 1016 mPVCurve.bindAllocation(mPVA); 1017 mPVCurve.bindConstants(mUniformAlloc, 1); 1018 1019 mRS.contextBindProgramVertex(mPV); 1020 } 1021 1022 private void initProgramFragment() { 1023 Sampler.Builder sb = new Sampler.Builder(mRS); 1024 sb.setMin(Sampler.Value.LINEAR_MIP_LINEAR); 1025 sb.setMag(Sampler.Value.NEAREST); 1026 sb.setWrapS(Sampler.Value.CLAMP); 1027 sb.setWrapT(Sampler.Value.CLAMP); 1028 Sampler linear = sb.create(); 1029 1030 sb.setMin(Sampler.Value.NEAREST); 1031 sb.setMag(Sampler.Value.NEAREST); 1032 Sampler nearest = sb.create(); 1033 1034 ProgramFragment.Builder bf = new ProgramFragment.Builder(mRS); 1035 bf.setTexture(ProgramFragment.Builder.EnvMode.MODULATE, 1036 ProgramFragment.Builder.Format.RGBA, 0); 1037 mPFTexMip = bf.create(); 1038 mPFTexMip.setName("PFTexMip"); 1039 mPFTexMip.bindSampler(linear, 0); 1040 1041 mPFTexNearest = bf.create(); 1042 mPFTexNearest.setName("PFTexNearest"); 1043 mPFTexNearest.bindSampler(nearest, 0); 1044 1045 bf.setTexture(ProgramFragment.Builder.EnvMode.MODULATE, 1046 ProgramFragment.Builder.Format.ALPHA, 0); 1047 mPFTexMipAlpha = bf.create(); 1048 mPFTexMipAlpha.setName("PFTexMipAlpha"); 1049 mPFTexMipAlpha.bindSampler(linear, 0); 1050 1051 } 1052 1053 private void initProgramStore() { 1054 ProgramStore.Builder bs = new ProgramStore.Builder(mRS, null, null); 1055 bs.setDepthFunc(ProgramStore.DepthFunc.ALWAYS); 1056 bs.setColorMask(true,true,true,false); 1057 bs.setDitherEnable(true); 1058 bs.setBlendFunc(ProgramStore.BlendSrcFunc.SRC_ALPHA, 1059 ProgramStore.BlendDstFunc.ONE_MINUS_SRC_ALPHA); 1060 mPSIcons = bs.create(); 1061 mPSIcons.setName("PSIcons"); 1062 } 1063 1064 private void initGl() { 1065 mTouchXBorders = new int[Defines.COLUMNS_PER_PAGE+1]; 1066 mTouchYBorders = new int[Defines.ROWS_PER_PAGE+1]; 1067 } 1068 1069 private void initData() { 1070 mParams = new Params(); 1071 mState = new State(); 1072 1073 final Utilities.BubbleText bubble = new Utilities.BubbleText(getContext()); 1074 1075 mParams.bubbleWidth = bubble.getBubbleWidth(); 1076 mParams.bubbleHeight = bubble.getMaxBubbleHeight(); 1077 mParams.bubbleBitmapWidth = bubble.getBitmapWidth(); 1078 mParams.bubbleBitmapHeight = bubble.getBitmapHeight(); 1079 1080 mHomeButtonNormal = Allocation.createFromBitmapResource(mRS, mRes, 1081 R.drawable.home_button_normal, Element.RGBA_8888(mRS), false); 1082 mHomeButtonNormal.uploadToTexture(0); 1083 mHomeButtonFocused = Allocation.createFromBitmapResource(mRS, mRes, 1084 R.drawable.home_button_focused, Element.RGBA_8888(mRS), false); 1085 mHomeButtonFocused.uploadToTexture(0); 1086 mHomeButtonPressed = Allocation.createFromBitmapResource(mRS, mRes, 1087 R.drawable.home_button_pressed, Element.RGBA_8888(mRS), false); 1088 mHomeButtonPressed.uploadToTexture(0); 1089 mParams.homeButtonWidth = 76; 1090 mParams.homeButtonHeight = 68; 1091 mParams.homeButtonTextureWidth = 128; 1092 mParams.homeButtonTextureHeight = 128; 1093 1094 mState.homeButtonId = mHomeButtonNormal.getID(); 1095 1096 mParams.save(); 1097 mState.save(); 1098 1099 mSelectionBitmap = Bitmap.createBitmap(Defines.SELECTION_TEXTURE_WIDTH_PX, 1100 Defines.SELECTION_TEXTURE_HEIGHT_PX, Bitmap.Config.ARGB_8888); 1101 mSelectionCanvas = new Canvas(mSelectionBitmap); 1102 1103 setApps(null); 1104 } 1105 1106 private void initScript(int id) { 1107 } 1108 1109 private void initRs() { 1110 ScriptC.Builder sb = new ScriptC.Builder(mRS); 1111 sb.setScript(mRes, R.raw.allapps); 1112 sb.setRoot(true); 1113 sb.addDefines(mDefines); 1114 sb.setType(mParams.mType, "params", Defines.ALLOC_PARAMS); 1115 sb.setType(mState.mType, "state", Defines.ALLOC_STATE); 1116 sb.setType(mUniformAlloc.getType(), "vpConstants", Defines.ALLOC_VP_CONSTANTS); 1117 mInvokeMove = sb.addInvokable("move"); 1118 mInvokeFling = sb.addInvokable("fling"); 1119 mInvokeMoveTo = sb.addInvokable("moveTo"); 1120 mInvokeResetWAR = sb.addInvokable("resetHWWar"); 1121 mInvokeSetZoom = sb.addInvokable("setZoom"); 1122 mScript = sb.create(); 1123 mScript.setClearColor(0.0f, 0.0f, 0.0f, 0.0f); 1124 mScript.bindAllocation(mParams.mAlloc, Defines.ALLOC_PARAMS); 1125 mScript.bindAllocation(mState.mAlloc, Defines.ALLOC_STATE); 1126 mScript.bindAllocation(mAllocIconIds, Defines.ALLOC_ICON_IDS); 1127 mScript.bindAllocation(mAllocLabelIds, Defines.ALLOC_LABEL_IDS); 1128 mScript.bindAllocation(mUniformAlloc, Defines.ALLOC_VP_CONSTANTS); 1129 1130 mRS.contextBindRootScript(mScript); 1131 } 1132 1133 void dirtyCheck() { 1134 if (mZoomDirty) { 1135 setZoom(mNextZoom, mAnimateNextZoom); 1136 } 1137 } 1138 1139 private void setApps(ArrayList<ApplicationInfo> list) { 1140 final int count = list != null ? list.size() : 0; 1141 int allocCount = count; 1142 if (allocCount < 1) { 1143 allocCount = 1; 1144 } 1145 1146 mIcons = new Allocation[count]; 1147 mIconIds = new int[allocCount]; 1148 mAllocIconIds = Allocation.createSized(mRS, Element.USER_I32(mRS), allocCount); 1149 1150 mLabels = new Allocation[count]; 1151 mLabelIds = new int[allocCount]; 1152 mAllocLabelIds = Allocation.createSized(mRS, Element.USER_I32(mRS), allocCount); 1153 1154 Element ie8888 = Element.RGBA_8888(mRS); 1155 1156 mState.iconCount = count; 1157 for (int i=0; i < mState.iconCount; i++) { 1158 createAppIconAllocations(i, list.get(i)); 1159 } 1160 for (int i=0; i < mState.iconCount; i++) { 1161 uploadAppIcon(i, list.get(i)); 1162 } 1163 saveAppsList(); 1164 } 1165 1166 private void setZoom(float zoom, boolean animate) { 1167 mRollo.clearSelectedIcon(); 1168 mRollo.setHomeSelected(SELECTED_NONE); 1169 if (zoom > 0.001f) { 1170 mRollo.mState.zoomTarget = zoom; 1171 } else { 1172 mRollo.mState.zoomTarget = 0; 1173 } 1174 mRollo.mState.save(); 1175 if (!animate) { 1176 mRollo.mInvokeSetZoom.execute(); 1177 } 1178 } 1179 1180 private void createAppIconAllocations(int index, ApplicationInfo item) { 1181 mIcons[index] = Allocation.createFromBitmap(mRS, item.iconBitmap, 1182 Element.RGBA_8888(mRS), true); 1183 mLabels[index] = Allocation.createFromBitmap(mRS, item.titleBitmap, 1184 Element.A_8(mRS), true); 1185 mIconIds[index] = mIcons[index].getID(); 1186 mLabelIds[index] = mLabels[index].getID(); 1187 } 1188 1189 private void uploadAppIcon(int index, ApplicationInfo item) { 1190 if (mIconIds[index] != mIcons[index].getID()) { 1191 throw new IllegalStateException("uploadAppIcon index=" + index 1192 + " mIcons[index].getID=" + mIcons[index].getID() 1193 + " mIconsIds[index]=" + mIconIds[index] 1194 + " item=" + item); 1195 } 1196 mIcons[index].uploadToTexture(0); 1197 mLabels[index].uploadToTexture(0); 1198 } 1199 1200 /** 1201 * Puts the empty spaces at the end. Updates mState.iconCount. You must 1202 * fill in the values and call saveAppsList(). 1203 */ 1204 private void reallocAppsList(int count) { 1205 Allocation[] icons = new Allocation[count]; 1206 int[] iconIds = new int[count]; 1207 mAllocIconIds = Allocation.createSized(mRS, Element.USER_I32(mRS), count); 1208 1209 Allocation[] labels = new Allocation[count]; 1210 int[] labelIds = new int[count]; 1211 mAllocLabelIds = Allocation.createSized(mRS, Element.USER_I32(mRS), count); 1212 1213 final int oldCount = mRollo.mState.iconCount; 1214 1215 System.arraycopy(mIcons, 0, icons, 0, oldCount); 1216 System.arraycopy(mIconIds, 0, iconIds, 0, oldCount); 1217 System.arraycopy(mLabels, 0, labels, 0, oldCount); 1218 System.arraycopy(mLabelIds, 0, labelIds, 0, oldCount); 1219 1220 mIcons = icons; 1221 mIconIds = iconIds; 1222 mLabels = labels; 1223 mLabelIds = labelIds; 1224 } 1225 1226 /** 1227 * Handle the allocations for the new app. Make sure you call saveAppsList when done. 1228 */ 1229 private void addApp(int index, ApplicationInfo item) { 1230 final int count = mState.iconCount - index; 1231 final int dest = index + 1; 1232 1233 System.arraycopy(mIcons, index, mIcons, dest, count); 1234 System.arraycopy(mIconIds, index, mIconIds, dest, count); 1235 System.arraycopy(mLabels, index, mLabels, dest, count); 1236 System.arraycopy(mLabelIds, index, mLabelIds, dest, count); 1237 1238 createAppIconAllocations(index, item); 1239 uploadAppIcon(index, item); 1240 mRollo.mState.iconCount++; 1241 } 1242 1243 /** 1244 * Handle the allocations for the removed app. Make sure you call saveAppsList when done. 1245 */ 1246 private void removeApp(int index) { 1247 final int count = mState.iconCount - index - 1; 1248 final int src = index + 1; 1249 1250 System.arraycopy(mIcons, src, mIcons, index, count); 1251 System.arraycopy(mIconIds, src, mIconIds, index, count); 1252 System.arraycopy(mLabels, src, mLabels, index, count); 1253 System.arraycopy(mLabelIds, src, mLabelIds, index, count); 1254 1255 mRollo.mState.iconCount--; 1256 final int last = mState.iconCount; 1257 1258 mIcons[last] = null; 1259 mIconIds[last] = 0; 1260 mLabels[last] = null; 1261 mLabelIds[last] = 0; 1262 } 1263 1264 /** 1265 * Send the apps list structures to RS. 1266 */ 1267 private void saveAppsList() { 1268 // WTF: how could mScript be not null but mAllocIconIds null b/2460740. 1269 if (mScript != null && mAllocIconIds != null) { 1270 mRS.contextBindRootScript(null); 1271 1272 mAllocIconIds.data(mIconIds); 1273 mAllocLabelIds.data(mLabelIds); 1274 1275 mScript.bindAllocation(mAllocIconIds, Defines.ALLOC_ICON_IDS); 1276 mScript.bindAllocation(mAllocLabelIds, Defines.ALLOC_LABEL_IDS); 1277 1278 mState.save(); 1279 1280 // Note: mScript may be null if we haven't initialized it yet. 1281 // In that case, this is a no-op. 1282 if (mInvokeResetWAR != null) { 1283 mInvokeResetWAR.execute(); 1284 } 1285 1286 mRS.contextBindRootScript(mScript); 1287 } 1288 } 1289 1290 void initTouchState() { 1291 int width = getWidth(); 1292 int height = getHeight(); 1293 int cellHeight = 145;//iconsSize / Defines.ROWS_PER_PAGE; 1294 int cellWidth = width / Defines.COLUMNS_PER_PAGE; 1295 1296 int centerY = (height / 2); 1297 mTouchYBorders[0] = centerY - (cellHeight * 2); 1298 mTouchYBorders[1] = centerY - cellHeight; 1299 mTouchYBorders[2] = centerY; 1300 mTouchYBorders[3] = centerY + cellHeight; 1301 mTouchYBorders[4] = centerY + (cellHeight * 2); 1302 1303 int centerX = (width / 2); 1304 mTouchXBorders[0] = 0; 1305 mTouchXBorders[1] = centerX - (width / 4); 1306 mTouchXBorders[2] = centerX; 1307 mTouchXBorders[3] = centerX + (width / 4); 1308 mTouchXBorders[4] = width; 1309 } 1310 1311 void fling() { 1312 mInvokeFling.execute(); 1313 } 1314 1315 void move() { 1316 mInvokeMove.execute(); 1317 } 1318 1319 void moveTo(float row) { 1320 mState.targetPos = row; 1321 mState.save(); 1322 mInvokeMoveTo.execute(); 1323 } 1324 1325 int chooseTappedIcon(int x, int y, float pos) { 1326 // Adjust for scroll position if not zero. 1327 y += (pos - ((int)pos)) * (mTouchYBorders[1] - mTouchYBorders[0]); 1328 1329 int col = -1; 1330 int row = -1; 1331 for (int i=0; i<Defines.COLUMNS_PER_PAGE; i++) { 1332 if (x >= mTouchXBorders[i] && x < mTouchXBorders[i+1]) { 1333 col = i; 1334 break; 1335 } 1336 } 1337 for (int i=0; i<Defines.ROWS_PER_PAGE; i++) { 1338 if (y >= mTouchYBorders[i] && y < mTouchYBorders[i+1]) { 1339 row = i; 1340 break; 1341 } 1342 } 1343 1344 if (row < 0 || col < 0) { 1345 return -1; 1346 } 1347 1348 int index = (((int)pos) * Defines.COLUMNS_PER_PAGE) 1349 + (row * Defines.ROWS_PER_PAGE) + col; 1350 1351 if (index >= mState.iconCount) { 1352 return -1; 1353 } else { 1354 return index; 1355 } 1356 } 1357 1358 /** 1359 * You need to call save() on mState on your own after calling this. 1360 * 1361 * @return the index of the icon that was selected. 1362 */ 1363 int selectIcon(int x, int y, float pos, int pressed) { 1364 final int index = chooseTappedIcon(x, y, pos); 1365 selectIcon(index, pressed); 1366 return index; 1367 } 1368 1369 /** 1370 * Select the icon at the given index. 1371 * 1372 * @param index The index. 1373 * @param pressed one of SELECTED_PRESSED or SELECTED_FOCUSED 1374 */ 1375 void selectIcon(int index, int pressed) { 1376 if (mAllAppsList == null || index < 0 || index >= mAllAppsList.size()) { 1377 mState.selectedIconIndex = -1; 1378 if (mLastSelection == SELECTION_ICONS) { 1379 mLastSelection = SELECTION_NONE; 1380 } 1381 } else { 1382 if (pressed == SELECTED_FOCUSED) { 1383 mLastSelection = SELECTION_ICONS; 1384 } 1385 1386 int prev = mState.selectedIconIndex; 1387 mState.selectedIconIndex = index; 1388 1389 ApplicationInfo info = mAllAppsList.get(index); 1390 Bitmap selectionBitmap = mSelectionBitmap; 1391 1392 Utilities.drawSelectedAllAppsBitmap(mSelectionCanvas, 1393 selectionBitmap.getWidth(), selectionBitmap.getHeight(), 1394 pressed == SELECTED_PRESSED, info.iconBitmap); 1395 1396 mSelectedIcon = Allocation.createFromBitmap(mRS, selectionBitmap, 1397 Element.RGBA_8888(mRS), false); 1398 mSelectedIcon.uploadToTexture(0); 1399 mState.selectedIconTexture = mSelectedIcon.getID(); 1400 1401 if (prev != index) { 1402 if (info.title != null && info.title.length() > 0) { 1403 //setContentDescription(info.title); 1404 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); 1405 } 1406 } 1407 } 1408 } 1409 1410 /** 1411 * You need to call save() on mState on your own after calling this. 1412 */ 1413 void clearSelectedIcon() { 1414 mState.selectedIconIndex = -1; 1415 } 1416 1417 void setHomeSelected(int mode) { 1418 final int prev = mLastSelection; 1419 switch (mode) { 1420 case SELECTED_NONE: 1421 mState.homeButtonId = mHomeButtonNormal.getID(); 1422 break; 1423 case SELECTED_FOCUSED: 1424 mLastSelection = SELECTION_HOME; 1425 mState.homeButtonId = mHomeButtonFocused.getID(); 1426 if (prev != SELECTION_HOME) { 1427 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); 1428 } 1429 break; 1430 case SELECTED_PRESSED: 1431 mState.homeButtonId = mHomeButtonPressed.getID(); 1432 break; 1433 } 1434 } 1435 1436 public void dumpState() { 1437 Log.d(TAG, "mRollo.mWidth=" + mWidth); 1438 Log.d(TAG, "mRollo.mHeight=" + mHeight); 1439 Log.d(TAG, "mRollo.mIcons=" + mIcons); 1440 if (mIcons != null) { 1441 Log.d(TAG, "mRollo.mIcons.length=" + mIcons.length); 1442 } 1443 if (mIconIds != null) { 1444 Log.d(TAG, "mRollo.mIconIds.length=" + mIconIds.length); 1445 } 1446 Log.d(TAG, "mRollo.mIconIds=" + Arrays.toString(mIconIds)); 1447 if (mLabelIds != null) { 1448 Log.d(TAG, "mRollo.mLabelIds.length=" + mLabelIds.length); 1449 } 1450 Log.d(TAG, "mRollo.mLabelIds=" + Arrays.toString(mLabelIds)); 1451 Log.d(TAG, "mRollo.mTouchXBorders=" + Arrays.toString(mTouchXBorders)); 1452 Log.d(TAG, "mRollo.mTouchYBorders=" + Arrays.toString(mTouchYBorders)); 1453 Log.d(TAG, "mRollo.mState.newPositionX=" + mState.newPositionX); 1454 Log.d(TAG, "mRollo.mState.newTouchDown=" + mState.newTouchDown); 1455 Log.d(TAG, "mRollo.mState.flingVelocity=" + mState.flingVelocity); 1456 Log.d(TAG, "mRollo.mState.iconCount=" + mState.iconCount); 1457 Log.d(TAG, "mRollo.mState.selectedIconIndex=" + mState.selectedIconIndex); 1458 Log.d(TAG, "mRollo.mState.selectedIconTexture=" + mState.selectedIconTexture); 1459 Log.d(TAG, "mRollo.mState.zoomTarget=" + mState.zoomTarget); 1460 Log.d(TAG, "mRollo.mState.homeButtonId=" + mState.homeButtonId); 1461 Log.d(TAG, "mRollo.mState.targetPos=" + mState.targetPos); 1462 Log.d(TAG, "mRollo.mParams.bubbleWidth=" + mParams.bubbleWidth); 1463 Log.d(TAG, "mRollo.mParams.bubbleHeight=" + mParams.bubbleHeight); 1464 Log.d(TAG, "mRollo.mParams.bubbleBitmapWidth=" + mParams.bubbleBitmapWidth); 1465 Log.d(TAG, "mRollo.mParams.bubbleBitmapHeight=" + mParams.bubbleBitmapHeight); 1466 Log.d(TAG, "mRollo.mParams.homeButtonWidth=" + mParams.homeButtonWidth); 1467 Log.d(TAG, "mRollo.mParams.homeButtonHeight=" + mParams.homeButtonHeight); 1468 Log.d(TAG, "mRollo.mParams.homeButtonTextureWidth=" + mParams.homeButtonTextureWidth); 1469 Log.d(TAG, "mRollo.mParams.homeButtonTextureHeight=" + mParams.homeButtonTextureHeight); 1470 } 1471 } 1472 1473 public void dumpState() { 1474 Log.d(TAG, "mRS=" + mRS); 1475 Log.d(TAG, "mRollo=" + mRollo); 1476 ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList", mAllAppsList); 1477 Log.d(TAG, "mArrowNavigation=" + mArrowNavigation); 1478 Log.d(TAG, "mStartedScrolling=" + mStartedScrolling); 1479 Log.d(TAG, "mLastSelection=" + mLastSelection); 1480 Log.d(TAG, "mLastSelectedIcon=" + mLastSelectedIcon); 1481 Log.d(TAG, "mVelocityTracker=" + mVelocityTracker); 1482 Log.d(TAG, "mTouchTracking=" + mTouchTracking); 1483 Log.d(TAG, "mShouldGainFocus=" + mShouldGainFocus); 1484 Log.d(TAG, "mZoomDirty=" + mZoomDirty); 1485 Log.d(TAG, "mAnimateNextZoom=" + mAnimateNextZoom); 1486 Log.d(TAG, "mZoom=" + mZoom); 1487 Log.d(TAG, "mPosX=" + mPosX); 1488 Log.d(TAG, "mVelocity=" + mVelocity); 1489 Log.d(TAG, "mMessageProc=" + mMessageProc); 1490 if (mRollo != null) { 1491 mRollo.dumpState(); 1492 } 1493 if (mRS != null) { 1494 mRS.contextDump(0); 1495 } 1496 } 1497} 1498 1499 1500