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