/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.launcher2; import android.content.ComponentName; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.PixelFormat; import android.graphics.Rect; import android.os.SystemClock; import android.renderscript.Allocation; import android.renderscript.Dimension; import android.renderscript.Element; import android.renderscript.ProgramFragment; import android.renderscript.ProgramStore; import android.renderscript.ProgramVertex; import android.renderscript.RSSurfaceView; import android.renderscript.RenderScript; import android.renderscript.Sampler; import android.renderscript.Script; import android.renderscript.ScriptC; import android.renderscript.SimpleMesh; import android.renderscript.Type; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.SoundEffectConstants; import android.view.SurfaceHolder; import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; public class AllAppsView extends RSSurfaceView implements View.OnClickListener, View.OnLongClickListener, DragSource { private static final String TAG = "Launcher.AllAppsView"; /** Bit for mLocks for when there are icons being loaded. */ private static final int LOCK_ICONS_PENDING = 1; private static final int TRACKING_NONE = 0; private static final int TRACKING_FLING = 1; private static final int TRACKING_HOME = 2; private static final int SELECTED_NONE = 0; private static final int SELECTED_FOCUSED = 1; private static final int SELECTED_PRESSED = 2; private static final int SELECTION_NONE = 0; private static final int SELECTION_ICONS = 1; private static final int SELECTION_HOME = 2; private Launcher mLauncher; private DragController mDragController; /** When this is 0, modifications are allowed, when it's not, they're not. * TODO: What about scrolling? */ private int mLocks = LOCK_ICONS_PENDING; private int mSlop; private int mMaxFlingVelocity; private Defines mDefines = new Defines(); private RenderScript mRS; private RolloRS mRollo; private ArrayList mAllAppsList; /** * True when we are using arrow keys or trackball to drive navigation */ private boolean mArrowNavigation = false; private boolean mStartedScrolling; /** * Used to keep track of the selection when AllAppsView loses window focus. * One of the SELECTION_ constants. */ private int mLastSelection; /** * Used to keep track of the selection when AllAppsView loses window focus */ private int mLastSelectedIcon; private VelocityTracker mVelocity; private int mTouchTracking; private int mMotionDownRawX; private int mMotionDownRawY; private int mDownIconIndex = -1; private int mCurrentIconIndex = -1; static class Defines { public static final int ALLOC_PARAMS = 0; public static final int ALLOC_STATE = 1; public static final int ALLOC_ICON_IDS = 3; public static final int ALLOC_LABEL_IDS = 4; public static final int COLUMNS_PER_PAGE = 4; public static final int ROWS_PER_PAGE = 4; public static final int ICON_WIDTH_PX = 64; public static final int ICON_TEXTURE_WIDTH_PX = 128; public static final int ICON_HEIGHT_PX = 64; public static final int ICON_TEXTURE_HEIGHT_PX = 128; public int SCREEN_WIDTH_PX; public int SCREEN_HEIGHT_PX; public void recompute(int w, int h) { SCREEN_WIDTH_PX = 480; SCREEN_HEIGHT_PX = 800; } } public AllAppsView(Context context, AttributeSet attrs) { super(context, attrs); setFocusable(true); setSoundEffectsEnabled(false); getHolder().setFormat(PixelFormat.TRANSLUCENT); final ViewConfiguration config = ViewConfiguration.get(context); mSlop = config.getScaledTouchSlop(); mMaxFlingVelocity = config.getScaledMaximumFlingVelocity(); setOnClickListener(this); setOnLongClickListener(this); setZOrderOnTop(true); getHolder().setFormat(PixelFormat.TRANSLUCENT); } /** * If you have an attached click listener, View always plays the click sound!?!? * Deal with sound effects by hand. */ public void reallyPlaySoundEffect(int sound) { boolean old = isSoundEffectsEnabled(); setSoundEffectsEnabled(true); playSoundEffect(sound); setSoundEffectsEnabled(old); } public AllAppsView(Context context, AttributeSet attrs, int defStyle) { this(context, attrs); } public void setLauncher(Launcher launcher) { mLauncher = launcher; } @Override public void surfaceDestroyed(SurfaceHolder holder) { super.surfaceDestroyed(holder); mRollo.mHasSurface = false; } @Override public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { Log.d(TAG, "starting surfaceChanged"); long startTime = SystemClock.uptimeMillis(); super.surfaceChanged(holder, format, w, h); if (mRS == null) { mRS = createRenderScript(true); mRollo = new RolloRS(); mRollo.mHasSurface = true; mRollo.init(getResources(), w, h); if (mAllAppsList != null) { mRollo.setApps(mAllAppsList); Log.d(TAG, "surfaceChanged... calling mRollo.setApps"); } } else { mRollo.mHasSurface = true; mRollo.dirtyCheck(); } Resources res = getContext().getResources(); int barHeight = (int)res.getDimension(R.dimen.button_bar_height); long endTime = SystemClock.uptimeMillis(); Log.d(TAG, "surfaceChanged took " + (endTime-startTime) + "ms"); } @Override public void onWindowFocusChanged(boolean hasWindowFocus) { super.onWindowFocusChanged(hasWindowFocus); if (mArrowNavigation) { if (!hasWindowFocus) { // Clear selection when we lose window focus mLastSelectedIcon = mRollo.mState.selectedIconIndex; mRollo.setHomeSelected(SELECTED_NONE); mRollo.clearSelectedIcon(); mRollo.mState.save(); } else if (hasWindowFocus) { if (mRollo.mState.iconCount > 0) { if (mLastSelection == SELECTION_ICONS) { int selection = mLastSelectedIcon; final int firstIcon = Math.round(mRollo.mMessageProc.mPosX) * Defines.COLUMNS_PER_PAGE; if (selection < 0 || // No selection selection < firstIcon || // off the top of the screen selection >= mRollo.mState.iconCount || // past last icon selection >= firstIcon + // past last icon on screen (Defines.COLUMNS_PER_PAGE * Defines.ROWS_PER_PAGE)) { selection = firstIcon; } // Select the first icon when we gain window focus mRollo.selectIcon(selection, SELECTED_FOCUSED); mRollo.mState.save(); } else if (mLastSelection == SELECTION_HOME) { mRollo.setHomeSelected(SELECTED_FOCUSED); mRollo.mState.save(); } } } } } @Override protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) { super.onFocusChanged(gainFocus, direction, previouslyFocusedRect); if (!isVisible()) { return; } if (gainFocus) { if (!mArrowNavigation && mRollo.mState.iconCount > 0) { // Select the first icon when we gain keyboard focus mArrowNavigation = true; mRollo.selectIcon(Math.round(mRollo.mMessageProc.mPosX) * Defines.COLUMNS_PER_PAGE, SELECTED_FOCUSED); mRollo.mState.save(); } } else { if (mArrowNavigation) { // Clear selection when we lose focus mRollo.clearSelectedIcon(); mRollo.setHomeSelected(SELECTED_NONE); mRollo.mState.save(); mArrowNavigation = false; } } } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { boolean handled = false; if (!isVisible()) { return false; } final int iconCount = mRollo.mState.iconCount; if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_ENTER) { if (mArrowNavigation) { if (mLastSelection == SELECTION_HOME) { reallyPlaySoundEffect(SoundEffectConstants.CLICK); mLauncher.closeAllApps(true); } else { int whichApp = mRollo.mState.selectedIconIndex; if (whichApp >= 0) { ApplicationInfo app = mAllAppsList.get(whichApp); mLauncher.startActivitySafely(app.intent); handled = true; } } } } if (mArrowNavigation && iconCount > 0) { mArrowNavigation = true; int currentSelection = mRollo.mState.selectedIconIndex; int currentTopRow = Math.round(mRollo.mMessageProc.mPosX); // The column of the current selection, in the range 0..COLUMNS_PER_PAGE-1 final int currentPageCol = currentSelection % Defines.COLUMNS_PER_PAGE; // The row of the current selection, in the range 0..ROWS_PER_PAGE-1 final int currentPageRow = (currentSelection - (currentTopRow*Defines.COLUMNS_PER_PAGE)) / Defines.ROWS_PER_PAGE; int newSelection = currentSelection; switch (keyCode) { case KeyEvent.KEYCODE_DPAD_UP: if (mLastSelection == SELECTION_HOME) { mRollo.setHomeSelected(SELECTED_NONE); int lastRowCount = iconCount % Defines.COLUMNS_PER_PAGE; if (lastRowCount == 0) { lastRowCount = Defines.COLUMNS_PER_PAGE; } newSelection = iconCount - lastRowCount + (Defines.COLUMNS_PER_PAGE / 2); if (newSelection >= iconCount) { newSelection = iconCount-1; } int target = (newSelection / Defines.COLUMNS_PER_PAGE) - (Defines.ROWS_PER_PAGE - 1); if (target < 0) { target = 0; } if (currentTopRow != target) { mRollo.moveTo(target); } } else { if (currentPageRow > 0) { newSelection = currentSelection - Defines.COLUMNS_PER_PAGE; } else if (currentTopRow > 0) { newSelection = currentSelection - Defines.COLUMNS_PER_PAGE; mRollo.moveTo(newSelection / Defines.COLUMNS_PER_PAGE); } } handled = true; break; case KeyEvent.KEYCODE_DPAD_DOWN: { final int rowCount = iconCount / Defines.COLUMNS_PER_PAGE + (iconCount % Defines.COLUMNS_PER_PAGE == 0 ? 0 : 1); final int currentRow = currentSelection / Defines.COLUMNS_PER_PAGE; if (mLastSelection != SELECTION_HOME) { if (currentRow < rowCount-1) { mRollo.setHomeSelected(SELECTED_NONE); newSelection = currentSelection + Defines.COLUMNS_PER_PAGE; if (newSelection >= iconCount) { // Go from D to G in this arrangement: // A B C D // E F G newSelection = iconCount - 1; } if (currentPageRow >= Defines.ROWS_PER_PAGE - 1) { mRollo.moveTo((newSelection / Defines.COLUMNS_PER_PAGE) - Defines.ROWS_PER_PAGE + 1); } } else { newSelection = -1; mRollo.setHomeSelected(SELECTED_FOCUSED); } } handled = true; break; } case KeyEvent.KEYCODE_DPAD_LEFT: if (currentPageCol > 0) { newSelection = currentSelection - 1; } handled = true; break; case KeyEvent.KEYCODE_DPAD_RIGHT: if ((currentPageCol < Defines.COLUMNS_PER_PAGE - 1) && (currentSelection < iconCount - 1)) { newSelection = currentSelection + 1; } handled = true; break; } if (newSelection != currentSelection) { mRollo.selectIcon(newSelection, SELECTED_FOCUSED); mRollo.mState.save(); } } return handled; } @Override public boolean onTouchEvent(MotionEvent ev) { mArrowNavigation = false; if (!isVisible()) { return true; } if (mLocks != 0) { return true; } super.onTouchEvent(ev); int x = (int)ev.getX(); int y = (int)ev.getY(); int action = ev.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: if (y > mRollo.mTouchYBorders[mRollo.mTouchYBorders.length-1]) { mTouchTracking = TRACKING_HOME; mRollo.setHomeSelected(SELECTED_PRESSED); mRollo.mState.save(); mCurrentIconIndex = -1; } else { mTouchTracking = TRACKING_FLING; mMotionDownRawX = (int)ev.getRawX(); mMotionDownRawY = (int)ev.getRawY(); mRollo.mState.newPositionX = ev.getRawY() / getHeight(); mRollo.mState.newTouchDown = 1; if (!mRollo.checkClickOK()) { mRollo.clearSelectedIcon(); } else { mDownIconIndex = mCurrentIconIndex = mRollo.selectIcon(x, y, mRollo.mMessageProc.mPosX, SELECTED_PRESSED); if (mDownIconIndex < 0) { // if nothing was selected, no long press. cancelLongPress(); } } mRollo.mState.save(); mRollo.move(); mVelocity = VelocityTracker.obtain(); mVelocity.addMovement(ev); mStartedScrolling = false; } break; case MotionEvent.ACTION_MOVE: case MotionEvent.ACTION_OUTSIDE: if (mTouchTracking == TRACKING_HOME) { mRollo.setHomeSelected(y > mRollo.mTouchYBorders[mRollo.mTouchYBorders.length-1] ? SELECTED_PRESSED : SELECTED_NONE); mRollo.mState.save(); } else if (mTouchTracking == TRACKING_FLING) { int rawX = (int)ev.getRawX(); int rawY = (int)ev.getRawY(); int slop; slop = Math.abs(rawY - mMotionDownRawY); if (!mStartedScrolling && slop < mSlop) { // don't update anything so when we do start scrolling // below, we get the right delta. mCurrentIconIndex = mRollo.chooseTappedIcon(x, y, mRollo.mMessageProc.mPosX); if (mDownIconIndex != mCurrentIconIndex) { // If a different icon is selected, don't allow it to be picked up. // This handles off-axis dragging. cancelLongPress(); mCurrentIconIndex = -1; } } else { if (!mStartedScrolling) { cancelLongPress(); mCurrentIconIndex = -1; } mRollo.mState.newPositionX = ev.getRawY() / getHeight(); mRollo.mState.newTouchDown = 1; mRollo.move(); mStartedScrolling = true; mRollo.clearSelectedIcon(); mVelocity.addMovement(ev); mRollo.mState.save(); } } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: if (mTouchTracking == TRACKING_HOME) { if (action == MotionEvent.ACTION_UP) { if (y > mRollo.mTouchYBorders[mRollo.mTouchYBorders.length-1]) { reallyPlaySoundEffect(SoundEffectConstants.CLICK); mLauncher.closeAllApps(true); } mRollo.setHomeSelected(SELECTED_NONE); mRollo.mState.save(); } mCurrentIconIndex = -1; } else if (mTouchTracking == TRACKING_FLING) { mRollo.mState.newTouchDown = 0; mRollo.mState.newPositionX = ev.getRawY() / getHeight(); mVelocity.computeCurrentVelocity(1000 /* px/sec */, mMaxFlingVelocity); mRollo.mState.flingVelocity = mVelocity.getYVelocity() / getHeight(); mRollo.clearSelectedIcon(); mRollo.mState.save(); mRollo.fling(); if (mVelocity != null) { mVelocity.recycle(); mVelocity = null; } } mTouchTracking = TRACKING_NONE; break; } return true; } public void onClick(View v) { if (mLocks != 0 || !isVisible()) { return; } if (mRollo.checkClickOK() && mCurrentIconIndex == mDownIconIndex && mCurrentIconIndex >= 0 && mCurrentIconIndex < mAllAppsList.size()) { reallyPlaySoundEffect(SoundEffectConstants.CLICK); ApplicationInfo app = mAllAppsList.get(mCurrentIconIndex); mLauncher.startActivitySafely(app.intent); } } public boolean onLongClick(View v) { if (mLocks != 0 || !isVisible()) { return true; } if (mRollo.checkClickOK() && mCurrentIconIndex == mDownIconIndex && mCurrentIconIndex >= 0 && mCurrentIconIndex < mAllAppsList.size()) { ApplicationInfo app = mAllAppsList.get(mCurrentIconIndex); // We don't really have an accurate location to use. This will do. int screenX = mMotionDownRawX - (mDefines.ICON_WIDTH_PX / 2); int screenY = mMotionDownRawY - mDefines.ICON_HEIGHT_PX; int left = (mDefines.ICON_TEXTURE_WIDTH_PX - mDefines.ICON_WIDTH_PX) / 2; int top = (mDefines.ICON_TEXTURE_HEIGHT_PX - mDefines.ICON_HEIGHT_PX) / 2; mDragController.startDrag(app.iconBitmap, screenX, screenY, left, top, mDefines.ICON_WIDTH_PX, mDefines.ICON_HEIGHT_PX, this, app, DragController.DRAG_ACTION_COPY); mLauncher.closeAllApps(true); } return true; } public void setDragController(DragController dragger) { mDragController = dragger; } public void onDropCompleted(View target, boolean success) { } /** * Zoom to the specifed amount. * * @param amount [0..1] 0 is hidden, 1 is open */ public void zoom(float amount) { if (mRollo == null) { return; } cancelLongPress(); mRollo.clearSelectedIcon(); mRollo.setHomeSelected(SELECTED_NONE); if (amount > 0.001f) { // set in readback, so we're correct even before the next frame mRollo.mState.zoomTarget = amount; } else { mRollo.mState.zoomTarget = 0; } mRollo.mState.save(); } public boolean isVisible() { if (mRollo == null) { return false; } return mRollo.mMessageProc.mZoom > 0.001f; } /* @Override public boolean onTrackballEvent(MotionEvent ev) { float x = ev.getX(); float y = ev.getY(); //Float tx = new Float(x); //Float ty = new Float(y); //Log.e("rs", "tbe " + tx.toString() + ", " + ty.toString()); return true; } */ public void setApps(ArrayList list) { mAllAppsList = list; if (mRollo != null) { mRollo.setApps(list); } mLocks &= ~LOCK_ICONS_PENDING; } public void addApps(ArrayList list) { if (mAllAppsList == null) { // Not done loading yet. We'll find out about it later. return; } final int N = list.size(); if (mRollo != null) { mRollo.reallocAppsList(mRollo.mState.iconCount + N); } for (int i=0; i list) { // Just remove and add, because they may need to be re-sorted. removeApps(list); addApps(list); } private Comparator mAppNameComp = new Comparator() { public int compare(ApplicationInfo a, ApplicationInfo b) { int result = a.title.toString().compareTo(b.toString()); if (result != 0) { return result; } return a.intent.getComponent().compareTo(b.intent.getComponent()); } }; private static int findAppByComponent(ArrayList list, ApplicationInfo item) { ComponentName component = item.intent.getComponent(); final int N = list.size(); for (int i=0; i 7) { angle = maxAngle * (ct - 7) * 0.2f; angle = Math.min(angle, maxAngle); } l = Math.max(0.4f, l); l = Math.min(1.0f, l); y += 0.1f * Math.cos(angle); z += 0.1f * Math.sin(angle); float t = 0.1f * ct; float ds = 0.08f; tm.setColor(l, l, l, 0.99f); tm.setTexture(ds, t); tm.addVertex(-0.5f, y, z); tm.setTexture(1 - ds, t); tm.addVertex(0.5f, y, z); } for (int ct=0; ct < (200 * 2 - 2); ct+= 2) { tm.addTriangle(ct, ct+1, ct+2); tm.addTriangle(ct+1, ct+3, ct+2); } mMesh2 = tm.create(); mMesh2.setName("SMMesh"); } private void initProgramVertex() { ProgramVertex.MatrixAllocation pva = new ProgramVertex.MatrixAllocation(mRS); pva.setupProjectionNormalized(mWidth, mHeight); ProgramVertex.Builder pvb = new ProgramVertex.Builder(mRS, null, null); pvb.setTextureMatrixEnable(true); mPV = pvb.create(); mPV.setName("PV"); mPV.bindAllocation(pva); //pva = new ProgramVertex.MatrixAllocation(mRS); //pva.setupOrthoWindow(mWidth, mHeight); //pvb.setTextureMatrixEnable(true); //mPVOrtho = pvb.create(); //mPVOrtho.setName("PVOrtho"); //mPVOrtho.bindAllocation(pva); mRS.contextBindProgramVertex(mPV); } private void initProgramFragment() { Sampler.Builder sb = new Sampler.Builder(mRS); sb.setMin(Sampler.Value.LINEAR_MIP_LINEAR); sb.setMag(Sampler.Value.LINEAR); sb.setWrapS(Sampler.Value.CLAMP); sb.setWrapT(Sampler.Value.CLAMP); Sampler linear = sb.create(); sb.setMin(Sampler.Value.NEAREST); sb.setMag(Sampler.Value.NEAREST); Sampler nearest = sb.create(); ProgramFragment.Builder bf = new ProgramFragment.Builder(mRS, null, null); //mPFColor = bf.create(); //mPFColor.setName("PFColor"); bf.setTexEnable(true, 0); bf.setTexEnvMode(ProgramFragment.EnvMode.MODULATE, 0); mPFTexMip = bf.create(); mPFTexMip.setName("PFTexMip"); mPFTexMip.bindSampler(linear, 0); mPFTexNearest = bf.create(); mPFTexNearest.setName("PFTexNearest"); mPFTexNearest.bindSampler(nearest, 0); } private void initProgramStore() { ProgramStore.Builder bs = new ProgramStore.Builder(mRS, null, null); bs.setDepthFunc(ProgramStore.DepthFunc.ALWAYS); bs.setColorMask(true,true,true,false); bs.setDitherEnable(true); bs.setBlendFunc(ProgramStore.BlendSrcFunc.SRC_ALPHA, ProgramStore.BlendDstFunc.ONE_MINUS_SRC_ALPHA); mPSIcons = bs.create(); mPSIcons.setName("PSIcons"); //bs.setDitherEnable(false); //mPSText = bs.create(); //mPSText.setName("PSText"); } private void initGl() { mTouchXBorders = new int[Defines.COLUMNS_PER_PAGE+1]; mTouchYBorders = new int[Defines.ROWS_PER_PAGE+1]; } private void initData() { mParams = new Params(); mState = new State(); final Utilities.BubbleText bubble = new Utilities.BubbleText(getContext()); mParams.bubbleWidth = bubble.getBubbleWidth(); mParams.bubbleHeight = bubble.getMaxBubbleHeight(); mParams.bubbleBitmapWidth = bubble.getBitmapWidth(); mParams.bubbleBitmapHeight = bubble.getBitmapHeight(); mHomeButtonNormal = Allocation.createFromBitmapResource(mRS, mRes, R.drawable.home_button_normal, Element.RGBA_8888(mRS), false); mHomeButtonNormal.uploadToTexture(0); mHomeButtonFocused = Allocation.createFromBitmapResource(mRS, mRes, R.drawable.home_button_focused, Element.RGBA_8888(mRS), false); mHomeButtonFocused.uploadToTexture(0); mHomeButtonPressed = Allocation.createFromBitmapResource(mRS, mRes, R.drawable.home_button_pressed, Element.RGBA_8888(mRS), false); mHomeButtonPressed.uploadToTexture(0); mParams.homeButtonWidth = 76; mParams.homeButtonHeight = 68; mParams.homeButtonTextureWidth = 128; mParams.homeButtonTextureHeight = 128; mState.homeButtonId = mHomeButtonNormal.getID(); mParams.save(); mState.save(); mSelectionBitmap = Bitmap.createBitmap(Defines.ICON_TEXTURE_WIDTH_PX, Defines.ICON_TEXTURE_HEIGHT_PX, Bitmap.Config.ARGB_8888); mSelectionCanvas = new Canvas(mSelectionBitmap); setApps(null); } private void initScript(int id) { } private void initRs() { ScriptC.Builder sb = new ScriptC.Builder(mRS); sb.setScript(mRes, R.raw.rollo3); sb.setRoot(true); sb.addDefines(mDefines); sb.setType(mParams.mType, "params", Defines.ALLOC_PARAMS); sb.setType(mState.mType, "state", Defines.ALLOC_STATE); mInvokeMove = sb.addInvokable("move"); mInvokeFling = sb.addInvokable("fling"); mInvokeMoveTo = sb.addInvokable("moveTo"); mInvokeResetWAR = sb.addInvokable("resetHWWar"); mScript = sb.create(); mScript.setClearColor(0.0f, 0.0f, 0.0f, 0.0f); mScript.bindAllocation(mParams.mAlloc, Defines.ALLOC_PARAMS); mScript.bindAllocation(mState.mAlloc, Defines.ALLOC_STATE); mScript.bindAllocation(mAllocIconIds, Defines.ALLOC_ICON_IDS); mScript.bindAllocation(mAllocLabelIds, Defines.ALLOC_LABEL_IDS); mMessageProc = new AAMessage(); mRS.mMessageCallback = mMessageProc; mRS.contextBindRootScript(mScript); } private void uploadApps(ArrayList list) { for (int i=0; i < mState.iconCount; i++) { uploadAppIcon(i, list.get(i)); } } void dirtyCheck() { if (mAppsDirty && mHasSurface) { uploadApps(mAllAppsList); saveAppsList(); mAppsDirty = false; } } private void setApps(ArrayList list) { final int count = list != null ? list.size() : 0; int allocCount = count; if (allocCount < 1) { allocCount = 1; } mIcons = new Allocation[count]; mIconIds = new int[allocCount]; mAllocIconIds = Allocation.createSized(mRS, Element.USER_I32(mRS), allocCount); mLabels = new Allocation[count]; mLabelIds = new int[allocCount]; mAllocLabelIds = Allocation.createSized(mRS, Element.USER_I32(mRS), allocCount); Element ie8888 = Element.RGBA_8888(mRS); Utilities.BubbleText bubble = new Utilities.BubbleText(getContext()); mState.iconCount = count; uploadApps(list); saveAppsList(); } private void frameBitmapAllocMips(Allocation alloc, int w, int h) { int black[] = new int[w > h ? w : h]; Allocation.Adapter2D a = alloc.createAdapter2D(); int mip = 0; while (w > 1 || h > 1) { a.subData(0, 0, 1, h, black); a.subData(w-1, 0, 1, h, black); a.subData(0, 0, w, 1, black); a.subData(0, h-1, w, 1, black); mip++; w = (w + 1) >> 1; h = (h + 1) >> 1; a.setConstraint(Dimension.LOD, mip); } a.subData(0, 0, 1, 1, black); } private void uploadAppIcon(int index, ApplicationInfo item) { mIcons[index] = Allocation.createFromBitmap(mRS, item.iconBitmap, Element.RGBA_8888(mRS), true); frameBitmapAllocMips(mIcons[index], item.iconBitmap.getWidth(), item.iconBitmap.getHeight()); mLabels[index] = Allocation.createFromBitmap(mRS, item.titleBitmap, Element.RGBA_8888(mRS), true); frameBitmapAllocMips(mLabels[index], item.titleBitmap.getWidth(), item.titleBitmap.getHeight()); mIcons[index].uploadToTexture(0); mLabels[index].uploadToTexture(0); mIconIds[index] = mIcons[index].getID(); mLabelIds[index] = mLabels[index].getID(); } /** * Puts the empty spaces at the end. Updates mState.iconCount. You must * fill in the values and call saveAppsList(). */ private void reallocAppsList(int count) { Allocation[] icons = new Allocation[count]; int[] iconIds = new int[count]; mAllocIconIds = Allocation.createSized(mRS, Element.USER_I32(mRS), count); Allocation[] labels = new Allocation[count]; int[] labelIds = new int[count]; mAllocLabelIds = Allocation.createSized(mRS, Element.USER_I32(mRS), count); final int oldCount = mIcons.length; System.arraycopy(mIcons, 0, icons, 0, oldCount); System.arraycopy(mIconIds, 0, iconIds, 0, oldCount); System.arraycopy(mLabels, 0, labels, 0, oldCount); System.arraycopy(mLabelIds, 0, labelIds, 0, oldCount); mIcons = icons; mIconIds = iconIds; mLabels = labels; mLabelIds = labelIds; } /** * Handle the allocations for the new app. Make sure you call saveAppsList when done. */ private void addApp(int index, ApplicationInfo item) { final int count = mState.iconCount - index; final int dest = index + 1; System.arraycopy(mIcons, index, mIcons, dest, count); System.arraycopy(mIconIds, index, mIconIds, dest, count); System.arraycopy(mLabels, index, mLabels, dest, count); System.arraycopy(mLabelIds, index, mLabelIds, dest, count); if (mHasSurface ) { uploadAppIcon(index, item); } else { mAppsDirty = true; } } /** * Handle the allocations for the removed app. Make sure you call saveAppsList when done. */ private void removeApp(int index) { final int count = mState.iconCount - index - 1; final int src = index + 1; System.arraycopy(mIcons, src, mIcons, index, count); System.arraycopy(mIconIds, src, mIconIds, index, count); System.arraycopy(mLabels, src, mLabels, index, count); System.arraycopy(mLabelIds, src, mLabelIds, index, count); final int last = mState.iconCount - 1; mIcons[last] = null; mIconIds[last] = 0; mLabels[last] = null; mLabelIds[last] = 0; } /** * Send the apps list structures to RS. */ private void saveAppsList() { mRS.contextBindRootScript(null); mAllocIconIds.data(mIconIds); mAllocLabelIds.data(mLabelIds); if (mScript != null) { // this happens when we init it mScript.bindAllocation(mAllocIconIds, Defines.ALLOC_ICON_IDS); mScript.bindAllocation(mAllocLabelIds, Defines.ALLOC_LABEL_IDS); } mState.save(); // Note: mScript may be null if we haven't initialized it yet. // In that case, this is a no-op. if (mInvokeResetWAR != null) { mInvokeResetWAR.execute(); } mRS.contextBindRootScript(mScript); } void initTouchState() { int width = getWidth(); int height = getHeight(); int cellHeight = 145;//iconsSize / Defines.ROWS_PER_PAGE; int cellWidth = width / Defines.COLUMNS_PER_PAGE; int centerY = (height / 2); mTouchYBorders[0] = centerY - (cellHeight * 2); mTouchYBorders[1] = centerY - cellHeight; mTouchYBorders[2] = centerY; mTouchYBorders[3] = centerY + cellHeight; mTouchYBorders[4] = centerY + (cellHeight * 2); int centerX = (width / 2); mTouchXBorders[0] = 0; mTouchXBorders[1] = centerX - (width / 4); mTouchXBorders[2] = centerX; mTouchXBorders[3] = centerX + (width / 4); mTouchXBorders[4] = width; } void fling() { mInvokeFling.execute(); } void move() { mInvokeMove.execute(); } void moveTo(float row) { mState.targetPos = row; mState.save(); mInvokeMoveTo.execute(); } int chooseTappedIcon(int x, int y, float pos) { // Adjust for scroll position if not zero. y += (pos - ((int)pos)) * (mTouchYBorders[1] - mTouchYBorders[0]); int col = -1; int row = -1; for (int i=0; i= mTouchXBorders[i] && x < mTouchXBorders[i+1]) { col = i; break; } } for (int i=0; i= mTouchYBorders[i] && y < mTouchYBorders[i+1]) { row = i; break; } } if (row < 0 || col < 0) { return -1; } int index = (((int)pos) * Defines.COLUMNS_PER_PAGE) + (row * Defines.ROWS_PER_PAGE) + col; if (index >= mState.iconCount) { return -1; } else { return index; } } /** * You need to call save() on mState on your own after calling this. * * @return the index of the icon that was selected. */ int selectIcon(int x, int y, float pos, int pressed) { final int index = chooseTappedIcon(x, y, pos); selectIcon(index, pressed); return index; } /** * Select the icon at the given index. * * @param index The index. * @param pressed one of SELECTED_PRESSED or SELECTED_FOCUSED */ void selectIcon(int index, int pressed) { if (mAllAppsList == null || index < 0 || index >= mAllAppsList.size()) { mState.selectedIconIndex = -1; if (mLastSelection == SELECTION_ICONS) { mLastSelection = SELECTION_NONE; } } else { if (pressed == SELECTED_FOCUSED) { mLastSelection = SELECTION_ICONS; } mState.selectedIconIndex = index; Bitmap selectionBitmap = mSelectionBitmap; Utilities.drawSelectedAllAppsBitmap(mSelectionCanvas, selectionBitmap.getWidth(), selectionBitmap.getHeight(), pressed == SELECTED_PRESSED, mAllAppsList.get(index).iconBitmap); mSelectedIcon = Allocation.createFromBitmap(mRS, selectionBitmap, Element.RGBA_8888(mRS), false); mSelectedIcon.uploadToTexture(0); mState.selectedIconTexture = mSelectedIcon.getID(); } } /** * You need to call save() on mState on your own after calling this. */ void clearSelectedIcon() { mState.selectedIconIndex = -1; } void setHomeSelected(int mode) { switch (mode) { case SELECTED_NONE: mState.homeButtonId = mHomeButtonNormal.getID(); break; case SELECTED_FOCUSED: mLastSelection = SELECTION_HOME; mState.homeButtonId = mHomeButtonFocused.getID(); break; case SELECTED_PRESSED: mState.homeButtonId = mHomeButtonPressed.getID(); break; } } } }