summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/com/android/launcher2/AllApps2D.java40
-rw-r--r--src/com/android/launcher2/AllApps3D.java392
-rw-r--r--src/com/android/launcher2/AllAppsList.java9
-rw-r--r--src/com/android/launcher2/AllAppsTabbed.java124
-rw-r--r--src/com/android/launcher2/ApplicationInfo.java7
-rw-r--r--src/com/android/launcher2/CellLayout.java648
-rw-r--r--src/com/android/launcher2/DeferredHandler.java5
-rw-r--r--src/com/android/launcher2/DeleteZone.java6
-rw-r--r--src/com/android/launcher2/DragController.java21
-rw-r--r--src/com/android/launcher2/DragLayer.java6
-rw-r--r--src/com/android/launcher2/DragView.java5
-rw-r--r--src/com/android/launcher2/DropTarget.java20
-rw-r--r--src/com/android/launcher2/Folder.java4
-rw-r--r--src/com/android/launcher2/FolderChooser.java37
-rw-r--r--src/com/android/launcher2/FolderIcon.java10
-rw-r--r--src/com/android/launcher2/FolderListAdapter.java20
-rw-r--r--src/com/android/launcher2/HomeCustomizationItemGallery.java50
-rw-r--r--src/com/android/launcher2/InstallShortcutReceiver.java38
-rw-r--r--src/com/android/launcher2/IntentListAdapter.java67
-rw-r--r--src/com/android/launcher2/ItemInfo.java5
-rw-r--r--src/com/android/launcher2/Launcher.java344
-rw-r--r--src/com/android/launcher2/LauncherAppWidgetInfo.java30
-rw-r--r--src/com/android/launcher2/LauncherApplication.java12
-rw-r--r--src/com/android/launcher2/LauncherModel.java200
-rw-r--r--src/com/android/launcher2/LauncherModelOrientationHelper.java180
-rw-r--r--src/com/android/launcher2/LiveFolderInfo.java1
-rw-r--r--src/com/android/launcher2/ShortcutChooser.java37
-rw-r--r--src/com/android/launcher2/ShortcutInfo.java6
-rw-r--r--src/com/android/launcher2/ShortcutListAdapter.java26
-rw-r--r--src/com/android/launcher2/ShortcutsAdapter.java5
-rw-r--r--src/com/android/launcher2/SymmetricalLinearTween.java2
-rw-r--r--src/com/android/launcher2/UserFolder.java8
-rw-r--r--src/com/android/launcher2/Utilities.java13
-rw-r--r--src/com/android/launcher2/WidgetChooser.java47
-rw-r--r--src/com/android/launcher2/WidgetListAdapter.java131
-rw-r--r--src/com/android/launcher2/Workspace.java517
-rw-r--r--src/com/android/launcher2/allapps.rs390
37 files changed, 2619 insertions, 844 deletions
diff --git a/src/com/android/launcher2/AllApps2D.java b/src/com/android/launcher2/AllApps2D.java
index 7ad5e49..b993364 100644
--- a/src/com/android/launcher2/AllApps2D.java
+++ b/src/com/android/launcher2/AllApps2D.java
@@ -16,32 +16,32 @@
package com.android.launcher2;
+import com.android.launcher.R;
+
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Resources;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.Bitmap;
-import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
-import android.view.ViewGroup;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
-import android.view.ViewConfiguration;
import android.widget.AdapterView;
-import android.widget.ImageButton;
-import android.widget.TextView;
import android.widget.ArrayAdapter;
import android.widget.GridView;
+import android.widget.ImageButton;
import android.widget.RelativeLayout;
+import android.widget.TextView;
import java.util.ArrayList;
import java.util.Collections;
-import com.android.launcher.R;
-
public class AllApps2D
extends RelativeLayout
implements AllAppsView,
@@ -68,6 +68,8 @@ public class AllApps2D
private AppsAdapter mAppsAdapter;
+ private boolean mIsViewOpaque;
+
// ------------------------------------------------------------
public static class HomeButton extends ImageButton {
@@ -126,24 +128,24 @@ public class AllApps2D
@Override
protected void onFinishInflate() {
- setBackgroundColor(Color.BLACK);
+ mIsViewOpaque = super.isOpaque();
try {
mGrid = (GridView)findViewWithTag("all_apps_2d_grid");
if (mGrid == null) throw new Resources.NotFoundException();
mGrid.setOnItemClickListener(this);
mGrid.setOnItemLongClickListener(this);
- mGrid.setBackgroundColor(Color.BLACK);
- mGrid.setCacheColorHint(Color.BLACK);
+ // The home button is optional; some layouts might not use it
ImageButton homeButton = (ImageButton) findViewWithTag("all_apps_2d_home");
- if (homeButton == null) throw new Resources.NotFoundException();
- homeButton.setOnClickListener(
- new View.OnClickListener() {
- public void onClick(View v) {
- mLauncher.closeAllApps(true);
- }
- });
+ if (homeButton != null) {
+ homeButton.setOnClickListener(
+ new View.OnClickListener() {
+ public void onClick(View v) {
+ mLauncher.closeAllApps(true);
+ }
+ });
+ }
} catch (Resources.NotFoundException e) {
Log.e(TAG, "Can't find necessary layout elements for AllApps2D");
}
@@ -252,7 +254,7 @@ public class AllApps2D
@Override
public boolean isOpaque() {
- return mZoom > 0.999f;
+ return mIsViewOpaque && mZoom > 0.999f;
}
public void setApps(ArrayList<ApplicationInfo> list) {
diff --git a/src/com/android/launcher2/AllApps3D.java b/src/com/android/launcher2/AllApps3D.java
index b8aa8ec..bb18870 100644
--- a/src/com/android/launcher2/AllApps3D.java
+++ b/src/com/android/launcher2/AllApps3D.java
@@ -16,6 +16,10 @@
package com.android.launcher2;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Resources;
@@ -29,12 +33,10 @@ import android.renderscript.ProgramFragment;
import android.renderscript.ProgramStore;
import android.renderscript.ProgramVertex;
import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScriptGL;
import android.renderscript.RenderScript;
+import android.renderscript.RenderScriptGL;
import android.renderscript.Sampler;
-import android.renderscript.Script;
-import android.renderscript.ScriptC;
-import android.renderscript.SimpleMesh;
+import android.renderscript.Mesh;
import android.renderscript.Type;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
@@ -48,10 +50,6 @@ import android.view.View;
import android.view.ViewConfiguration;
import android.view.accessibility.AccessibilityEvent;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-
import com.android.launcher.R;
public class AllApps3D extends RSSurfaceView
@@ -131,27 +129,16 @@ public class AllApps3D extends RSSurfaceView
private boolean mSurrendered;
private int mRestoreFocusIndex = -1;
-
+
@SuppressWarnings({"UnusedDeclaration"})
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 ALLOC_VP_CONSTANTS = 5;
-
public static final int COLUMNS_PER_PAGE_PORTRAIT = 4;
public static final int ROWS_PER_PAGE_PORTRAIT = 4;
public static final int COLUMNS_PER_PAGE_LANDSCAPE = 6;
public static final int ROWS_PER_PAGE_LANDSCAPE = 3;
- public static final int ICON_WIDTH_PX = 64;
- public static final int ICON_TEXTURE_WIDTH_PX = 74;
public static final int SELECTION_TEXTURE_WIDTH_PX = 74 + 20;
-
- public static final int ICON_HEIGHT_PX = 64;
- public static final int ICON_TEXTURE_HEIGHT_PX = 74;
public static final int SELECTION_TEXTURE_HEIGHT_PX = 74 + 20;
}
@@ -159,7 +146,6 @@ public class AllApps3D extends RSSurfaceView
super(context, attrs);
setFocusable(true);
setSoundEffectsEnabled(false);
- getHolder().setFormat(PixelFormat.TRANSLUCENT);
final ViewConfiguration config = ViewConfiguration.get(context);
mSlop = config.getScaledTouchSlop();
mMaxFlingVelocity = config.getScaledMaximumFlingVelocity();
@@ -274,24 +260,25 @@ public class AllApps3D extends RSSurfaceView
sRollo.dirtyCheck();
sRollo.resize(w, h);
+ Log.d(TAG, "sc " + sRS);
if (sRS != null) {
sRS.mMessageCallback = mMessageProc = new AAMessage();
}
if (sRollo.mUniformAlloc != null) {
- float tf[] = new float[] {72.f, 72.f,
- 120.f, 120.f, 0.f, 0.f,
- 120.f, 680.f,
- (2.f / 480.f), 0, -((float)w / 2) - 0.25f, -380.25f};
+ ScriptField_VpConsts.Item i = new ScriptField_VpConsts.Item();
+ i.ScaleOffset.x = (2.f / 480.f);
+ i.ScaleOffset.y = 0;
+ i.ScaleOffset.z = -((float)w / 2) - 0.25f;
+ i.ScaleOffset.w = -380.25f;
+ i.BendPos.x = 120.f;
+ i.BendPos.y = 680.f;
if (w > h) {
- tf[6] = 40.f;
- tf[7] = h - 40.f;
- tf[9] = 1.f;
- tf[10] = -((float)w / 2) - 0.25f;
- tf[11] = -((float)h / 2) - 0.25f;
+ i.ScaleOffset.z = 40.f;
+ i.ScaleOffset.w = h - 40.f;
+ i.BendPos.y = 1.f;
}
-
- sRollo.mUniformAlloc.data(tf);
+ sRollo.mUniformAlloc.set(i, 0, true);
}
//long endTime = SystemClock.uptimeMillis();
@@ -307,18 +294,17 @@ public class AllApps3D extends RSSurfaceView
if (mArrowNavigation) {
if (!hasWindowFocus) {
// Clear selection when we lose window focus
- mLastSelectedIcon = sRollo.mState.selectedIconIndex;
+ mLastSelectedIcon = sRollo.mScript.get_gSelectedIconIndex();
sRollo.setHomeSelected(SELECTED_NONE);
sRollo.clearSelectedIcon();
- sRollo.mState.save();
} else {
- if (sRollo.mState.iconCount > 0) {
+ if (sRollo.mScript.get_gIconCount() > 0) {
if (mLastSelection == SELECTION_ICONS) {
int selection = mLastSelectedIcon;
final int firstIcon = Math.round(sRollo.mScrollPos) * mColumnsPerPage;
if (selection < 0 || // No selection
selection < firstIcon || // off the top of the screen
- selection >= sRollo.mState.iconCount || // past last icon
+ selection >= sRollo.mScript.get_gIconCount() || // past last icon
selection >= firstIcon + // past last icon on screen
(mColumnsPerPage * mRowsPerPage)) {
selection = firstIcon;
@@ -326,10 +312,8 @@ public class AllApps3D extends RSSurfaceView
// Select the first icon when we gain window focus
sRollo.selectIcon(selection, SELECTED_FOCUSED);
- sRollo.mState.save();
} else if (mLastSelection == SELECTION_HOME) {
sRollo.setHomeSelected(SELECTED_FOCUSED);
- sRollo.mState.save();
}
}
}
@@ -356,7 +340,6 @@ public class AllApps3D extends RSSurfaceView
// Clear selection when we lose focus
sRollo.clearSelectedIcon();
sRollo.setHomeSelected(SELECTED_NONE);
- sRollo.mState.save();
mArrowNavigation = false;
}
} else {
@@ -366,11 +349,10 @@ public class AllApps3D extends RSSurfaceView
}
private void gainFocus() {
- if (!mArrowNavigation && sRollo.mState.iconCount > 0) {
+ if (!mArrowNavigation && sRollo.mScript.get_gIconCount() > 0) {
// Select the first icon when we gain keyboard focus
mArrowNavigation = true;
sRollo.selectIcon(Math.round(sRollo.mScrollPos) * mColumnsPerPage, SELECTED_FOCUSED);
- sRollo.mState.save();
}
}
@@ -382,7 +364,7 @@ public class AllApps3D extends RSSurfaceView
if (!isVisible()) {
return false;
}
- final int iconCount = sRollo.mState.iconCount;
+ final int iconCount = sRollo.mScript.get_gIconCount();
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_ENTER) {
if (mArrowNavigation) {
@@ -390,7 +372,7 @@ public class AllApps3D extends RSSurfaceView
reallyPlaySoundEffect(SoundEffectConstants.CLICK);
mLauncher.closeAllApps(true);
} else {
- int whichApp = sRollo.mState.selectedIconIndex;
+ int whichApp = sRollo.mScript.get_gSelectedIconIndex();
if (whichApp >= 0) {
ApplicationInfo app = mAllAppsList.get(whichApp);
mLauncher.startActivitySafely(app.intent, app);
@@ -402,10 +384,10 @@ public class AllApps3D extends RSSurfaceView
if (iconCount > 0) {
final boolean isPortrait = getWidth() < getHeight();
-
+
mArrowNavigation = true;
- int currentSelection = sRollo.mState.selectedIconIndex;
+ int currentSelection = sRollo.mScript.get_gSelectedIconIndex();
int currentTopRow = Math.round(sRollo.mScrollPos);
// The column of the current selection, in the range 0..COLUMNS_PER_PAGE_PORTRAIT-1
@@ -511,7 +493,6 @@ public class AllApps3D extends RSSurfaceView
}
if (newSelection != currentSelection) {
sRollo.selectIcon(newSelection, SELECTED_FOCUSED);
- sRollo.mState.save();
}
}
return handled;
@@ -611,7 +592,6 @@ public class AllApps3D extends RSSurfaceView
(!isPortrait && x > mTouchXBorders[mTouchXBorders.length-1])) {
mTouchTracking = TRACKING_HOME;
sRollo.setHomeSelected(SELECTED_PRESSED);
- sRollo.mState.save();
mCurrentIconIndex = -1;
} else {
mTouchTracking = TRACKING_FLING;
@@ -619,9 +599,6 @@ public class AllApps3D extends RSSurfaceView
mMotionDownRawX = (int)ev.getRawX();
mMotionDownRawY = (int)ev.getRawY();
- sRollo.mState.newPositionX = ev.getRawY() / getHeight();
- sRollo.mState.newTouchDown = 1;
-
if (!sRollo.checkClickOK()) {
sRollo.clearSelectedIcon();
} else {
@@ -632,8 +609,7 @@ public class AllApps3D extends RSSurfaceView
cancelLongPress();
}
}
- sRollo.mState.save();
- sRollo.move();
+ sRollo.move(ev.getRawY() / getHeight());
mVelocityTracker = VelocityTracker.obtain();
mVelocityTracker.addMovement(ev);
mStartedScrolling = false;
@@ -646,7 +622,6 @@ public class AllApps3D extends RSSurfaceView
y > mTouchYBorders[mTouchYBorders.length-1]) || (!isPortrait
&& x > mTouchXBorders[mTouchXBorders.length-1])
? SELECTED_PRESSED : SELECTED_NONE);
- sRollo.mState.save();
} else if (mTouchTracking == TRACKING_FLING) {
int rawY = (int)ev.getRawY();
int slop;
@@ -667,14 +642,11 @@ public class AllApps3D extends RSSurfaceView
cancelLongPress();
mCurrentIconIndex = -1;
}
- sRollo.mState.newPositionX = ev.getRawY() / getHeight();
- sRollo.mState.newTouchDown = 1;
- sRollo.move();
+ sRollo.move(ev.getRawY() / getHeight());
mStartedScrolling = true;
sRollo.clearSelectedIcon();
mVelocityTracker.addMovement(ev);
- sRollo.mState.save();
}
}
break;
@@ -688,18 +660,13 @@ public class AllApps3D extends RSSurfaceView
mLauncher.closeAllApps(true);
}
sRollo.setHomeSelected(SELECTED_NONE);
- sRollo.mState.save();
}
mCurrentIconIndex = -1;
} else if (mTouchTracking == TRACKING_FLING) {
- sRollo.mState.newTouchDown = 0;
- sRollo.mState.newPositionX = ev.getRawY() / getHeight();
-
mVelocityTracker.computeCurrentVelocity(1000 /* px/sec */, mMaxFlingVelocity);
- sRollo.mState.flingVelocity = mVelocityTracker.getYVelocity() / getHeight();
sRollo.clearSelectedIcon();
- sRollo.mState.save();
- sRollo.fling();
+ sRollo.fling(ev.getRawY() / getHeight(),
+ mVelocityTracker.getYVelocity() / getHeight());
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
@@ -761,7 +728,7 @@ public class AllApps3D extends RSSurfaceView
int pos = -1;
switch (mLastSelection) {
case SELECTION_ICONS:
- index = sRollo.mState.selectedIconIndex;
+ index = sRollo.mScript.get_gSelectedIconIndex();
if (index >= 0) {
ApplicationInfo info = mAllAppsList.get(index);
if (info.title != null) {
@@ -853,13 +820,12 @@ public class AllApps3D extends RSSurfaceView
if (sRollo != null && reload) {
sRollo.setApps(list);
}
-
+
if (hasFocus() && mRestoreFocusIndex != -1) {
sRollo.selectIcon(mRestoreFocusIndex, SELECTED_FOCUSED);
- sRollo.mState.save();
mRestoreFocusIndex = -1;
}
-
+
mLocks &= ~LOCK_ICONS_PENDING;
}
@@ -876,7 +842,7 @@ public class AllApps3D extends RSSurfaceView
final int N = list.size();
if (sRollo != null) {
sRollo.pause();
- sRollo.reallocAppsList(sRollo.mState.iconCount + N);
+ sRollo.reallocAppsList(sRollo.mScript.get_gIconCount() + N);
}
for (int i=0; i<N; i++) {
@@ -946,17 +912,6 @@ public class AllApps3D extends RSSurfaceView
return -1;
}
- /*
- private static int countPages(int iconCount) {
- int iconsPerPage = getColumnsCount() * Defines.ROWS_PER_PAGE_PORTRAIT;
- int pages = iconCount / iconsPerPage;
- if (pages*iconsPerPage != iconCount) {
- pages++;
- }
- return pages;
- }
- */
-
class AAMessage extends RenderScript.RSMessage {
public void run() {
sRollo.mScrollPos = ((float)mData[0]) / (1 << 16);
@@ -988,23 +943,12 @@ public class AllApps3D extends RSSurfaceView
private int mHeight;
private Resources mRes;
- private Script mScript;
- private Script.Invokable mInvokeMove;
- private Script.Invokable mInvokeMoveTo;
- private Script.Invokable mInvokeFling;
- private Script.Invokable mInvokeResetWAR;
- private Script.Invokable mInvokeSetZoom;
-
- private ProgramStore mPSIcons;
- private ProgramFragment mPFTexMip;
- private ProgramFragment mPFTexMipAlpha;
- private ProgramFragment mPFTexNearest;
- private ProgramVertex mPV;
- private ProgramVertex mPVCurve;
- private SimpleMesh mMesh;
+ ScriptC_Allapps mScript;
+
+ private Mesh mMesh;
private ProgramVertex.MatrixAllocation mPVA;
- private Allocation mUniformAlloc;
+ private ScriptField_VpConsts mUniformAlloc;
private Allocation mHomeButtonNormal;
private Allocation mHomeButtonFocused;
@@ -1017,15 +961,11 @@ public class AllApps3D extends RSSurfaceView
private Allocation[] mLabels;
private int[] mLabelIds;
private Allocation mAllocLabelIds;
- private Allocation mSelectedIcon;
private Bitmap mSelectionBitmap;
private Canvas mSelectionCanvas;
-
- private float mScrollPos;
- Params mParams;
- State mState;
+ private float mScrollPos;
AllApps3D mAllApps;
boolean mInitialize;
@@ -1056,41 +996,6 @@ public class AllApps3D extends RSSurfaceView
}
}
- class Params extends BaseAlloc {
- Params() {
- mType = Type.createFromClass(sRS, Params.class, 1, "ParamsClass");
- mAlloc = Allocation.createTyped(sRS, mType);
- save();
- }
- public int bubbleWidth;
- public int bubbleHeight;
- public int bubbleBitmapWidth;
- public int bubbleBitmapHeight;
-
- public int homeButtonWidth;
- public int homeButtonHeight;
- public int homeButtonTextureWidth;
- public int homeButtonTextureHeight;
- }
-
- class State extends BaseAlloc {
- public float newPositionX;
- public int newTouchDown;
- public float flingVelocity;
- public int iconCount;
- public int selectedIconIndex = -1;
- public int selectedIconTexture;
- public float zoomTarget;
- public int homeButtonId;
- public float targetPos;
-
- State() {
- mType = Type.createFromClass(sRS, State.class, 1, "StateClass");
- mAlloc = Allocation.createTyped(sRS, mType);
- save();
- }
- }
-
public RolloRS(AllApps3D allApps) {
mAllApps = allApps;
}
@@ -1099,16 +1004,21 @@ public class AllApps3D extends RSSurfaceView
mRes = res;
mWidth = width;
mHeight = height;
+ mScript = new ScriptC_Allapps(sRS, mRes, R.raw.allapps, true);
+
initProgramVertex();
initProgramFragment();
initProgramStore();
initGl();
initData();
- initRs();
+
+ mScript.bind_gIconIDs(mAllocIconIds);
+ mScript.bind_gLabelIDs(mAllocLabelIds);
+ sRS.contextBindRootScript(mScript);
}
public void initMesh() {
- SimpleMesh.TriangleMeshBuilder tm = new SimpleMesh.TriangleMeshBuilder(sRS, 2, 0);
+ Mesh.TriangleMeshBuilder tm = new Mesh.TriangleMeshBuilder(sRS, 2, 0);
for (int ct=0; ct < 16; ct++) {
float pos = (1.f / (16.f - 1)) * ct;
@@ -1119,8 +1029,8 @@ public class AllApps3D extends RSSurfaceView
tm.addTriangle(ct, ct+1, ct+2);
tm.addTriangle(ct+1, ct+3, ct+2);
}
- mMesh = tm.create();
- mMesh.setName("SMCell");
+ mMesh = tm.create(true);
+ mScript.set_gSMCell(mMesh);
}
void resize(int w, int h) {
@@ -1135,18 +1045,12 @@ public class AllApps3D extends RSSurfaceView
ProgramVertex.Builder pvb = new ProgramVertex.Builder(sRS, null, null);
pvb.setTextureMatrixEnable(true);
- mPV = pvb.create();
- mPV.setName("PV");
- mPV.bindAllocation(mPVA);
-
- Element.Builder eb = new Element.Builder(sRS);
- eb.add(Element.createVector(sRS, Element.DataType.FLOAT_32, 2), "ImgSize");
- eb.add(Element.createVector(sRS, Element.DataType.FLOAT_32, 4), "Position");
- eb.add(Element.createVector(sRS, Element.DataType.FLOAT_32, 2), "BendPos");
- eb.add(Element.createVector(sRS, Element.DataType.FLOAT_32, 4), "ScaleOffset");
- Element e = eb.create();
+ ProgramVertex pv = pvb.create();
+ pv.bindAllocation(mPVA);
+ sRS.contextBindProgramVertex(pv);
- mUniformAlloc = Allocation.createSized(sRS, e, 1);
+ mUniformAlloc = new ScriptField_VpConsts(sRS, 1);
+ mScript.bind_vpConstants(mUniformAlloc);
initMesh();
ProgramVertex.ShaderBuilder sb = new ProgramVertex.ShaderBuilder(sRS);
@@ -1208,13 +1112,12 @@ public class AllApps3D extends RSSurfaceView
"}\n";
sb.setShader(t);
sb.addConstant(mUniformAlloc.getType());
- sb.addInput(mMesh.getVertexType(0).getElement());
- mPVCurve = sb.create();
- mPVCurve.setName("PVCurve");
- mPVCurve.bindAllocation(mPVA);
- mPVCurve.bindConstants(mUniformAlloc, 1);
+ sb.addInput(mMesh.getVertexAllocation(0).getType().getElement());
+ ProgramVertex pvc = sb.create();
+ pvc.bindAllocation(mPVA);
+ pvc.bindConstants(mUniformAlloc.getAllocation(), 1);
- sRS.contextBindProgramVertex(mPV);
+ mScript.set_gPVCurve(pvc);
}
private void initProgramFragment() {
@@ -1232,20 +1135,20 @@ public class AllApps3D extends RSSurfaceView
ProgramFragment.Builder bf = new ProgramFragment.Builder(sRS);
bf.setTexture(ProgramFragment.Builder.EnvMode.MODULATE,
ProgramFragment.Builder.Format.RGBA, 0);
- mPFTexMip = bf.create();
- mPFTexMip.setName("PFTexMip");
- mPFTexMip.bindSampler(linear, 0);
+ ProgramFragment pfTexMip = bf.create();
+ pfTexMip.bindSampler(linear, 0);
- mPFTexNearest = bf.create();
- mPFTexNearest.setName("PFTexNearest");
- mPFTexNearest.bindSampler(nearest, 0);
+ ProgramFragment pfTexNearest = bf.create();
+ pfTexNearest.bindSampler(nearest, 0);
bf.setTexture(ProgramFragment.Builder.EnvMode.MODULATE,
ProgramFragment.Builder.Format.ALPHA, 0);
- mPFTexMipAlpha = bf.create();
- mPFTexMipAlpha.setName("PFTexMipAlpha");
- mPFTexMipAlpha.bindSampler(linear, 0);
+ ProgramFragment pfTexMipAlpha = bf.create();
+ pfTexMipAlpha.bindSampler(linear, 0);
+ mScript.set_gPFTexNearest(pfTexNearest);
+ mScript.set_gPFTexMip(pfTexMip);
+ mScript.set_gPFTexMipAlpha(pfTexMipAlpha);
}
private void initProgramStore() {
@@ -1255,23 +1158,17 @@ public class AllApps3D extends RSSurfaceView
bs.setDitherEnable(true);
bs.setBlendFunc(ProgramStore.BlendSrcFunc.SRC_ALPHA,
ProgramStore.BlendDstFunc.ONE_MINUS_SRC_ALPHA);
- mPSIcons = bs.create();
- mPSIcons.setName("PSIcons");
+ mScript.set_gPS(bs.create());
}
private void initGl() {
}
private void initData() {
- mParams = new Params();
- mState = new State();
-
- final Utilities.BubbleText bubble = new Utilities.BubbleText(mAllApps.getContext());
-
- mParams.bubbleWidth = bubble.getBubbleWidth();
- mParams.bubbleHeight = bubble.getMaxBubbleHeight();
- mParams.bubbleBitmapWidth = bubble.getBitmapWidth();
- mParams.bubbleBitmapHeight = bubble.getBitmapHeight();
+ mScript.set_COLUMNS_PER_PAGE_PORTRAIT(Defines.COLUMNS_PER_PAGE_PORTRAIT);
+ mScript.set_ROWS_PER_PAGE_PORTRAIT(Defines.ROWS_PER_PAGE_PORTRAIT);
+ mScript.set_COLUMNS_PER_PAGE_LANDSCAPE(Defines.COLUMNS_PER_PAGE_LANDSCAPE);
+ mScript.set_ROWS_PER_PAGE_LANDSCAPE(Defines.ROWS_PER_PAGE_LANDSCAPE);
mHomeButtonNormal = Allocation.createFromBitmapResource(sRS, mRes,
R.drawable.home_button_normal, Element.RGBA_8888(sRS), false);
@@ -1282,15 +1179,8 @@ public class AllApps3D extends RSSurfaceView
mHomeButtonPressed = Allocation.createFromBitmapResource(sRS, mRes,
R.drawable.home_button_pressed, Element.RGBA_8888(sRS), false);
mHomeButtonPressed.uploadToTexture(0);
- mParams.homeButtonWidth = 76;
- mParams.homeButtonHeight = 68;
- mParams.homeButtonTextureWidth = 128;
- mParams.homeButtonTextureHeight = 128;
-
- mState.homeButtonId = mHomeButtonNormal.getID();
- mParams.save();
- mState.save();
+ mScript.set_gHomeButton(mHomeButtonNormal);
mSelectionBitmap = Bitmap.createBitmap(Defines.SELECTION_TEXTURE_WIDTH_PX,
Defines.SELECTION_TEXTURE_HEIGHT_PX, Bitmap.Config.ARGB_8888);
@@ -1299,30 +1189,6 @@ public class AllApps3D extends RSSurfaceView
setApps(null);
}
- private void initRs() {
- ScriptC.Builder sb = new ScriptC.Builder(sRS);
- sb.setScript(mRes, R.raw.allapps);
- sb.setRoot(true);
- sb.addDefines(mAllApps.mDefines);
- sb.setType(mParams.mType, "params", Defines.ALLOC_PARAMS);
- sb.setType(mState.mType, "state", Defines.ALLOC_STATE);
- sb.setType(mUniformAlloc.getType(), "vpConstants", Defines.ALLOC_VP_CONSTANTS);
- mInvokeMove = sb.addInvokable("move");
- mInvokeFling = sb.addInvokable("fling");
- mInvokeMoveTo = sb.addInvokable("moveTo");
- mInvokeResetWAR = sb.addInvokable("resetHWWar");
- mInvokeSetZoom = sb.addInvokable("setZoom");
- 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);
- mScript.bindAllocation(mUniformAlloc, Defines.ALLOC_VP_CONSTANTS);
-
- sRS.contextBindRootScript(mScript);
- }
-
void dirtyCheck() {
if (sZoomDirty) {
setZoom(mAllApps.sNextZoom, mAllApps.sAnimateNextZoom);
@@ -1340,20 +1206,21 @@ public class AllApps3D extends RSSurfaceView
mIcons = new Allocation[count];
mIconIds = new int[allocCount];
- mAllocIconIds = Allocation.createSized(sRS, Element.USER_I32(sRS), allocCount);
+ mAllocIconIds = Allocation.createSized(sRS, Element.I32(sRS), allocCount);
mLabels = new Allocation[count];
mLabelIds = new int[allocCount];
- mAllocLabelIds = Allocation.createSized(sRS, Element.USER_I32(sRS), allocCount);
+ mAllocLabelIds = Allocation.createSized(sRS, Element.I32(sRS), allocCount);
- mState.iconCount = count;
- for (int i=0; i < mState.iconCount; i++) {
+ mScript.set_gIconCount(count);
+ for (int i=0; i < count; i++) {
createAppIconAllocations(i, list.get(i));
}
- for (int i=0; i < mState.iconCount; i++) {
+ for (int i=0; i < count; i++) {
uploadAppIcon(i, list.get(i));
}
saveAppsList();
+ android.util.Log.e("rs", "setApps");
sRollo.resume();
}
@@ -1362,15 +1229,7 @@ public class AllApps3D extends RSSurfaceView
sRollo.clearSelectedIcon();
sRollo.setHomeSelected(SELECTED_NONE);
}
- if (zoom > 0.001f) {
- sRollo.mState.zoomTarget = zoom;
- } else {
- sRollo.mState.zoomTarget = 0;
- }
- sRollo.mState.save();
- if (!animate) {
- sRollo.mInvokeSetZoom.execute();
- }
+ sRollo.mScript.invoke_setZoom(zoom, animate ? 1 : 0);
}
private void createAppIconAllocations(int index, ApplicationInfo item) {
@@ -1400,13 +1259,13 @@ public class AllApps3D extends RSSurfaceView
private void reallocAppsList(int count) {
Allocation[] icons = new Allocation[count];
int[] iconIds = new int[count];
- mAllocIconIds = Allocation.createSized(sRS, Element.USER_I32(sRS), count);
+ mAllocIconIds = Allocation.createSized(sRS, Element.I32(sRS), count);
Allocation[] labels = new Allocation[count];
int[] labelIds = new int[count];
- mAllocLabelIds = Allocation.createSized(sRS, Element.USER_I32(sRS), count);
+ mAllocLabelIds = Allocation.createSized(sRS, Element.I32(sRS), count);
- final int oldCount = sRollo.mState.iconCount;
+ final int oldCount = sRollo.mScript.get_gIconCount();
System.arraycopy(mIcons, 0, icons, 0, oldCount);
System.arraycopy(mIconIds, 0, iconIds, 0, oldCount);
@@ -1423,7 +1282,7 @@ public class AllApps3D extends RSSurfaceView
* 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 count = mScript.get_gIconCount() - index;
final int dest = index + 1;
System.arraycopy(mIcons, index, mIcons, dest, count);
@@ -1433,14 +1292,15 @@ public class AllApps3D extends RSSurfaceView
createAppIconAllocations(index, item);
uploadAppIcon(index, item);
- sRollo.mState.iconCount++;
+
+ mScript.set_gIconCount(mScript.get_gIconCount() + 1);
}
/**
* 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 count = mScript.get_gIconCount() - index - 1;
final int src = index + 1;
System.arraycopy(mIcons, src, mIcons, index, count);
@@ -1448,8 +1308,8 @@ public class AllApps3D extends RSSurfaceView
System.arraycopy(mLabels, src, mLabels, index, count);
System.arraycopy(mLabelIds, src, mLabelIds, index, count);
- sRollo.mState.iconCount--;
- final int last = mState.iconCount;
+ mScript.set_gIconCount(mScript.get_gIconCount() - 1);
+ final int last = mScript.get_gIconCount();
mIcons[last] = null;
mIconIds[last] = 0;
@@ -1466,31 +1326,21 @@ public class AllApps3D extends RSSurfaceView
mAllocIconIds.data(mIconIds);
mAllocLabelIds.data(mLabelIds);
- 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();
- }
+ mScript.bind_gIconIDs(mAllocIconIds);
+ mScript.bind_gLabelIDs(mAllocLabelIds);
}
}
- void fling() {
- mInvokeFling.execute();
+ void fling(float pos, float v) {
+ mScript.invoke_fling(pos, v);
}
- void move() {
- mInvokeMove.execute();
+ void move(float pos) {
+ mScript.invoke_move(pos);
}
void moveTo(float row) {
- mState.targetPos = row;
- mState.save();
- mInvokeMoveTo.execute();
+ mScript.invoke_moveTo(row);
}
/**
@@ -1520,7 +1370,7 @@ public class AllApps3D extends RSSurfaceView
if (mAllApps != null) {
mAllApps.mRestoreFocusIndex = index;
}
- mState.selectedIconIndex = -1;
+ mScript.set_gSelectedIconIndex(-1);
if (mAllApps.mLastSelection == SELECTION_ICONS) {
mAllApps.mLastSelection = SELECTION_NONE;
}
@@ -1529,8 +1379,8 @@ public class AllApps3D extends RSSurfaceView
mAllApps.mLastSelection = SELECTION_ICONS;
}
- int prev = mState.selectedIconIndex;
- mState.selectedIconIndex = index;
+ int prev = mScript.get_gSelectedIconIndex();
+ mScript.set_gSelectedIconIndex(index);
ApplicationInfo info = appsList.get(index);
Bitmap selectionBitmap = mSelectionBitmap;
@@ -1539,10 +1389,10 @@ public class AllApps3D extends RSSurfaceView
selectionBitmap.getWidth(), selectionBitmap.getHeight(),
pressed == SELECTED_PRESSED, info.iconBitmap);
- mSelectedIcon = Allocation.createFromBitmap(sRS, selectionBitmap,
+ Allocation si = Allocation.createFromBitmap(sRS, selectionBitmap,
Element.RGBA_8888(sRS), false);
- mSelectedIcon.uploadToTexture(0);
- mState.selectedIconTexture = mSelectedIcon.getID();
+ si.uploadToTexture(0);
+ mScript.set_gSelectedIconTexture(si);
if (prev != index) {
if (info.title != null && info.title.length() > 0) {
@@ -1557,24 +1407,24 @@ public class AllApps3D extends RSSurfaceView
* You need to call save() on mState on your own after calling this.
*/
void clearSelectedIcon() {
- mState.selectedIconIndex = -1;
+ mScript.set_gSelectedIconIndex(-1);
}
void setHomeSelected(int mode) {
final int prev = mAllApps.mLastSelection;
switch (mode) {
case SELECTED_NONE:
- mState.homeButtonId = mHomeButtonNormal.getID();
+ mScript.set_gHomeButton(mHomeButtonNormal);
break;
case SELECTED_FOCUSED:
mAllApps.mLastSelection = SELECTION_HOME;
- mState.homeButtonId = mHomeButtonFocused.getID();
+ mScript.set_gHomeButton(mHomeButtonFocused);
if (prev != SELECTION_HOME) {
mAllApps.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
}
break;
case SELECTED_PRESSED:
- mState.homeButtonId = mHomeButtonPressed.getID();
+ mScript.set_gHomeButton(mHomeButtonPressed);
break;
}
}
@@ -1594,23 +1444,15 @@ public class AllApps3D extends RSSurfaceView
Log.d(TAG, "sRollo.mLabelIds.length=" + mLabelIds.length);
}
Log.d(TAG, "sRollo.mLabelIds=" + Arrays.toString(mLabelIds));
- Log.d(TAG, "sRollo.mState.newPositionX=" + mState.newPositionX);
- Log.d(TAG, "sRollo.mState.newTouchDown=" + mState.newTouchDown);
- Log.d(TAG, "sRollo.mState.flingVelocity=" + mState.flingVelocity);
- Log.d(TAG, "sRollo.mState.iconCount=" + mState.iconCount);
- Log.d(TAG, "sRollo.mState.selectedIconIndex=" + mState.selectedIconIndex);
- Log.d(TAG, "sRollo.mState.selectedIconTexture=" + mState.selectedIconTexture);
- Log.d(TAG, "sRollo.mState.zoomTarget=" + mState.zoomTarget);
- Log.d(TAG, "sRollo.mState.homeButtonId=" + mState.homeButtonId);
- Log.d(TAG, "sRollo.mState.targetPos=" + mState.targetPos);
- Log.d(TAG, "sRollo.mParams.bubbleWidth=" + mParams.bubbleWidth);
- Log.d(TAG, "sRollo.mParams.bubbleHeight=" + mParams.bubbleHeight);
- Log.d(TAG, "sRollo.mParams.bubbleBitmapWidth=" + mParams.bubbleBitmapWidth);
- Log.d(TAG, "sRollo.mParams.bubbleBitmapHeight=" + mParams.bubbleBitmapHeight);
- Log.d(TAG, "sRollo.mParams.homeButtonWidth=" + mParams.homeButtonWidth);
- Log.d(TAG, "sRollo.mParams.homeButtonHeight=" + mParams.homeButtonHeight);
- Log.d(TAG, "sRollo.mParams.homeButtonTextureWidth=" + mParams.homeButtonTextureWidth);
- Log.d(TAG, "sRollo.mParams.homeButtonTextureHeight=" + mParams.homeButtonTextureHeight);
+ //Log.d(TAG, "sRollo.mState.newPositionX=" + mState.newPositionX);
+ //Log.d(TAG, "sRollo.mState.newTouchDown=" + mState.newTouchDown);
+ //Log.d(TAG, "sRollo.mState.flingVelocity=" + mState.flingVelocity);
+ //Log.d(TAG, "sRollo.mState.iconCount=" + mState.iconCount);
+ //Log.d(TAG, "sRollo.mState.selectedIconIndex=" + mState.selectedIconIndex);
+ //Log.d(TAG, "sRollo.mState.selectedIconTexture=" + mState.selectedIconTexture);
+ //Log.d(TAG, "sRollo.mState.zoomTarget=" + mState.zoomTarget);
+ //Log.d(TAG, "sRollo.mState.homeButtonId=" + mState.homeButtonId);
+ //Log.d(TAG, "sRollo.mState.targetPos=" + mState.targetPos);
}
}
@@ -1641,5 +1483,3 @@ public class AllApps3D extends RSSurfaceView
}
}
}
-
-
diff --git a/src/com/android/launcher2/AllAppsList.java b/src/com/android/launcher2/AllAppsList.java
index 3a5baea..e5d8782 100644
--- a/src/com/android/launcher2/AllAppsList.java
+++ b/src/com/android/launcher2/AllAppsList.java
@@ -16,17 +16,16 @@
package com.android.launcher2;
+import java.util.ArrayList;
+import java.util.List;
+
import android.content.ComponentName;
-import android.content.Intent;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
/**
* Stores the list of all applications for the all apps view.
diff --git a/src/com/android/launcher2/AllAppsTabbed.java b/src/com/android/launcher2/AllAppsTabbed.java
new file mode 100644
index 0000000..67293d9
--- /dev/null
+++ b/src/com/android/launcher2/AllAppsTabbed.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2010 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 com.android.launcher.R;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.widget.TabHost;
+
+import java.util.ArrayList;
+
+/**
+ * Implements a tabbed version of AllApps2D.
+ */
+public class AllAppsTabbed extends TabHost implements AllAppsView {
+
+ private static final String TAG = "Launcher.AllAppsTabbed";
+
+ private AllAppsView mAllApps2D;
+
+ public AllAppsTabbed(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ try {
+ mAllApps2D = (AllAppsView)findViewById(R.id.all_apps_2d);
+ if (mAllApps2D == null) throw new Resources.NotFoundException();
+ } catch (Resources.NotFoundException e) {
+ Log.e(TAG, "Can't find necessary layout elements for AllAppsTabbed");
+ }
+ setup();
+
+ // This lets us share the same view between all tabs
+ TabContentFactory contentFactory = new TabContentFactory() {
+ public View createTabContent(String tag) {
+ return (View)mAllApps2D;
+ }
+ };
+
+ // TODO: Make these tabs show the appropriate content (they're no-ops for now)
+ addTab(newTabSpec("apps").setIndicator("All").setContent(contentFactory));
+ addTab(newTabSpec("apps").setIndicator("Apps").setContent(contentFactory));
+ addTab(newTabSpec("apps").setIndicator("Games").setContent(contentFactory));
+ addTab(newTabSpec("apps").setIndicator("Downloaded").setContent(contentFactory));
+
+ setCurrentTab(0);
+ setVisibility(GONE);
+ }
+
+ @Override
+ public void setLauncher(Launcher launcher) {
+ mAllApps2D.setLauncher(launcher);
+ }
+
+ @Override
+ public void setDragController(DragController dragger) {
+ mAllApps2D.setDragController(dragger);
+ }
+
+ @Override
+ public void zoom(float zoom, boolean animate) {
+ // NOTE: animate parameter is ignored for the TabHost itself
+ setVisibility((zoom == 0.0f) ? View.GONE : View.VISIBLE);
+ mAllApps2D.zoom(zoom, animate);
+ bringChildToFront((View)mAllApps2D);
+ getParent().bringChildToFront(this);
+ }
+
+ @Override
+ public boolean isVisible() {
+ return mAllApps2D.isVisible();
+ }
+
+ @Override
+ public void setApps(ArrayList<ApplicationInfo> list) {
+ mAllApps2D.setApps(list);
+ }
+
+ @Override
+ public void addApps(ArrayList<ApplicationInfo> list) {
+ mAllApps2D.addApps(list);
+ }
+
+ @Override
+ public void removeApps(ArrayList<ApplicationInfo> list) {
+ mAllApps2D.removeApps(list);
+ }
+
+ @Override
+ public void updateApps(ArrayList<ApplicationInfo> list) {
+ mAllApps2D.updateApps(list);
+ }
+
+ @Override
+ public void dumpState() {
+ mAllApps2D.dumpState();
+ }
+
+ @Override
+ public void surrender() {
+ mAllApps2D.surrender();
+ }
+
+}
diff --git a/src/com/android/launcher2/ApplicationInfo.java b/src/com/android/launcher2/ApplicationInfo.java
index 5bb5037..7b00f4f 100644
--- a/src/com/android/launcher2/ApplicationInfo.java
+++ b/src/com/android/launcher2/ApplicationInfo.java
@@ -16,17 +16,14 @@
package com.android.launcher2;
+import java.util.ArrayList;
+
import android.content.ComponentName;
-import android.content.ContentValues;
-import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.graphics.Bitmap;
-import android.graphics.drawable.Drawable;
import android.util.Log;
-import java.util.ArrayList;
-
/**
* Represents an app in AllAppsView.
*/
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java
index 9d39c2c..7ca549e 100644
--- a/src/com/android/launcher2/CellLayout.java
+++ b/src/com/android/launcher2/CellLayout.java
@@ -16,36 +16,46 @@
package com.android.launcher2;
+import com.android.launcher.R;
+
+import android.app.WallpaperManager;
import android.content.Context;
-import android.content.res.TypedArray;
import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.RectF;
-import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.ContextMenu;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewGroup;
-import android.app.WallpaperManager;
+import android.view.animation.Animation;
+import android.view.animation.LayoutAnimationController;
import java.util.ArrayList;
-
-import com.android.launcher.R;
+import java.util.Arrays;
public class CellLayout extends ViewGroup {
+ static final String TAG = "CellLayout";
+
private boolean mPortrait;
private int mCellWidth;
private int mCellHeight;
-
+
private int mLongAxisStartPadding;
private int mLongAxisEndPadding;
-
private int mShortAxisStartPadding;
private int mShortAxisEndPadding;
+ private int mLeftPadding;
+ private int mRightPadding;
+ private int mTopPadding;
+ private int mBottomPadding;
+
private int mShortAxisCells;
private int mLongAxisCells;
@@ -53,17 +63,33 @@ public class CellLayout extends ViewGroup {
private int mHeightGap;
private final Rect mRect = new Rect();
+ private final RectF mRectF = new RectF();
private final CellInfo mCellInfo = new CellInfo();
-
- int[] mCellXY = new int[2];
+
+ // This is a temporary variable to prevent having to allocate a new object just to
+ // return an (x, y) value from helper functions. Do NOT use it to maintain other state.
+ private final int[] mTmpCellXY = new int[2];
+
boolean[][] mOccupied;
- private RectF mDragRect = new RectF();
+ private final RectF mDragRect = new RectF();
+
+ // When dragging, used to indicate a vacant drop location
+ private Drawable mVacantDrawable;
+
+ // When dragging, used to indicate an occupied drop location
+ private Drawable mOccupiedDrawable;
+
+ // Updated to point to mVacantDrawable or mOccupiedDrawable, as appropriate
+ private Drawable mDragRectDrawable;
+
+ // When a drag operation is in progress, holds the nearest cell to the touch point
+ private final int[] mDragCell = new int[2];
private boolean mDirtyTag;
private boolean mLastDownOnOccupiedCell = false;
-
- private final WallpaperManager mWallpaperManager;
+
+ private final WallpaperManager mWallpaperManager;
public CellLayout(Context context) {
this(context, null);
@@ -75,20 +101,27 @@ public class CellLayout extends ViewGroup {
public CellLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
+
+ // A ViewGroup usually does not draw, but CellLayout needs to draw a rectangle to show
+ // the user where a dragged item will land when dropped.
+ setWillNotDraw(false);
+ mVacantDrawable = getResources().getDrawable(R.drawable.rounded_rect_green);
+ mOccupiedDrawable = getResources().getDrawable(R.drawable.rounded_rect_red);
+
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0);
mCellWidth = a.getDimensionPixelSize(R.styleable.CellLayout_cellWidth, 10);
mCellHeight = a.getDimensionPixelSize(R.styleable.CellLayout_cellHeight, 10);
-
- mLongAxisStartPadding =
+
+ mLongAxisStartPadding =
a.getDimensionPixelSize(R.styleable.CellLayout_longAxisStartPadding, 10);
- mLongAxisEndPadding =
+ mLongAxisEndPadding =
a.getDimensionPixelSize(R.styleable.CellLayout_longAxisEndPadding, 10);
mShortAxisStartPadding =
a.getDimensionPixelSize(R.styleable.CellLayout_shortAxisStartPadding, 10);
- mShortAxisEndPadding =
+ mShortAxisEndPadding =
a.getDimensionPixelSize(R.styleable.CellLayout_shortAxisEndPadding, 10);
-
+
mShortAxisCells = a.getInt(R.styleable.CellLayout_shortAxisCells, 4);
mLongAxisCells = a.getInt(R.styleable.CellLayout_longAxisCells, 4);
@@ -96,14 +129,6 @@ public class CellLayout extends ViewGroup {
setAlwaysDrawnWithCacheEnabled(false);
- if (mOccupied == null) {
- if (mPortrait) {
- mOccupied = new boolean[mShortAxisCells][mLongAxisCells];
- } else {
- mOccupied = new boolean[mLongAxisCells][mShortAxisCells];
- }
- }
-
mWallpaperManager = WallpaperManager.getInstance(getContext());
}
@@ -113,6 +138,18 @@ public class CellLayout extends ViewGroup {
}
@Override
+ protected void onDraw(Canvas canvas) {
+ if (!mDragRect.isEmpty()) {
+ mDragRectDrawable.setBounds(
+ (int)mDragRect.left,
+ (int)mDragRect.top,
+ (int)mDragRect.right,
+ (int)mDragRect.bottom);
+ mDragRectDrawable.draw(canvas);
+ }
+ }
+
+ @Override
public void cancelLongPress() {
super.cancelLongPress();
@@ -132,14 +169,24 @@ public class CellLayout extends ViewGroup {
return mPortrait ? mLongAxisCells : mShortAxisCells;
}
- @Override
- public void addView(View child, int index, ViewGroup.LayoutParams params) {
+ // Takes canonical layout parameters
+ public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params) {
+ final LayoutParams lp = params;
+
// Generate an id for each view, this assumes we have at most 256x256 cells
// per workspace screen
- final LayoutParams cellParams = (LayoutParams) params;
- cellParams.regenerateId = true;
+ if (lp.cellX >= 0 && lp.cellX <= getCountX() - 1 && lp.cellY >= 0 && lp.cellY <= getCountY() - 1) {
+ // If the horizontal or vertical span is set to -1, it is taken to
+ // mean that it spans the extent of the CellLayout
+ if (lp.cellHSpan < 0) lp.cellHSpan = getCountX();
+ if (lp.cellVSpan < 0) lp.cellVSpan = getCountY();
- super.addView(child, index, params);
+ child.setId(childId);
+
+ addView(child, index, lp);
+ return true;
+ }
+ return false;
}
@Override
@@ -158,67 +205,73 @@ public class CellLayout extends ViewGroup {
mCellInfo.screen = ((ViewGroup) getParent()).indexOfChild(this);
}
+ public void setTagToCellInfoForPoint(int touchX, int touchY) {
+ final CellInfo cellInfo = mCellInfo;
+ final Rect frame = mRect;
+ final int x = touchX + mScrollX;
+ final int y = touchY + mScrollY;
+ final int count = getChildCount();
+
+ boolean found = false;
+ for (int i = count - 1; i >= 0; i--) {
+ final View child = getChildAt(i);
+
+ if ((child.getVisibility()) == VISIBLE || child.getAnimation() != null) {
+ child.getHitRect(frame);
+ if (frame.contains(x, y)) {
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ cellInfo.cell = child;
+ cellInfo.cellX = lp.cellX;
+ cellInfo.cellY = lp.cellY;
+ cellInfo.spanX = lp.cellHSpan;
+ cellInfo.spanY = lp.cellVSpan;
+ cellInfo.valid = true;
+ found = true;
+ mDirtyTag = false;
+ break;
+ }
+ }
+ }
+
+ mLastDownOnOccupiedCell = found;
+
+ if (!found) {
+ final int cellXY[] = mTmpCellXY;
+ pointToCellExact(x, y, cellXY);
+
+ final boolean portrait = mPortrait;
+ final int xCount = portrait ? mShortAxisCells : mLongAxisCells;
+ final int yCount = portrait ? mLongAxisCells : mShortAxisCells;
+
+ final boolean[][] occupied = mOccupied;
+ findOccupiedCells(xCount, yCount, occupied, null, true);
+
+ cellInfo.cell = null;
+ cellInfo.cellX = cellXY[0];
+ cellInfo.cellY = cellXY[1];
+ cellInfo.spanX = 1;
+ cellInfo.spanY = 1;
+ cellInfo.valid = cellXY[0] >= 0 && cellXY[1] >= 0 && cellXY[0] < xCount &&
+ cellXY[1] < yCount && !occupied[cellXY[0]][cellXY[1]];
+
+ // Instead of finding the interesting vacant cells here, wait until a
+ // caller invokes getTag() to retrieve the result. Finding the vacant
+ // cells is a bit expensive and can generate many new objects, it's
+ // therefore better to defer it until we know we actually need it.
+
+ mDirtyTag = true;
+ }
+ setTag(cellInfo);
+ }
+
+
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
final CellInfo cellInfo = mCellInfo;
if (action == MotionEvent.ACTION_DOWN) {
- final Rect frame = mRect;
- final int x = (int) ev.getX() + mScrollX;
- final int y = (int) ev.getY() + mScrollY;
- final int count = getChildCount();
-
- boolean found = false;
- for (int i = count - 1; i >= 0; i--) {
- final View child = getChildAt(i);
-
- if ((child.getVisibility()) == VISIBLE || child.getAnimation() != null) {
- child.getHitRect(frame);
- if (frame.contains(x, y)) {
- final LayoutParams lp = (LayoutParams) child.getLayoutParams();
- cellInfo.cell = child;
- cellInfo.cellX = lp.cellX;
- cellInfo.cellY = lp.cellY;
- cellInfo.spanX = lp.cellHSpan;
- cellInfo.spanY = lp.cellVSpan;
- cellInfo.valid = true;
- found = true;
- mDirtyTag = false;
- break;
- }
- }
- }
-
- mLastDownOnOccupiedCell = found;
-
- if (!found) {
- int cellXY[] = mCellXY;
- pointToCellExact(x, y, cellXY);
-
- final boolean portrait = mPortrait;
- final int xCount = portrait ? mShortAxisCells : mLongAxisCells;
- final int yCount = portrait ? mLongAxisCells : mShortAxisCells;
-
- final boolean[][] occupied = mOccupied;
- findOccupiedCells(xCount, yCount, occupied, null);
-
- cellInfo.cell = null;
- cellInfo.cellX = cellXY[0];
- cellInfo.cellY = cellXY[1];
- cellInfo.spanX = 1;
- cellInfo.spanY = 1;
- cellInfo.valid = cellXY[0] >= 0 && cellXY[1] >= 0 && cellXY[0] < xCount &&
- cellXY[1] < yCount && !occupied[cellXY[0]][cellXY[1]];
-
- // Instead of finding the interesting vacant cells here, wait until a
- // caller invokes getTag() to retrieve the result. Finding the vacant
- // cells is a bit expensive and can generate many new objects, it's
- // therefore better to defer it until we know we actually need it.
-
- mDirtyTag = true;
- }
- setTag(cellInfo);
+ setTagToCellInfoForPoint((int) ev.getX(), (int) ev.getY());
} else if (action == MotionEvent.ACTION_UP) {
cellInfo.cell = null;
cellInfo.cellX = -1;
@@ -242,7 +295,7 @@ public class CellLayout extends ViewGroup {
final int yCount = portrait ? mLongAxisCells : mShortAxisCells;
final boolean[][] occupied = mOccupied;
- findOccupiedCells(xCount, yCount, occupied, null);
+ findOccupiedCells(xCount, yCount, occupied, null, true);
findIntersectingVacantCells(info, info.cellX, info.cellY, xCount, yCount, occupied);
@@ -251,8 +304,8 @@ public class CellLayout extends ViewGroup {
return info;
}
- private static void findIntersectingVacantCells(CellInfo cellInfo, int x, int y,
- int xCount, int yCount, boolean[][] occupied) {
+ private static void findIntersectingVacantCells(CellInfo cellInfo, int x,
+ int y, int xCount, int yCount, boolean[][] occupied) {
cellInfo.maxVacantSpanX = Integer.MIN_VALUE;
cellInfo.maxVacantSpanXSpanY = Integer.MIN_VALUE;
@@ -324,6 +377,9 @@ public class CellLayout extends ViewGroup {
cellInfo.vacantCells.add(cell);
}
+ /**
+ * Check if the column 'x' is empty from rows 'top' to 'bottom', inclusive.
+ */
private static boolean isColumnEmpty(int x, int top, int bottom, boolean[][] occupied) {
for (int y = top; y <= bottom; y++) {
if (occupied[x][y]) {
@@ -333,6 +389,9 @@ public class CellLayout extends ViewGroup {
return true;
}
+ /**
+ * Check if the row 'y' is empty from columns 'left' to 'right', inclusive.
+ */
private static boolean isRowEmpty(int y, int left, int right, boolean[][] occupied) {
for (int x = left; x <= right; x++) {
if (occupied[x][y]) {
@@ -356,7 +415,7 @@ public class CellLayout extends ViewGroup {
}
}
} else {
- findOccupiedCells(xCount, yCount, occupied, ignoreView);
+ findOccupiedCells(xCount, yCount, occupied, ignoreView, true);
}
CellInfo cellInfo = new CellInfo();
@@ -387,21 +446,21 @@ public class CellLayout extends ViewGroup {
// Assume the caller will perform their own cell searching, otherwise we
// risk causing an unnecessary rebuild after findCellForSpan()
-
+
return cellInfo;
}
/**
- * Given a point, return the cell that strictly encloses that point
+ * Given a point, return the cell that strictly encloses that point
* @param x X coordinate of the point
* @param y Y coordinate of the point
* @param result Array of 2 ints to hold the x and y coordinate of the cell
*/
void pointToCellExact(int x, int y, int[] result) {
final boolean portrait = mPortrait;
-
- final int hStartPadding = portrait ? mShortAxisStartPadding : mLongAxisStartPadding;
- final int vStartPadding = portrait ? mLongAxisStartPadding : mShortAxisStartPadding;
+
+ final int hStartPadding = getLeftPadding();
+ final int vStartPadding = getTopPadding();
result[0] = (x - hStartPadding) / (mCellWidth + mWidthGap);
result[1] = (y - vStartPadding) / (mCellHeight + mHeightGap);
@@ -414,7 +473,7 @@ public class CellLayout extends ViewGroup {
if (result[1] < 0) result[1] = 0;
if (result[1] >= yAxis) result[1] = yAxis - 1;
}
-
+
/**
* Given a point, return the cell that most closely encloses that point
* @param x X coordinate of the point
@@ -427,18 +486,15 @@ public class CellLayout extends ViewGroup {
/**
* Given a cell coordinate, return the point that represents the upper left corner of that cell
- *
- * @param cellX X coordinate of the cell
+ *
+ * @param cellX X coordinate of the cell
* @param cellY Y coordinate of the cell
- *
+ *
* @param result Array of 2 ints to hold the x and y coordinate of the point
*/
void cellToPoint(int cellX, int cellY, int[] result) {
- final boolean portrait = mPortrait;
-
- final int hStartPadding = portrait ? mShortAxisStartPadding : mLongAxisStartPadding;
- final int vStartPadding = portrait ? mLongAxisStartPadding : mShortAxisStartPadding;
-
+ final int hStartPadding = getLeftPadding();
+ final int vStartPadding = getTopPadding();
result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap);
result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap);
@@ -453,97 +509,117 @@ public class CellLayout extends ViewGroup {
}
int getLeftPadding() {
- return mPortrait ? mShortAxisStartPadding : mLongAxisStartPadding;
+ return mLeftPadding;
}
int getTopPadding() {
- return mPortrait ? mLongAxisStartPadding : mShortAxisStartPadding;
+ return mTopPadding;
}
int getRightPadding() {
- return mPortrait ? mShortAxisEndPadding : mLongAxisEndPadding;
+ return mRightPadding;
}
int getBottomPadding() {
- return mPortrait ? mLongAxisEndPadding : mShortAxisEndPadding;
+ return mBottomPadding;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO: currently ignoring padding
-
+
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
- int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
-
+ int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
+
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
-
+
if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions");
}
final int shortAxisCells = mShortAxisCells;
final int longAxisCells = mLongAxisCells;
- final int longAxisStartPadding = mLongAxisStartPadding;
- final int longAxisEndPadding = mLongAxisEndPadding;
- final int shortAxisStartPadding = mShortAxisStartPadding;
- final int shortAxisEndPadding = mShortAxisEndPadding;
final int cellWidth = mCellWidth;
final int cellHeight = mCellHeight;
- mPortrait = heightSpecSize > widthSpecSize;
+ boolean portrait = heightSpecSize > widthSpecSize;
+ if (portrait != mPortrait || mOccupied == null) {
+ if (portrait) {
+ mOccupied = new boolean[mShortAxisCells][mLongAxisCells];
+ } else {
+ mOccupied = new boolean[mLongAxisCells][mShortAxisCells];
+ }
+ }
+ mPortrait = portrait;
int numShortGaps = shortAxisCells - 1;
int numLongGaps = longAxisCells - 1;
if (mPortrait) {
- int vSpaceLeft = heightSpecSize - longAxisStartPadding - longAxisEndPadding
- - (cellHeight * longAxisCells);
+ int vSpaceLeft = heightSpecSize - mLongAxisStartPadding
+ - mLongAxisEndPadding - (cellHeight * longAxisCells);
mHeightGap = vSpaceLeft / numLongGaps;
- int hSpaceLeft = widthSpecSize - shortAxisStartPadding - shortAxisEndPadding
- - (cellWidth * shortAxisCells);
+ int hSpaceLeft = widthSpecSize - mShortAxisStartPadding
+ - mShortAxisEndPadding - (cellWidth * shortAxisCells);
if (numShortGaps > 0) {
mWidthGap = hSpaceLeft / numShortGaps;
} else {
mWidthGap = 0;
}
+
+ if (LauncherApplication.isInPlaceRotationEnabled()) {
+ mWidthGap = mHeightGap = Math.min(mHeightGap, mWidthGap);
+ mLeftPadding = mRightPadding = (widthSpecSize - cellWidth
+ * shortAxisCells - (shortAxisCells - 1) * mWidthGap) / 2;
+ mTopPadding = mBottomPadding = (heightSpecSize - cellHeight
+ * longAxisCells - (longAxisCells - 1) * mHeightGap) / 2;
+ } else {
+ mLeftPadding = mShortAxisStartPadding;
+ mRightPadding = mShortAxisEndPadding;
+ mTopPadding = mLongAxisStartPadding;
+ mBottomPadding = mLongAxisEndPadding;
+ }
} else {
- int hSpaceLeft = widthSpecSize - longAxisStartPadding - longAxisEndPadding
- - (cellWidth * longAxisCells);
+ int hSpaceLeft = widthSpecSize - mLongAxisStartPadding
+ - mLongAxisEndPadding - (cellWidth * longAxisCells);
mWidthGap = hSpaceLeft / numLongGaps;
- int vSpaceLeft = heightSpecSize - shortAxisStartPadding - shortAxisEndPadding
- - (cellHeight * shortAxisCells);
+ int vSpaceLeft = heightSpecSize - mShortAxisStartPadding
+ - mShortAxisEndPadding - (cellHeight * shortAxisCells);
if (numShortGaps > 0) {
mHeightGap = vSpaceLeft / numShortGaps;
} else {
mHeightGap = 0;
}
+
+ if (LauncherApplication.isScreenXLarge()) {
+ mWidthGap = mHeightGap = Math.min(mHeightGap, mWidthGap);
+ mLeftPadding = mRightPadding = (widthSpecSize - cellWidth
+ * longAxisCells - (longAxisCells - 1) * mWidthGap) / 2 ;
+ mTopPadding = mBottomPadding = (heightSpecSize - cellHeight
+ * shortAxisCells - (shortAxisCells - 1) * mHeightGap) / 2;
+ } else {
+ mLeftPadding = mLongAxisStartPadding;
+ mRightPadding = mLongAxisEndPadding;
+ mTopPadding = mShortAxisStartPadding;
+ mBottomPadding = mShortAxisEndPadding;
+ }
}
-
int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap,
+ mLeftPadding, mTopPadding);
- if (mPortrait) {
- lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap, shortAxisStartPadding,
- longAxisStartPadding);
- } else {
- lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap, longAxisStartPadding,
- shortAxisStartPadding);
- }
-
- if (lp.regenerateId) {
- child.setId(((getId() & 0xFF) << 16) | (lp.cellX & 0xFF) << 8 | (lp.cellY & 0xFF));
- lp.regenerateId = false;
- }
+ int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width,
+ MeasureSpec.EXACTLY);
+ int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height,
+ MeasureSpec.EXACTLY);
- int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
- int childheightMeasureSpec =
- MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);
child.measure(childWidthMeasureSpec, childheightMeasureSpec);
}
@@ -567,7 +643,7 @@ public class CellLayout extends ViewGroup {
if (lp.dropped) {
lp.dropped = false;
- final int[] cellXY = mCellXY;
+ final int[] cellXY = mTmpCellXY;
getLocationOnScreen(cellXY);
mWallpaperManager.sendWallpaperCommand(getWindowToken(), "android.home.drop",
cellXY[0] + childLeft + lp.width / 2,
@@ -593,10 +669,110 @@ public class CellLayout extends ViewGroup {
super.setChildrenDrawnWithCacheEnabled(enabled);
}
+ private boolean isVacant(int originX, int originY, int spanX, int spanY) {
+ for (int i = 0; i < spanY; i++) {
+ if (!isRowEmpty(originY + i, originX, originX + spanX - 1, mOccupied)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public View getChildAt(int x, int y) {
+ final int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ View child = getChildAt(i);
+ LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+ if ((lp.cellX <= x) && (x < lp.cellX + lp.cellHSpan) &&
+ (lp.cellY <= y) && (y < lp.cellY + lp.cellHSpan)) {
+ return child;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Estimate the size that a child with the given dimensions will take in the layout.
+ */
+ void estimateChildSize(int minWidth, int minHeight, int[] result) {
+ // Assuming it's placed at 0, 0, find where the bottom right cell will land
+ rectToCell(minWidth, minHeight, result);
+
+ // Then figure out the rect it will occupy
+ cellToRect(0, 0, result[0], result[1], mRectF);
+ result[0] = (int)mRectF.width();
+ result[1] = (int)mRectF.height();
+ }
+
+ /**
+ * Estimate where the top left cell of the dragged item will land if it is dropped.
+ *
+ * @param originX The X value of the top left corner of the item
+ * @param originY The Y value of the top left corner of the item
+ * @param spanX The number of horizontal cells that the item spans
+ * @param spanY The number of vertical cells that the item spans
+ * @param result The estimated drop cell X and Y.
+ */
+ void estimateDropCell(int originX, int originY, int spanX, int spanY, int[] result) {
+ final int countX = getCountX();
+ final int countY = getCountY();
+
+ pointToCellRounded(originX, originY, result);
+
+ // If the item isn't fully on this screen, snap to the edges
+ int rightOverhang = result[0] + spanX - countX;
+ if (rightOverhang > 0) {
+ result[0] -= rightOverhang; // Snap to right
+ }
+ result[0] = Math.max(0, result[0]); // Snap to left
+ int bottomOverhang = result[1] + spanY - countY;
+ if (bottomOverhang > 0) {
+ result[1] -= bottomOverhang; // Snap to bottom
+ }
+ result[1] = Math.max(0, result[1]); // Snap to top
+ }
+
+ void visualizeDropLocation(View view, int originX, int originY, int spanX, int spanY) {
+ final int[] originCell = mDragCell;
+ final int[] cellXY = mTmpCellXY;
+ estimateDropCell(originX, originY, spanX, spanY, cellXY);
+
+ // Only recalculate the bounding rect when necessary
+ if (!Arrays.equals(cellXY, originCell)) {
+ originCell[0] = cellXY[0];
+ originCell[1] = cellXY[1];
+
+ // Find the top left corner of the rect the object will occupy
+ final int[] topLeft = mTmpCellXY;
+ cellToPoint(originCell[0], originCell[1], topLeft);
+ final int left = topLeft[0];
+ final int top = topLeft[1];
+
+ // Now find the bottom right
+ final int[] bottomRight = mTmpCellXY;
+ cellToPoint(originCell[0] + spanX - 1, originCell[1] + spanY - 1, bottomRight);
+ bottomRight[0] += mCellWidth;
+ bottomRight[1] += mCellHeight;
+
+ final int countX = mPortrait ? mShortAxisCells : mLongAxisCells;
+ final int countY = mPortrait ? mLongAxisCells : mShortAxisCells;
+ // TODO: It's not necessary to do this every time, but it's not especially expensive
+ findOccupiedCells(countX, countY, mOccupied, view, false);
+
+ boolean vacant = isVacant(originCell[0], originCell[1], spanX, spanY);
+ mDragRectDrawable = vacant ? mVacantDrawable : mOccupiedDrawable;
+
+ // mDragRect will be rendered in onDraw()
+ mDragRect.set(left, top, bottomRight[0], bottomRight[1]);
+ invalidate();
+ }
+ }
+
/**
* Find a vacant area that will fit the given bounds nearest the requested
* cell location. Uses Euclidean distance to score multiple vacant areas.
- *
+ *
* @param pixelX The X location at which you want to search for a vacant area.
* @param pixelY The Y location at which you want to search for a vacant area.
* @param spanX Horizontal span of the object.
@@ -608,12 +784,11 @@ public class CellLayout extends ViewGroup {
*/
int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY,
CellInfo vacantCells, int[] recycle) {
-
+
// Keep track of best-scoring drop area
final int[] bestXY = recycle != null ? recycle : new int[2];
- final int[] cellXY = mCellXY;
double bestDistance = Double.MAX_VALUE;
-
+
// Bail early if vacant cells aren't valid
if (!vacantCells.valid) {
return null;
@@ -623,17 +798,18 @@ public class CellLayout extends ViewGroup {
final int size = vacantCells.vacantCells.size();
for (int i = 0; i < size; i++) {
final CellInfo.VacantCell cell = vacantCells.vacantCells.get(i);
-
+
// Reject if vacant cell isn't our exact size
if (cell.spanX != spanX || cell.spanY != spanY) {
continue;
}
-
- // Score is center distance from requested pixel
+
+ // Score is distance from requested pixel to the top left of each cell
+ final int[] cellXY = mTmpCellXY;
cellToPoint(cell.cellX, cell.cellY, cellXY);
-
- double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2) +
- Math.pow(cellXY[1] - pixelY, 2));
+
+ double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2)
+ + Math.pow(cellXY[1] - pixelY, 2));
if (distance <= bestDistance) {
bestDistance = distance;
bestXY[0] = cell.cellX;
@@ -641,44 +817,52 @@ public class CellLayout extends ViewGroup {
}
}
- // Return null if no suitable location found
+ // Return null if no suitable location found
if (bestDistance < Double.MAX_VALUE) {
return bestXY;
} else {
return null;
}
}
-
+
/**
- * Drop a child at the specified position
+ * Called when a drag and drop operation has finished (successfully or not).
+ */
+ void onDragComplete() {
+ // Invalidate the drag data
+ mDragCell[0] = -1;
+ mDragCell[1] = -1;
+
+ mDragRect.setEmpty();
+ invalidate();
+ }
+
+ /**
+ * Mark a child as having been dropped.
*
* @param child The child that is being dropped
- * @param targetXY Destination area to move to
*/
- void onDropChild(View child, int[] targetXY) {
+ void onDropChild(View child) {
if (child != null) {
LayoutParams lp = (LayoutParams) child.getLayoutParams();
- lp.cellX = targetXY[0];
- lp.cellY = targetXY[1];
lp.isDragging = false;
lp.dropped = true;
mDragRect.setEmpty();
child.requestLayout();
- invalidate();
}
+ onDragComplete();
}
void onDropAborted(View child) {
if (child != null) {
((LayoutParams) child.getLayoutParams()).isDragging = false;
- invalidate();
}
- mDragRect.setEmpty();
+ onDragComplete();
}
/**
* Start dragging the specified child
- *
+ *
* @param child The child that is being dragged
*/
void onDragChild(View child) {
@@ -686,58 +870,44 @@ public class CellLayout extends ViewGroup {
lp.isDragging = true;
mDragRect.setEmpty();
}
-
- /**
- * Drag a child over the specified position
- *
- * @param child The child that is being dropped
- * @param cellX The child's new x cell location
- * @param cellY The child's new y cell location
- */
- void onDragOverChild(View child, int cellX, int cellY) {
- int[] cellXY = mCellXY;
- pointToCellRounded(cellX, cellY, cellXY);
- LayoutParams lp = (LayoutParams) child.getLayoutParams();
- cellToRect(cellXY[0], cellXY[1], lp.cellHSpan, lp.cellVSpan, mDragRect);
- invalidate();
- }
-
+
/**
* Computes a bounding rectangle for a range of cells
- *
+ *
* @param cellX X coordinate of upper left corner expressed as a cell position
* @param cellY Y coordinate of upper left corner expressed as a cell position
- * @param cellHSpan Width in cells
+ * @param cellHSpan Width in cells
* @param cellVSpan Height in cells
- * @param dragRect Rectnagle into which to put the results
+ * @param resultRect Rect into which to put the results
*/
- public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, RectF dragRect) {
+ public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, RectF resultRect) {
final boolean portrait = mPortrait;
final int cellWidth = mCellWidth;
final int cellHeight = mCellHeight;
final int widthGap = mWidthGap;
final int heightGap = mHeightGap;
-
- final int hStartPadding = portrait ? mShortAxisStartPadding : mLongAxisStartPadding;
- final int vStartPadding = portrait ? mLongAxisStartPadding : mShortAxisStartPadding;
-
+
+ final int hStartPadding = getLeftPadding();
+ final int vStartPadding = getTopPadding();
+
int width = cellHSpan * cellWidth + ((cellHSpan - 1) * widthGap);
int height = cellVSpan * cellHeight + ((cellVSpan - 1) * heightGap);
int x = hStartPadding + cellX * (cellWidth + widthGap);
int y = vStartPadding + cellY * (cellHeight + heightGap);
-
- dragRect.set(x, y, x + width, y + height);
+
+ resultRect.set(x, y, x + width, y + height);
}
-
+
/**
- * Computes the required horizontal and vertical cell spans to always
+ * Computes the required horizontal and vertical cell spans to always
* fit the given rectangle.
- *
+ *
* @param width Width in pixels
* @param height Height in pixels
+ * @param result An array of length 2 in which to store the result (may be null).
*/
- public int[] rectToCell(int width, int height) {
+ public int[] rectToCell(int width, int height, int[] result) {
// Always assume we're working with the smallest span to make sure we
// reserve enough space in both orientations.
final Resources resources = getResources();
@@ -749,7 +919,12 @@ public class CellLayout extends ViewGroup {
int spanX = (width + smallerSize) / smallerSize;
int spanY = (height + smallerSize) / smallerSize;
- return new int[] { spanX, spanY };
+ if (result == null) {
+ return new int[] { spanX, spanY };
+ }
+ result[0] = spanX;
+ result[1] = spanY;
+ return result;
}
/**
@@ -758,7 +933,7 @@ public class CellLayout extends ViewGroup {
* @param vacant Holds the x and y coordinate of the vacant cell
* @param spanX Horizontal cell span.
* @param spanY Vertical cell span.
- *
+ *
* @return True if a vacant cell was found
*/
public boolean getVacantCell(int[] vacant, int spanX, int spanY) {
@@ -767,7 +942,7 @@ public class CellLayout extends ViewGroup {
final int yCount = portrait ? mLongAxisCells : mShortAxisCells;
final boolean[][] occupied = mOccupied;
- findOccupiedCells(xCount, yCount, occupied, null);
+ findOccupiedCells(xCount, yCount, occupied, null, true);
return findVacantCell(vacant, spanX, spanY, xCount, yCount, occupied);
}
@@ -796,13 +971,16 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
return false;
}
- boolean[] getOccupiedCells() {
+ /**
+ * Update the array of occupied cells (mOccupied), and return a flattened copy of the array.
+ */
+ boolean[] getOccupiedCellsFlattened() {
final boolean portrait = mPortrait;
final int xCount = portrait ? mShortAxisCells : mLongAxisCells;
final int yCount = portrait ? mLongAxisCells : mShortAxisCells;
final boolean[][] occupied = mOccupied;
- findOccupiedCells(xCount, yCount, occupied, null);
+ findOccupiedCells(xCount, yCount, occupied, null, true);
final boolean[] flat = new boolean[xCount * yCount];
for (int y = 0; y < yCount; y++) {
@@ -814,7 +992,14 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
return flat;
}
- private void findOccupiedCells(int xCount, int yCount, boolean[][] occupied, View ignoreView) {
+ /**
+ * Update the array of occupied cells.
+ * @param ignoreView If non-null, the space occupied by this View is treated as vacant
+ * @param ignoreFolders If true, a cell occupied by a Folder is treated as vacant
+ */
+ private void findOccupiedCells(
+ int xCount, int yCount, boolean[][] occupied, View ignoreView, boolean ignoreFolders) {
+
for (int x = 0; x < xCount; x++) {
for (int y = 0; y < yCount; y++) {
occupied[x][y] = false;
@@ -824,7 +1009,7 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
- if (child instanceof Folder || child.equals(ignoreView)) {
+ if ((ignoreFolders && child instanceof Folder) || child.equals(ignoreView)) {
continue;
}
LayoutParams lp = (LayoutParams) child.getLayoutParams();
@@ -852,6 +1037,17 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
return new CellLayout.LayoutParams(p);
}
+ public static class CellLayoutAnimationController extends LayoutAnimationController {
+ public CellLayoutAnimationController(Animation animation, float delay) {
+ super(animation, delay);
+ }
+
+ @Override
+ protected long getDelayForView(View view) {
+ return (int) (Math.random() * 150);
+ }
+ }
+
public static class LayoutParams extends ViewGroup.MarginLayoutParams {
/**
* Horizontal location of the item in the grid.
@@ -876,7 +1072,7 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
*/
@ViewDebug.ExportedProperty
public int cellVSpan;
-
+
/**
* Is this item currently being dragged
*/
@@ -889,8 +1085,6 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
@ViewDebug.ExportedProperty
int y;
- boolean regenerateId;
-
boolean dropped;
public LayoutParams(Context c, AttributeSet attrs) {
@@ -904,7 +1098,15 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
cellHSpan = 1;
cellVSpan = 1;
}
-
+
+ public LayoutParams(LayoutParams source) {
+ super(source);
+ this.cellX = source.cellX;
+ this.cellY = source.cellY;
+ this.cellHSpan = source.cellHSpan;
+ this.cellVSpan = source.cellVSpan;
+ }
+
public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) {
super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
this.cellX = cellX;
@@ -915,12 +1117,12 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap,
int hStartPadding, int vStartPadding) {
-
+
final int myCellHSpan = cellHSpan;
final int myCellVSpan = cellVSpan;
final int myCellX = cellX;
final int myCellY = cellY;
-
+
width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) -
leftMargin - rightMargin;
height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) -
@@ -929,14 +1131,18 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
x = hStartPadding + myCellX * (cellWidth + widthGap) + leftMargin;
y = vStartPadding + myCellY * (cellHeight + heightGap) + topMargin;
}
+
+ public String toString() {
+ return "(" + this.cellX + ", " + this.cellY + ")";
+ }
}
static final class CellInfo implements ContextMenu.ContextMenuInfo {
/**
- * See View.AttachInfo.InvalidateInfo for futher explanations about
- * the recycling mechanism. In this case, we recycle the vacant cells
- * instances because up to several hundreds can be instanciated when
- * the user long presses an empty cell.
+ * See View.AttachInfo.InvalidateInfo for futher explanations about the
+ * recycling mechanism. In this case, we recycle the vacant cells
+ * instances because up to several hundreds can be instanciated when the
+ * user long presses an empty cell.
*/
static final class VacantCell {
int cellX;
@@ -947,7 +1153,7 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
// We can create up to 523 vacant cells on a 4x4 grid, 100 seems
// like a reasonable compromise given the size of a VacantCell and
// the fact that the user is not likely to touch an empty 4x4 grid
- // very often
+ // very often
private static final int POOL_LIMIT = 100;
private static final Object sLock = new Object();
@@ -982,8 +1188,8 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
@Override
public String toString() {
- return "VacantCell[x=" + cellX + ", y=" + cellY + ", spanX=" + spanX +
- ", spanY=" + spanY + "]";
+ return "VacantCell[x=" + cellX + ", y=" + cellY + ", spanX="
+ + spanX + ", spanY=" + spanY + "]";
}
}
@@ -1006,7 +1212,9 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
final ArrayList<VacantCell> list = vacantCells;
final int count = list.size();
- for (int i = 0; i < count; i++) list.get(i).release();
+ for (int i = 0; i < count; i++) {
+ list.get(i).release();
+ }
list.clear();
}
@@ -1052,7 +1260,9 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
boolean found = false;
- if (this.spanX >= spanX && this.spanY >= spanY) {
+ // return the span represented by the CellInfo only there is no view there
+ // (this.cell == null) and there is enough space
+ if (this.cell == null && this.spanX >= spanX && this.spanY >= spanY) {
cellXY[0] = cellX;
cellXY[1] = cellY;
found = true;
@@ -1080,15 +1290,17 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
}
}
- if (clear) clearVacantCells();
+ if (clear) {
+ clearVacantCells();
+ }
return found;
}
@Override
public String toString() {
- return "Cell[view=" + (cell == null ? "null" : cell.getClass()) + ", x=" + cellX +
- ", y=" + cellY + "]";
+ return "Cell[view=" + (cell == null ? "null" : cell.getClass())
+ + ", x=" + cellX + ", y=" + cellY + "]";
}
}
@@ -1096,5 +1308,3 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
return mLastDownOnOccupiedCell;
}
}
-
-
diff --git a/src/com/android/launcher2/DeferredHandler.java b/src/com/android/launcher2/DeferredHandler.java
index 7801642..0323c7f 100644
--- a/src/com/android/launcher2/DeferredHandler.java
+++ b/src/com/android/launcher2/DeferredHandler.java
@@ -16,13 +16,12 @@
package com.android.launcher2;
+import java.util.LinkedList;
+
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.MessageQueue;
-import android.util.Log;
-
-import java.util.LinkedList;
/**
* Queue of things to run on a looper thread. Items posted with {@link #post} will not
diff --git a/src/com/android/launcher2/DeleteZone.java b/src/com/android/launcher2/DeleteZone.java
index 3a6c63d..b11b1dd 100644
--- a/src/com/android/launcher2/DeleteZone.java
+++ b/src/com/android/launcher2/DeleteZone.java
@@ -254,4 +254,10 @@ public class DeleteZone extends ImageView implements DropTarget, DragController.
return false;
}
}
+
+ @Override
+ public DropTarget getDropTargetDelegate(DragSource source, int x, int y, int xOffset, int yOffset,
+ DragView dragView, Object dragInfo) {
+ return null;
+ }
}
diff --git a/src/com/android/launcher2/DragController.java b/src/com/android/launcher2/DragController.java
index b4f972b..0130ba9 100644
--- a/src/com/android/launcher2/DragController.java
+++ b/src/com/android/launcher2/DragController.java
@@ -395,6 +395,13 @@ public class DragController {
final int[] coordinates = mCoordinatesTemp;
DropTarget dropTarget = findDropTarget(screenX, screenY, coordinates);
if (dropTarget != null) {
+ DropTarget delegate = dropTarget.getDropTargetDelegate(
+ mDragSource, coordinates[0], coordinates[1],
+ (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
+ if (delegate != null) {
+ dropTarget = delegate;
+ }
+
if (mLastDropTarget == dropTarget) {
dropTarget.onDragOver(mDragSource, coordinates[0], coordinates[1],
(int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
@@ -482,13 +489,25 @@ public class DragController {
final ArrayList<DropTarget> dropTargets = mDropTargets;
final int count = dropTargets.size();
for (int i=count-1; i>=0; i--) {
- final DropTarget target = dropTargets.get(i);
+ DropTarget target = dropTargets.get(i);
target.getHitRect(r);
+
+ // Convert the hit rect to screen coordinates
target.getLocationOnScreen(dropCoordinates);
r.offset(dropCoordinates[0] - target.getLeft(), dropCoordinates[1] - target.getTop());
+
if (r.contains(x, y)) {
+ DropTarget delegate = target.getDropTargetDelegate(mDragSource,
+ x, y, (int)mTouchOffsetX, (int)mTouchOffsetY, mDragView, mDragInfo);
+ if (delegate != null) {
+ target = delegate;
+ target.getLocationOnScreen(dropCoordinates);
+ }
+
+ // Make dropCoordinates relative to the DropTarget
dropCoordinates[0] = x - dropCoordinates[0];
dropCoordinates[1] = y - dropCoordinates[1];
+
return target;
}
}
diff --git a/src/com/android/launcher2/DragLayer.java b/src/com/android/launcher2/DragLayer.java
index c683207..ab71670 100644
--- a/src/com/android/launcher2/DragLayer.java
+++ b/src/com/android/launcher2/DragLayer.java
@@ -18,13 +18,13 @@ package com.android.launcher2;
import android.content.Context;
import android.util.AttributeSet;
-import android.view.MotionEvent;
import android.view.KeyEvent;
+import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
/**
- * A ViewGroup that coordinated dragging across its dscendants
+ * A ViewGroup that coordinates dragging across its descendants
*/
public class DragLayer extends FrameLayout {
DragController mDragController;
@@ -33,7 +33,7 @@ public class DragLayer extends FrameLayout {
* Used to create a new DragLayer from XML.
*
* @param context The application's context.
- * @param attrs The attribtues set containing the Workspace's customization values.
+ * @param attrs The attributes set containing the Workspace's customization values.
*/
public DragLayer(Context context, AttributeSet attrs) {
super(context, attrs);
diff --git a/src/com/android/launcher2/DragView.java b/src/com/android/launcher2/DragView.java
index 248712e..bae592c 100644
--- a/src/com/android/launcher2/DragView.java
+++ b/src/com/android/launcher2/DragView.java
@@ -18,20 +18,15 @@
package com.android.launcher2;
import android.content.Context;
-import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
-import android.graphics.Point;
import android.os.IBinder;
-import android.util.AttributeSet;
-import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
-import android.view.KeyEvent;
import android.view.WindowManager;
import android.view.WindowManagerImpl;
diff --git a/src/com/android/launcher2/DropTarget.java b/src/com/android/launcher2/DropTarget.java
index 72eb330..7e54231 100644
--- a/src/com/android/launcher2/DropTarget.java
+++ b/src/com/android/launcher2/DropTarget.java
@@ -51,6 +51,26 @@ public interface DropTarget {
DragView dragView, Object dragInfo);
/**
+ * Allows a DropTarget to delegate drag and drop events to another object.
+ *
+ * Most subclasses will should just return null from this method.
+ *
+ * @param source DragSource where the drag started
+ * @param x X coordinate of the drop location
+ * @param y Y coordinate of the drop location
+ * @param xOffset Horizontal offset with the object being dragged where the original
+ * touch happened
+ * @param yOffset Vertical offset with the object being dragged where the original
+ * touch happened
+ * @param dragView The DragView that's being dragged around on screen.
+ * @param dragInfo Data associated with the object being dragged
+ *
+ * @return The DropTarget to delegate to, or null to not delegate to another object.
+ */
+ DropTarget getDropTargetDelegate(DragSource source, int x, int y, int xOffset, int yOffset,
+ DragView dragView, Object dragInfo);
+
+ /**
* Check if a drop action can occur at, or near, the requested location.
* This may be called repeatedly during a drag, so any calls should return
* quickly.
diff --git a/src/com/android/launcher2/Folder.java b/src/com/android/launcher2/Folder.java
index 7ff8328..4d7c666 100644
--- a/src/com/android/launcher2/Folder.java
+++ b/src/com/android/launcher2/Folder.java
@@ -21,11 +21,11 @@ import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.view.View.OnClickListener;
+import android.widget.AbsListView;
import android.widget.AdapterView;
+import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
-import android.widget.AbsListView;
-import android.widget.BaseAdapter;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
diff --git a/src/com/android/launcher2/FolderChooser.java b/src/com/android/launcher2/FolderChooser.java
new file mode 100644
index 0000000..b152ad5
--- /dev/null
+++ b/src/com/android/launcher2/FolderChooser.java
@@ -0,0 +1,37 @@
+package com.android.launcher2;
+
+import com.android.launcher.R;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.provider.LiveFolders;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.AdapterView;
+
+public class FolderChooser extends HomeCustomizationItemGallery {
+
+ public FolderChooser(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
+ // todo: this code sorta overlaps with other places
+ ResolveInfo info = (ResolveInfo)getAdapter().getItem(position);
+ mLauncher.prepareAddItemFromHomeCustomizationDrawer();
+
+ Intent createFolderIntent = new Intent(LiveFolders.ACTION_CREATE_LIVE_FOLDER);
+ if (info.labelRes == R.string.group_folder) {
+ // Create app shortcuts is a special built-in case of shortcuts
+ createFolderIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, getContext().getString(R.string.group_folder));
+ } else {
+ ComponentName name = new ComponentName(info.activityInfo.packageName, info.activityInfo.name);
+ createFolderIntent.setComponent(name);
+ }
+ mLauncher.addLiveFolder(createFolderIntent);
+
+ return true;
+ }
+}
diff --git a/src/com/android/launcher2/FolderIcon.java b/src/com/android/launcher2/FolderIcon.java
index 0013644..78a9516 100644
--- a/src/com/android/launcher2/FolderIcon.java
+++ b/src/com/android/launcher2/FolderIcon.java
@@ -91,7 +91,9 @@ public class FolderIcon extends BubbleTextView implements DropTarget {
public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
DragView dragView, Object dragInfo) {
- setCompoundDrawablesWithIntrinsicBounds(null, mOpenIcon, null, null);
+ if (acceptDrop(source, x, y, xOffset, yOffset, dragView, dragInfo)) {
+ setCompoundDrawablesWithIntrinsicBounds(null, mOpenIcon, null, null);
+ }
}
public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
@@ -102,4 +104,10 @@ public class FolderIcon extends BubbleTextView implements DropTarget {
DragView dragView, Object dragInfo) {
setCompoundDrawablesWithIntrinsicBounds(null, mCloseIcon, null, null);
}
+
+ @Override
+ public DropTarget getDropTargetDelegate(DragSource source, int x, int y, int xOffset, int yOffset,
+ DragView dragView, Object dragInfo) {
+ return null;
+ }
}
diff --git a/src/com/android/launcher2/FolderListAdapter.java b/src/com/android/launcher2/FolderListAdapter.java
new file mode 100644
index 0000000..bdfeaeb
--- /dev/null
+++ b/src/com/android/launcher2/FolderListAdapter.java
@@ -0,0 +1,20 @@
+package com.android.launcher2;
+
+import com.android.launcher.R;
+
+import android.content.Context;
+import android.content.pm.ResolveInfo;
+
+public class FolderListAdapter extends IntentListAdapter {
+
+ public FolderListAdapter(Context context, String actionFilter) {
+ super(context, actionFilter);
+
+ // Manually create a separate entry for creating a folder in Launcher
+ ResolveInfo folder = new ResolveInfo();
+ folder.icon = R.drawable.ic_launcher_folder;
+ folder.labelRes = R.string.group_folder;
+ folder.resolvePackageName = context.getPackageName();
+ mIntentList.add(0, folder);
+ }
+}
diff --git a/src/com/android/launcher2/HomeCustomizationItemGallery.java b/src/com/android/launcher2/HomeCustomizationItemGallery.java
new file mode 100644
index 0000000..df64d5e
--- /dev/null
+++ b/src/com/android/launcher2/HomeCustomizationItemGallery.java
@@ -0,0 +1,50 @@
+package com.android.launcher2;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.widget.Gallery;
+
+public abstract class HomeCustomizationItemGallery extends Gallery
+ implements Gallery.OnItemLongClickListener {
+
+ protected Context mContext;
+
+ protected Launcher mLauncher;
+
+ protected int mMotionDownRawX;
+ protected int mMotionDownRawY;
+
+ public HomeCustomizationItemGallery(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setLongClickable(true);
+ setOnItemLongClickListener(this);
+ mContext = context;
+
+ setCallbackDuringFling(false);
+ }
+
+ public void setLauncher(Launcher launcher) {
+ mLauncher = launcher;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ if (ev.getAction() == MotionEvent.ACTION_DOWN && mLauncher.isAllAppsVisible()) {
+ return false;
+ }
+
+ super.onTouchEvent(ev);
+
+ int x = (int) ev.getX();
+ int y = (int) ev.getY();
+
+ switch (ev.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ mMotionDownRawX = (int) ev.getRawX();
+ mMotionDownRawY = (int) ev.getRawY();
+ }
+ return true;
+ }
+}
+
diff --git a/src/com/android/launcher2/InstallShortcutReceiver.java b/src/com/android/launcher2/InstallShortcutReceiver.java
index 3fc568b..3638054 100644
--- a/src/com/android/launcher2/InstallShortcutReceiver.java
+++ b/src/com/android/launcher2/InstallShortcutReceiver.java
@@ -16,11 +16,11 @@
package com.android.launcher2;
+import java.util.ArrayList;
+
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.content.ContentResolver;
-import android.database.Cursor;
import android.widget.Toast;
import com.android.launcher.R;
@@ -86,38 +86,24 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
private static boolean findEmptyCell(Context context, int[] xy, int screen) {
final int xCount = Launcher.NUMBER_CELLS_X;
final int yCount = Launcher.NUMBER_CELLS_Y;
-
boolean[][] occupied = new boolean[xCount][yCount];
- final ContentResolver cr = context.getContentResolver();
- Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,
- new String[] { LauncherSettings.Favorites.CELLX, LauncherSettings.Favorites.CELLY,
- LauncherSettings.Favorites.SPANX, LauncherSettings.Favorites.SPANY },
- LauncherSettings.Favorites.SCREEN + "=?",
- new String[] { String.valueOf(screen) }, null);
-
- final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
- final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
- final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);
- final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);
-
- try {
- while (c.moveToNext()) {
- int cellX = c.getInt(cellXIndex);
- int cellY = c.getInt(cellYIndex);
- int spanX = c.getInt(spanXIndex);
- int spanY = c.getInt(spanYIndex);
-
+ ArrayList<ItemInfo> items = LauncherModel.getItemsInLocalCoordinates(context);
+ ItemInfo item = null;
+ int cellX, cellY, spanX, spanY;
+ for (int i = 0; i < items.size(); ++i) {
+ item = items.get(i);
+ if (item.screen == screen) {
+ cellX = item.cellX;
+ cellY = item.cellY;
+ spanX = item.spanX;
+ spanY = item.spanY;
for (int x = cellX; x < cellX + spanX && x < xCount; x++) {
for (int y = cellY; y < cellY + spanY && y < yCount; y++) {
occupied[x][y] = true;
}
}
}
- } catch (Exception e) {
- return false;
- } finally {
- c.close();
}
return CellLayout.findVacantCell(xy, 1, 1, xCount, yCount, occupied);
diff --git a/src/com/android/launcher2/IntentListAdapter.java b/src/com/android/launcher2/IntentListAdapter.java
new file mode 100644
index 0000000..7ebffd4
--- /dev/null
+++ b/src/com/android/launcher2/IntentListAdapter.java
@@ -0,0 +1,67 @@
+package com.android.launcher2;
+
+import com.android.launcher.R;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.graphics.drawable.Drawable;
+import android.provider.LiveFolders;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import java.util.List;
+
+public class IntentListAdapter extends BaseAdapter {
+ private LayoutInflater mLayoutInflater;
+ private PackageManager mPackageManager;
+ protected List<ResolveInfo> mIntentList;
+
+ public IntentListAdapter(Context context, String actionFilter) {
+ mLayoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mPackageManager = context.getPackageManager();
+
+ Intent createLiveFolderIntent = new Intent(actionFilter);
+ mIntentList = mPackageManager.queryIntentActivities(createLiveFolderIntent, 0);
+ }
+
+ public int getCount() {
+ return mIntentList.size();
+ }
+
+ public Object getItem(int position) {
+ return mIntentList.get(position);
+ }
+
+ public long getItemId(int position) {
+ return position;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ TextView textView;
+
+ if (convertView == null) {
+ textView = (TextView) mLayoutInflater.inflate(
+ R.layout.home_customization_drawer_item, parent, false);
+ } else {
+ textView = (TextView) convertView;
+ }
+
+ ResolveInfo info = mIntentList.get(position);
+ Drawable image = info.loadIcon(mPackageManager);
+ image.setBounds(0, 0, image.getIntrinsicWidth(), image.getIntrinsicHeight());
+ textView.setCompoundDrawables(null, image, null, null);
+
+ CharSequence label = info.loadLabel(mPackageManager);
+ textView.setText(label);
+
+ return textView;
+ }
+}
diff --git a/src/com/android/launcher2/ItemInfo.java b/src/com/android/launcher2/ItemInfo.java
index a96d9ae..dc45750 100644
--- a/src/com/android/launcher2/ItemInfo.java
+++ b/src/com/android/launcher2/ItemInfo.java
@@ -112,6 +112,11 @@ class ItemInfo {
}
}
+ void updateValuesWithCoordinates(ContentValues values, int cellX, int cellY) {
+ values.put(LauncherSettings.Favorites.CELLX, cellX);
+ values.put(LauncherSettings.Favorites.CELLY, cellY);
+ }
+
static byte[] flattenBitmap(Bitmap bitmap) {
// Try go guesstimate how much space the icon will take when serialized
// to avoid unnecessary allocations/copies during the write.
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index a5988bf..f846b51 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -17,6 +17,7 @@
package com.android.launcher2;
import com.android.common.Search;
+import com.android.launcher.R;
import android.app.Activity;
import android.app.AlertDialog;
@@ -24,6 +25,8 @@ import android.app.Dialog;
import android.app.SearchManager;
import android.app.StatusBarManager;
import android.app.WallpaperManager;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -41,10 +44,10 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.ContentObserver;
import android.graphics.Bitmap;
-import android.graphics.Rect;
import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
+import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -63,34 +66,37 @@ import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
+import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewGroup;
import android.view.View.OnLongClickListener;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.animation.Animation;
+import android.view.animation.Animation.AnimationListener;
+import android.view.animation.AnimationUtils;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
-import android.widget.TextView;
-import android.widget.Toast;
import android.widget.ImageView;
-import android.widget.PopupWindow;
import android.widget.LinearLayout;
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
+import android.widget.PopupWindow;
+import android.widget.TabHost;
+import android.widget.TextView;
+import android.widget.Toast;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.HashMap;
+import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
-import java.io.DataInputStream;
-
-import com.android.launcher.R;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
/**
* Default launcher application.
*/
public final class Launcher extends Activity
- implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, AllAppsView.Watcher {
+ implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks,
+ AllAppsView.Watcher, View.OnTouchListener {
static final String TAG = "Launcher";
static final boolean LOGD = false;
@@ -182,6 +188,7 @@ public final class Launcher extends Activity
private DeleteZone mDeleteZone;
private HandleView mHandleView;
private AllAppsView mAllAppsGrid;
+ private TabHost mHomeCustomizationDrawer;
private Bundle mSavedState;
@@ -211,10 +218,17 @@ public final class Launcher extends Activity
private Drawable[] mHotseatIcons = null;
private CharSequence[] mHotseatLabels = null;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ if (LauncherApplication.isInPlaceRotationEnabled()) {
+ // hide the status bar (temporary until we get the status bar design figured out)
+ getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
+ }
+
LauncherApplication app = ((LauncherApplication)getApplication());
mModel = app.setLauncher(this);
mIconCache = app.getIconCache();
@@ -232,8 +246,26 @@ public final class Launcher extends Activity
loadHotseats();
checkForLocaleChange();
setWallpaperDimension();
-
setContentView(R.layout.launcher);
+ mHomeCustomizationDrawer = (TabHost) findViewById(com.android.internal.R.id.tabhost);
+ if (mHomeCustomizationDrawer != null) {
+ mHomeCustomizationDrawer.setup();
+
+ String widgetsLabel = getString(R.string.widgets_tab_label);
+ mHomeCustomizationDrawer.addTab(mHomeCustomizationDrawer.newTabSpec("widgets")
+ .setIndicator(widgetsLabel).setContent(R.id.widget_chooser));
+ String foldersLabel = getString(R.string.folders_tab_label);
+ mHomeCustomizationDrawer.addTab(mHomeCustomizationDrawer.newTabSpec("folders")
+ .setIndicator(foldersLabel).setContent(R.id.folder_chooser));
+ String shortcutsLabel = getString(R.string.shortcuts_tab_label);
+ mHomeCustomizationDrawer.addTab(mHomeCustomizationDrawer.newTabSpec("shortcuts")
+ .setIndicator(shortcutsLabel).setContent(R.id.shortcut_chooser));
+ String wallpapersLabel = getString(R.string.wallpapers_tab_label);
+ mHomeCustomizationDrawer.addTab(mHomeCustomizationDrawer.newTabSpec("wallpapers")
+ .setIndicator(wallpapersLabel).setContent(R.id.wallpaperstab));
+
+ mHomeCustomizationDrawer.setCurrentTab(0);
+ }
setupViews();
registerContentObservers();
@@ -259,6 +291,19 @@ public final class Launcher extends Activity
registerReceiver(mCloseSystemDialogsReceiver, filter);
}
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ // TODO Auto-generated method stub
+ super.onConfigurationChanged(newConfig);
+
+ if (LauncherApplication.isInPlaceRotationEnabled()) {
+ mModel.updateOrientation();
+ mWorkspace.refreshWorkspaceChildren();
+ mWorkspace.rotateCurrentScreensChildren();
+ }
+ }
+
+
private void checkForLocaleChange() {
final LocaleConfiguration localeConfiguration = new LocaleConfiguration();
readConfiguration(this, localeConfiguration);
@@ -419,7 +464,7 @@ public final class Launcher extends Activity
// note: if the user launches this without a default set, she
// will always be taken to the default URL above; this is
// unavoidable as we must specify a valid URL in order for the
- // chooser to appear, and once the user selects something, that
+ // chooser to appear, and once the user selects something, that
// URL is unavoidably sent to the chosen app.
} else {
try {
@@ -429,7 +474,7 @@ public final class Launcher extends Activity
// bogus; leave intent=null
}
}
-
+
if (intent == null) {
mHotseats[i] = null;
mHotseatLabels[i] = getText(R.string.activity_not_found);
@@ -437,15 +482,15 @@ public final class Launcher extends Activity
}
if (LOGD) {
- Log.d(TAG, "loadHotseats: hotseat " + i
- + " initial intent=["
+ Log.d(TAG, "loadHotseats: hotseat " + i
+ + " initial intent=["
+ intent.toUri(Intent.URI_INTENT_SCHEME)
+ "]");
}
ResolveInfo bestMatch = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
List<ResolveInfo> allMatches = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
- if (LOGD) {
+ if (LOGD) {
Log.d(TAG, "Best match for intent: " + bestMatch);
Log.d(TAG, "All matches: ");
for (ResolveInfo ri : allMatches) {
@@ -454,8 +499,8 @@ public final class Launcher extends Activity
}
// did this resolve to a single app, or the resolver?
if (allMatches.size() == 0 || bestMatch == null) {
- // can't find any activity to handle this. let's leave the
- // intent as-is and let Launcher show a toast when it fails
+ // can't find any activity to handle this. let's leave the
+ // intent as-is and let Launcher show a toast when it fails
// to launch.
mHotseats[i] = intent;
@@ -471,7 +516,7 @@ public final class Launcher extends Activity
break;
}
}
-
+
if (!found) {
if (LOGD) Log.d(TAG, "Multiple options, no default yet");
// the bestMatch is probably the ResolveActivity, meaning the
@@ -496,8 +541,8 @@ public final class Launcher extends Activity
}
if (LOGD) {
- Log.d(TAG, "loadHotseats: hotseat " + i
- + " final intent=["
+ Log.d(TAG, "loadHotseats: hotseat " + i
+ + " final intent=["
+ ((mHotseats[i] == null)
? "null"
: mHotseats[i].toUri(Intent.URI_INTENT_SCHEME))
@@ -536,10 +581,11 @@ public final class Launcher extends Activity
completeAddLiveFolder(data, mAddItemCellInfo);
break;
case REQUEST_PICK_APPWIDGET:
- addAppWidget(data);
+ addAppWidgetFromPick(data);
break;
case REQUEST_CREATE_APPWIDGET:
- completeAddAppWidget(data, mAddItemCellInfo);
+ int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
+ completeAddAppWidget(appWidgetId, mAddItemCellInfo);
break;
case REQUEST_PICK_WALLPAPER:
// We just wanted the activity result here so we can clear mWaitingForResult
@@ -572,8 +618,13 @@ public final class Launcher extends Activity
@Override
protected void onPause() {
super.onPause();
- dismissPreview(mPreviousView);
- dismissPreview(mNextView);
+ // Some launcher layouts don't have a previous and next view
+ if (mPreviousView != null) {
+ dismissPreview(mPreviousView);
+ }
+ if (mNextView != null) {
+ dismissPreview(mNextView);
+ }
mDragController.cancelDrag();
}
@@ -706,12 +757,17 @@ public final class Launcher extends Activity
mAllAppsGrid.setDragController(dragController);
((View) mAllAppsGrid).setWillNotDraw(false); // We don't want a hole punched in our window.
// Manage focusability manually since this thing is always visible
- ((View) mAllAppsGrid).setFocusable(false);
+ ((View) mAllAppsGrid).setFocusable(false);
mWorkspace = (Workspace) dragLayer.findViewById(R.id.workspace);
final Workspace workspace = mWorkspace;
workspace.setHapticFeedbackEnabled(false);
+ // We only intercept touch events to dismiss the home customization drawer; if it doesn't
+ // exist, then no need to do this
+ if (mHomeCustomizationDrawer != null)
+ workspace.setOnInterceptTouchListener(this);
+
DeleteZone deleteZone = (DeleteZone) dragLayer.findViewById(R.id.delete_zone);
mDeleteZone = deleteZone;
@@ -720,24 +776,42 @@ public final class Launcher extends Activity
mHandleView.setOnClickListener(this);
mHandleView.setOnLongClickListener(this);
- ImageView hotseatLeft = (ImageView) findViewById(R.id.hotseat_left);
- hotseatLeft.setContentDescription(mHotseatLabels[0]);
- hotseatLeft.setImageDrawable(mHotseatIcons[0]);
- ImageView hotseatRight = (ImageView) findViewById(R.id.hotseat_right);
- hotseatRight.setContentDescription(mHotseatLabels[1]);
- hotseatRight.setImageDrawable(mHotseatIcons[1]);
+ WidgetChooser widgetChooser = (WidgetChooser) findViewById(R.id.widget_chooser);
+ if (widgetChooser != null) {
+ WidgetListAdapter widgetGalleryAdapter = new WidgetListAdapter(this);
+ widgetChooser.setAdapter(widgetGalleryAdapter);
+ widgetChooser.setDragController(dragController);
+ widgetChooser.setLauncher(this);
+
+ FolderChooser folderChooser = (FolderChooser) findViewById(R.id.folder_chooser);
+ IntentListAdapter folderTypes = new FolderListAdapter(this, LiveFolders.ACTION_CREATE_LIVE_FOLDER);
+ folderChooser.setAdapter(folderTypes);
+ folderChooser.setLauncher(this);
+
+ ShortcutChooser shortcutChooser = (ShortcutChooser) findViewById(R.id.shortcut_chooser);
+ IntentListAdapter shortcutTypes = new ShortcutListAdapter(this, Intent.ACTION_CREATE_SHORTCUT);
+ shortcutChooser.setAdapter(shortcutTypes);
+ shortcutChooser.setLauncher(this);
+ } else {
+ ImageView hotseatLeft = (ImageView) findViewById(R.id.hotseat_left);
+ hotseatLeft.setContentDescription(mHotseatLabels[0]);
+ hotseatLeft.setImageDrawable(mHotseatIcons[0]);
+ ImageView hotseatRight = (ImageView) findViewById(R.id.hotseat_right);
+ hotseatRight.setContentDescription(mHotseatLabels[1]);
+ hotseatRight.setImageDrawable(mHotseatIcons[1]);
- mPreviousView = (ImageView) dragLayer.findViewById(R.id.previous_screen);
- mNextView = (ImageView) dragLayer.findViewById(R.id.next_screen);
+ mPreviousView = (ImageView) dragLayer.findViewById(R.id.previous_screen);
+ mNextView = (ImageView) dragLayer.findViewById(R.id.next_screen);
- Drawable previous = mPreviousView.getDrawable();
- Drawable next = mNextView.getDrawable();
- mWorkspace.setIndicators(previous, next);
+ Drawable previous = mPreviousView.getDrawable();
+ Drawable next = mNextView.getDrawable();
+ mWorkspace.setIndicators(previous, next);
- mPreviousView.setHapticFeedbackEnabled(false);
- mPreviousView.setOnLongClickListener(this);
- mNextView.setHapticFeedbackEnabled(false);
- mNextView.setOnLongClickListener(this);
+ mPreviousView.setHapticFeedbackEnabled(false);
+ mPreviousView.setOnLongClickListener(this);
+ mNextView.setHapticFeedbackEnabled(false);
+ mNextView.setOnLongClickListener(this);
+ }
workspace.setOnLongClickListener(this);
workspace.setDragController(dragController);
@@ -745,7 +819,8 @@ public final class Launcher extends Activity
deleteZone.setLauncher(this);
deleteZone.setDragController(dragController);
- deleteZone.setHandle(findViewById(R.id.all_apps_button_cluster));
+ int deleteZoneHandleId = LauncherApplication.isScreenXLarge() ? R.id.add_button : R.id.all_apps_button_cluster;
+ deleteZone.setHandle(findViewById(deleteZoneHandleId));
dragController.setDragScoller(workspace);
dragController.setDragListener(deleteZone);
@@ -792,7 +867,7 @@ public final class Launcher extends Activity
);
}
}
-
+
/**
* Creates a view representing a shortcut.
*
@@ -876,17 +951,12 @@ public final class Launcher extends Activity
* @param data The intent describing the appWidgetId.
* @param cellInfo The position on screen where to create the widget.
*/
- private void completeAddAppWidget(Intent data, CellLayout.CellInfo cellInfo) {
- Bundle extras = data.getExtras();
- int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
-
- if (LOGD) Log.d(TAG, "dumping extras content=" + extras.toString());
-
+ private void completeAddAppWidget(int appWidgetId, CellLayout.CellInfo cellInfo) {
AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
// Calculate the grid spans needed to fit this widget
CellLayout layout = (CellLayout) mWorkspace.getChildAt(cellInfo.screen);
- int[] spans = layout.rectToCell(appWidgetInfo.minWidth, appWidgetInfo.minHeight);
+ int[] spans = layout.rectToCell(appWidgetInfo.minWidth, appWidgetInfo.minHeight, null);
// Try finding open space on Launcher screen
final int[] xy = mCellCoordinates;
@@ -960,10 +1030,13 @@ public final class Launcher extends Activity
boolean alreadyOnHome = ((intent.getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT)
!= Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
boolean allAppsVisible = isAllAppsVisible();
+
+ // TODO: Figure out the right thing to do in XLarge mode here
if (!mWorkspace.isDefaultScreenShowing()) {
mWorkspace.moveToDefaultScreen(alreadyOnHome && !allAppsVisible);
}
closeAllApps(alreadyOnHome && allAppsVisible);
+ hideCustomizationDrawer();
final View v = getWindow().peekDecorView();
if (v != null && v.getWindowToken() != null) {
@@ -978,6 +1051,13 @@ public final class Launcher extends Activity
protected void onRestoreInstanceState(Bundle savedInstanceState) {
// Do not call super here
mSavedInstanceState = savedInstanceState;
+
+ if (mHomeCustomizationDrawer != null) {
+ String cur = savedInstanceState.getString("currentTab");
+ if (cur != null) {
+ mHomeCustomizationDrawer.setCurrentTabByTag(cur);
+ }
+ }
}
@Override
@@ -1014,13 +1094,20 @@ public final class Launcher extends Activity
outState.putInt(RUNTIME_STATE_PENDING_ADD_COUNT_X, layout.getCountX());
outState.putInt(RUNTIME_STATE_PENDING_ADD_COUNT_Y, layout.getCountY());
outState.putBooleanArray(RUNTIME_STATE_PENDING_ADD_OCCUPIED_CELLS,
- layout.getOccupiedCells());
+ layout.getOccupiedCellsFlattened());
}
if (mFolderInfo != null && mWaitingForResult) {
outState.putBoolean(RUNTIME_STATE_PENDING_FOLDER_RENAME, true);
outState.putLong(RUNTIME_STATE_PENDING_FOLDER_RENAME_ID, mFolderInfo.id);
}
+
+ if (mHomeCustomizationDrawer != null) {
+ String currentTabTag = mHomeCustomizationDrawer.getCurrentTabTag();
+ if (currentTabTag != null) {
+ outState.putString("currentTab", currentTabTag);
+ }
+ }
}
@Override
@@ -1040,9 +1127,14 @@ public final class Launcher extends Activity
unbindDesktopItems();
getContentResolver().unregisterContentObserver(mWidgetObserver);
-
- dismissPreview(mPreviousView);
- dismissPreview(mNextView);
+
+ // Some launcher layouts don't have a previous and next view
+ if (mPreviousView != null) {
+ dismissPreview(mPreviousView);
+ }
+ if (mNextView != null) {
+ dismissPreview(mNextView);
+ }
unregisterReceiver(mCloseSystemDialogsReceiver);
}
@@ -1131,6 +1223,13 @@ public final class Launcher extends Activity
return true;
}
+ // we need to initialize mAddItemCellInfo before adding something to the homescreen -- when
+ // using the settings menu to add an item, something similar happens in showAddDialog
+ public void prepareAddItemFromHomeCustomizationDrawer() {
+ mMenuAddInfo = mWorkspace.findAllVacantCells(null);
+ mAddItemCellInfo = mMenuAddInfo;
+ }
+
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
@@ -1168,12 +1267,32 @@ public final class Launcher extends Activity
private void addItems() {
closeAllApps(true);
- showAddDialog(mMenuAddInfo);
+ if (LauncherApplication.isScreenXLarge()) {
+ // Animate the widget chooser up from the bottom of the screen
+ if (!isCustomizationDrawerVisible()) {
+ showCustomizationDrawer();
+ }
+ } else {
+ showAddDialog(mMenuAddInfo);
+ }
+ }
+
+ void addAppWidgetFromDrop(ComponentName appWidgetProvider, CellLayout.CellInfo cellInfo) {
+ mAddItemCellInfo = cellInfo;
+ int appWidgetId = getAppWidgetHost().allocateAppWidgetId();
+ AppWidgetManager.getInstance(this).bindAppWidgetId(appWidgetId, appWidgetProvider);
+ addAppWidgetImpl(appWidgetId);
}
- void addAppWidget(Intent data) {
+ void addAppWidgetFromPick(Intent data) {
// TODO: catch bad widget exception when sent
int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
+ // TODO: Is this log message meaningful?
+ if (LOGD) Log.d(TAG, "dumping extras content=" + data.getExtras());
+ addAppWidgetImpl(appWidgetId);
+ }
+
+ void addAppWidgetImpl(int appWidgetId) {
AppWidgetProviderInfo appWidget = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
if (appWidget.configure != null) {
@@ -1185,7 +1304,7 @@ public final class Launcher extends Activity
startActivityForResultSafely(intent, REQUEST_CREATE_APPWIDGET);
} else {
// Otherwise just add it
- onActivityResult(REQUEST_CREATE_APPWIDGET, Activity.RESULT_OK, data);
+ completeAddAppWidget(appWidgetId, mAddItemCellInfo);
}
}
@@ -1386,11 +1505,16 @@ public final class Launcher extends Activity
public void onBackPressed() {
if (isAllAppsVisible()) {
closeAllApps(true);
+ } else if (isCustomizationDrawerVisible()) {
+ hideCustomizationDrawer();
} else {
closeFolder();
}
- dismissPreview(mPreviousView);
- dismissPreview(mNextView);
+ // Some launcher layouts don't have a previous and next view
+ if (mPreviousView != null) {
+ dismissPreview(mPreviousView);
+ dismissPreview(mNextView);
+ }
}
private void closeFolder() {
@@ -1456,6 +1580,23 @@ public final class Launcher extends Activity
}
}
+ public boolean onTouch(View v, MotionEvent event) {
+ // this is being forwarded from mWorkspace;
+ // clicking anywhere on the workspace causes the drawer to slide down
+ hideCustomizationDrawer();
+ return false;
+ }
+
+ /**
+ * Event handler for the "plus" button that appears on the home screen, which
+ * enters home screen customization mode.
+ *
+ * @param v The view that was clicked.
+ */
+ public void onClickAddButton(View v) {
+ addItems();
+ }
+
void startActivitySafely(Intent intent, Object tag) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
@@ -1471,7 +1612,7 @@ public final class Launcher extends Activity
+ "tag="+ tag + " intent=" + intent, e);
}
}
-
+
void startActivityForResultSafely(Intent intent, int requestCode) {
try {
startActivityForResult(intent, requestCode);
@@ -1516,7 +1657,7 @@ public final class Launcher extends Activity
*
* @param folderInfo The FolderInfo describing the folder to open.
*/
- private void openFolder(FolderInfo folderInfo) {
+ public void openFolder(FolderInfo folderInfo) {
Folder openFolder;
if (folderInfo instanceof UserFolderInfo) {
@@ -1533,7 +1674,8 @@ public final class Launcher extends Activity
openFolder.bind(folderInfo);
folderInfo.opened = true;
- mWorkspace.addInScreen(openFolder, folderInfo.screen, 0, 0, 4, 4);
+ mWorkspace.addInFullScreen(openFolder, folderInfo.screen);
+
openFolder.onOpen();
}
@@ -1631,9 +1773,9 @@ public final class Launcher extends Activity
final Workspace workspace = mWorkspace;
CellLayout cell = ((CellLayout) workspace.getChildAt(start));
-
+
float max = workspace.getChildCount();
-
+
final Rect r = new Rect();
resources.getDrawable(R.drawable.preview_background).getPadding(r);
int extraW = (int) ((r.left + r.right) * max);
@@ -1684,7 +1826,7 @@ public final class Launcher extends Activity
preview.addView(image,
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
- bitmaps.add(bitmap);
+ bitmaps.add(bitmap);
}
final PopupWindow p = new PopupWindow(this);
@@ -1705,7 +1847,7 @@ public final class Launcher extends Activity
anchor.setTag(p);
anchor.setTag(R.id.workspace, preview);
- anchor.setTag(R.id.icon, bitmaps);
+ anchor.setTag(R.id.icon, bitmaps);
}
class PreviewTouchHandler implements View.OnClickListener, Runnable, View.OnFocusChangeListener {
@@ -1721,7 +1863,7 @@ public final class Launcher extends Activity
}
public void run() {
- dismissPreview(mAnchor);
+ dismissPreview(mAnchor);
}
public void onFocusChange(View v, boolean hasFocus) {
@@ -1776,6 +1918,7 @@ public final class Launcher extends Activity
}
private void pickShortcut() {
+ // Insert extra item to handle picking application
Bundle bundle = new Bundle();
ArrayList<String> shortcutNames = new ArrayList<String>();
@@ -1888,11 +2031,20 @@ public final class Launcher extends Activity
}
void showAllApps(boolean animated) {
- mAllAppsGrid.zoom(1.0f, animated);
+ hideCustomizationDrawer();
+
+ if (LauncherApplication.isScreenXLarge() && animated) {
+ // Not really a zoom -- this just makes the view visible
+ mAllAppsGrid.zoom(1.0f, false);
+ Animation anim = AnimationUtils.loadAnimation(this, R.anim.all_apps_zoom_in);
+ ((View) mAllAppsGrid).startAnimation(anim);
+ } else {
+ mAllAppsGrid.zoom(1.0f, animated);
+ }
((View) mAllAppsGrid).setFocusable(true);
((View) mAllAppsGrid).requestFocus();
-
+
// TODO: fade these two too
mDeleteZone.setVisibility(View.GONE);
}
@@ -1939,7 +2091,19 @@ public final class Launcher extends Activity
void closeAllApps(boolean animated) {
if (mAllAppsGrid.isVisible()) {
mWorkspace.setVisibility(View.VISIBLE);
- mAllAppsGrid.zoom(0.0f, animated);
+ if (LauncherApplication.isScreenXLarge() && animated) {
+ Animation anim = AnimationUtils.loadAnimation(this, R.anim.all_apps_zoom_out);
+ anim.setAnimationListener(new AnimationListener() {
+ public void onAnimationStart(Animation animation) {}
+ public void onAnimationRepeat(Animation animation) {}
+ public void onAnimationEnd(Animation animation) {
+ mAllAppsGrid.zoom(0.0f, false);
+ }
+ });
+ ((View)mAllAppsGrid).startAnimation(anim);
+ } else {
+ mAllAppsGrid.zoom(0.0f, animated);
+ }
((View)mAllAppsGrid).setFocusable(false);
mWorkspace.getChildAt(mWorkspace.getCurrentScreen()).requestFocus();
}
@@ -1953,6 +2117,33 @@ public final class Launcher extends Activity
// TODO
}
+ private boolean isCustomizationDrawerVisible() {
+ return mHomeCustomizationDrawer != null && mHomeCustomizationDrawer.getVisibility() == View.VISIBLE;
+ }
+
+ private void showCustomizationDrawer() {
+ if (isAllAppsVisible()) {
+ // TODO: Make a smoother transition here
+ closeAllApps(false);
+ }
+ mHomeCustomizationDrawer.setVisibility(View.VISIBLE);
+ mHomeCustomizationDrawer.startAnimation(AnimationUtils.loadAnimation(this, R.anim.home_customization_drawer_slide_up));
+ }
+
+ private void hideCustomizationDrawer() {
+ if (isCustomizationDrawerVisible()) {
+ Animation slideDownAnimation = AnimationUtils.loadAnimation(this, R.anim.home_customization_drawer_slide_down);
+ slideDownAnimation.setAnimationListener(new Animation.AnimationListener() {
+ public void onAnimationEnd(Animation animation) {
+ mHomeCustomizationDrawer.setVisibility(View.GONE);
+ }
+ public void onAnimationRepeat(Animation animation) {}
+ public void onAnimationStart(Animation animation) {}
+ });
+ mHomeCustomizationDrawer.startAnimation(slideDownAnimation);
+ }
+ }
+
/**
* Displays the shortcut creation dialog and launches, if necessary, the
* appropriate activity.
@@ -2005,7 +2196,6 @@ public final class Launcher extends Activity
switch (which) {
case AddAdapter.ITEM_SHORTCUT: {
- // Insert extra item to handle picking application
pickShortcut();
break;
}
@@ -2053,7 +2243,7 @@ public final class Launcher extends Activity
}
public void onShow(DialogInterface dialog) {
- mWaitingForResult = true;
+ mWaitingForResult = true;
}
}
diff --git a/src/com/android/launcher2/LauncherAppWidgetInfo.java b/src/com/android/launcher2/LauncherAppWidgetInfo.java
index 8499ebb..32c92aa 100644
--- a/src/com/android/launcher2/LauncherAppWidgetInfo.java
+++ b/src/com/android/launcher2/LauncherAppWidgetInfo.java
@@ -17,25 +17,50 @@
package com.android.launcher2;
import android.appwidget.AppWidgetHostView;
+import android.content.ComponentName;
import android.content.ContentValues;
/**
- * Represents a widget, which just contains an identifier.
+ * Represents a widget (either instantiated or about to be) in the Launcher.
*/
class LauncherAppWidgetInfo extends ItemInfo {
/**
+ * Indicates that the widget hasn't been instantiated yet.
+ */
+ static final int NO_ID = -1;
+
+ /**
* Identifier for this widget when talking with
* {@link android.appwidget.AppWidgetManager} for updates.
*/
- int appWidgetId;
+ int appWidgetId = NO_ID;
+
+ ComponentName providerName;
+ // TODO: Are these necessary here?
+ int minWidth = -1;
+ int minHeight = -1;
+
/**
* View that holds this widget after it's been created. This view isn't created
* until Launcher knows it's needed.
*/
AppWidgetHostView hostView = null;
+ /**
+ * Constructor for use with AppWidgets that haven't been instantiated yet.
+ */
+ LauncherAppWidgetInfo(ComponentName providerName) {
+ itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
+ this.providerName = providerName;
+
+ // Since the widget isn't instantiated yet, we don't know these values. Set them to -1
+ // to indicate that they should be calculated based on the layout and minWidth/minHeight
+ spanX = -1;
+ spanY = -1;
+ }
+
LauncherAppWidgetInfo(int appWidgetId) {
itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
this.appWidgetId = appWidgetId;
@@ -52,7 +77,6 @@ class LauncherAppWidgetInfo extends ItemInfo {
return "AppWidget(id=" + Integer.toString(appWidgetId) + ")";
}
-
@Override
void unbind() {
super.unbind();
diff --git a/src/com/android/launcher2/LauncherApplication.java b/src/com/android/launcher2/LauncherApplication.java
index eda92d9..ca08378 100644
--- a/src/com/android/launcher2/LauncherApplication.java
+++ b/src/com/android/launcher2/LauncherApplication.java
@@ -20,6 +20,7 @@ import android.app.Application;
import android.content.ContentResolver;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.Configuration;
import android.database.ContentObserver;
import android.os.Handler;
import dalvik.system.VMRuntime;
@@ -27,6 +28,8 @@ import dalvik.system.VMRuntime;
public class LauncherApplication extends Application {
public LauncherModel mModel;
public IconCache mIconCache;
+ private static boolean sIsScreenXLarge;
+ private static final boolean ENABLE_ROTATION = false;
@Override
public void onCreate() {
@@ -36,6 +39,7 @@ public class LauncherApplication extends Application {
mIconCache = new IconCache(this);
mModel = new LauncherModel(this, mIconCache);
+ sIsScreenXLarge = (getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE;
// Register intent receivers
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
@@ -89,4 +93,12 @@ public class LauncherApplication extends Application {
LauncherModel getModel() {
return mModel;
}
+
+ public static boolean isInPlaceRotationEnabled() {
+ return sIsScreenXLarge && ENABLE_ROTATION;
+ }
+
+ public static boolean isScreenXLarge() {
+ return sIsScreenXLarge;
+ }
}
diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java
index eb341f6..238fbdf 100644
--- a/src/com/android/launcher2/LauncherModel.java
+++ b/src/com/android/launcher2/LauncherModel.java
@@ -16,6 +16,15 @@
package com.android.launcher2;
+import java.lang.ref.WeakReference;
+import java.net.URISyntaxException;
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.BroadcastReceiver;
@@ -23,9 +32,9 @@ import android.content.ComponentName;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.ContentValues;
+import android.content.Context;
import android.content.Intent;
import android.content.Intent.ShortcutIconResource;
-import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
@@ -38,20 +47,10 @@ import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Parcelable;
-import android.os.RemoteException;
-import android.util.Log;
import android.os.Process;
+import android.os.RemoteException;
import android.os.SystemClock;
-
-import java.lang.ref.WeakReference;
-import java.net.URISyntaxException;
-import java.text.Collator;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
+import android.util.Log;
import com.android.launcher.R;
@@ -91,6 +90,8 @@ public class LauncherModel extends BroadcastReceiver {
private Bitmap mDefaultIcon;
+ private static LauncherModelOrientationHelper mModelOrientationHelper;
+
public interface Callbacks {
public int getCurrentWorkspaceScreen();
public void startBinding();
@@ -109,6 +110,7 @@ public class LauncherModel extends BroadcastReceiver {
mApp = app;
mAllAppsList = new AllAppsList(iconCache);
mIconCache = iconCache;
+ mModelOrientationHelper = new LauncherModelOrientationHelper(mApp);
mDefaultIcon = Utilities.createIconBitmap(
app.getPackageManager().getDefaultActivityIcon(), app);
@@ -141,11 +143,20 @@ public class LauncherModel extends BroadcastReceiver {
}
}
+ static int getCurrentOrientation() {
+ return mModelOrientationHelper.getCurrentOrientation();
+ }
+
+ static int getPreviousOrientationRelativeToCurrent() {
+ return mModelOrientationHelper.getPreviousOrientationRelativeToCurrent();
+ }
+
/**
* Move an item in the DB to a new <container, screen, cellX, cellY>
*/
static void moveItemInDatabase(Context context, ItemInfo item, long container, int screen,
int cellX, int cellY) {
+
item.container = container;
item.screen = screen;
item.cellX = cellX;
@@ -153,10 +164,11 @@ public class LauncherModel extends BroadcastReceiver {
final ContentValues values = new ContentValues();
final ContentResolver cr = context.getContentResolver();
+ final LauncherModelOrientationHelper.Coordinates coord = mModelOrientationHelper.getCanonicalCoordinates(item);
values.put(LauncherSettings.Favorites.CONTAINER, item.container);
- values.put(LauncherSettings.Favorites.CELLX, item.cellX);
- values.put(LauncherSettings.Favorites.CELLY, item.cellY);
+ values.put(LauncherSettings.Favorites.CELLX, coord.x);
+ values.put(LauncherSettings.Favorites.CELLY, coord.y);
values.put(LauncherSettings.Favorites.SCREEN, item.screen);
cr.update(LauncherSettings.Favorites.getContentUri(item.id, false), values, null, null);
@@ -181,6 +193,48 @@ public class LauncherModel extends BroadcastReceiver {
}
/**
+ * Returns an ItemInfo array containing all the items in the LauncherModel.
+ * The ItemInfo.id is not set through this function.
+ */
+ static ArrayList<ItemInfo> getItemsInLocalCoordinates(Context context) {
+ ArrayList<ItemInfo> items = new ArrayList<ItemInfo>();
+ final ContentResolver cr = context.getContentResolver();
+ Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, new String[] {
+ LauncherSettings.Favorites.ITEM_TYPE, LauncherSettings.Favorites.CONTAINER,
+ LauncherSettings.Favorites.SCREEN, LauncherSettings.Favorites.CELLX, LauncherSettings.Favorites.CELLY,
+ LauncherSettings.Favorites.SPANX, LauncherSettings.Favorites.SPANY }, null, null, null);
+
+ final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
+ final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
+ final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
+ final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
+ final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
+ final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);
+ final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);
+
+ try {
+ while (c.moveToNext()) {
+ ItemInfo item = new ItemInfo();
+ item.cellX = c.getInt(cellXIndex);
+ item.cellY = c.getInt(cellYIndex);
+ item.spanX = c.getInt(spanXIndex);
+ item.spanY = c.getInt(spanYIndex);
+ item.container = c.getInt(containerIndex);
+ item.itemType = c.getInt(itemTypeIndex);
+ item.screen = c.getInt(screenIndex);
+
+ items.add(item);
+ }
+ } catch (Exception e) {
+ items.clear();
+ } finally {
+ c.close();
+ }
+
+ return items;
+ }
+
+ /**
* Find a folder in the db, creating the FolderInfo if necessary, and adding it to folderList.
*/
FolderInfo getFolderById(Context context, HashMap<Long,FolderInfo> folderList, long id) {
@@ -210,12 +264,13 @@ public class LauncherModel extends BroadcastReceiver {
break;
}
+ final LauncherModelOrientationHelper.Coordinates coord = mModelOrientationHelper.getLocalCoordinates(c.getInt(cellXIndex), c.getInt(cellYIndex), 1, 1);
folderInfo.title = c.getString(titleIndex);
folderInfo.id = id;
folderInfo.container = c.getInt(containerIndex);
folderInfo.screen = c.getInt(screenIndex);
- folderInfo.cellX = c.getInt(cellXIndex);
- folderInfo.cellY = c.getInt(cellYIndex);
+ folderInfo.cellX = coord.x;
+ folderInfo.cellY = coord.y;
return folderInfo;
}
@@ -239,9 +294,12 @@ public class LauncherModel extends BroadcastReceiver {
final ContentValues values = new ContentValues();
final ContentResolver cr = context.getContentResolver();
-
item.onAddToDatabase(values);
+ // update the values to be written with their canonical counterparts
+ final LauncherModelOrientationHelper.Coordinates coord = mModelOrientationHelper.getCanonicalCoordinates(item);
+ item.updateValuesWithCoordinates(values, coord.x, coord.y);
+
Uri result = cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI :
LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values);
@@ -251,6 +309,44 @@ public class LauncherModel extends BroadcastReceiver {
}
/**
+ * Creates a new unique child id, for a given cell span across all layouts.
+ */
+ static int getCanonicalCellLayoutChildId(int cellId, int screen, int localCellX, int localCellY, int spanX, int spanY) {
+ if (LauncherApplication.isInPlaceRotationEnabled()) {
+ LauncherModelOrientationHelper.Coordinates coord = mModelOrientationHelper.getCanonicalCoordinates(localCellX, localCellY, spanX, spanY);
+ return ((screen & 0xFF) << 16) | (coord.x & 0xFF) << 8 | (coord.y & 0xFF);
+ } else {
+ return ((cellId & 0xFF) << 16) | (localCellX & 0xFF) << 8 | (localCellY & 0xFF);
+ }
+ }
+
+ /*
+ * Convenience functions to help return the local device width and height.
+ */
+ static int getLocalDeviceWidth() {
+ return mModelOrientationHelper.getLocalDeviceWidth();
+ }
+
+ static int getLocalDeviceHeight() {
+ return mModelOrientationHelper.getLocalDeviceHeight();
+ }
+
+ /**
+ * Return the new local coordinates given the local coordinates from the previous orientation.
+ */
+ static LauncherModelOrientationHelper.Coordinates getLocalCoordinatesFromPreviousLocalCoordinates(CellLayout.LayoutParams lp) {
+ return mModelOrientationHelper.getLocalCoordinatesFromPreviousLocalCoordinates(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan);
+ }
+
+ /**
+ * Updates the model orientation helper to take into account the current layout dimensions
+ * when performing local/canonical coordinate transformations.
+ */
+ static void updateWorkspaceLayoutCells(int shortAxisCellCount, int longAxisCellCount) {
+ mModelOrientationHelper.updateDeviceDimensions(shortAxisCellCount, longAxisCellCount);
+ }
+
+ /**
* Update an item to the database in a specified container.
*/
static void updateItemInDatabase(Context context, ItemInfo item) {
@@ -259,6 +355,10 @@ public class LauncherModel extends BroadcastReceiver {
item.onAddToDatabase(values);
+ // update the values to be written with their canonical counterparts
+ final LauncherModelOrientationHelper.Coordinates coord = mModelOrientationHelper.getCanonicalCoordinates(item);
+ item.updateValuesWithCoordinates(values, coord.x, coord.y);
+
cr.update(LauncherSettings.Favorites.getContentUri(item.id, false), values, null, null);
}
@@ -293,13 +393,18 @@ public class LauncherModel extends BroadcastReceiver {
}
}
+ public void updateOrientation() {
+ // we update the LauncherModelOrientationHelper orientation whenever we re-initialize
+ mModelOrientationHelper.updateOrientation(mApp);
+ }
+
/**
* Call from the handler for ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and
* ACTION_PACKAGE_CHANGED.
*/
public void onReceive(Context context, Intent intent) {
if (DEBUG_LOADERS) Log.d(TAG, "onReceive intent=" + intent);
-
+
final String action = intent.getAction();
if (Intent.ACTION_PACKAGE_CHANGED.equals(action)
@@ -343,7 +448,6 @@ public class LauncherModel extends BroadcastReceiver {
String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
enqueuePackageUpdated(new PackageUpdatedTask(
PackageUpdatedTask.OP_UNAVAILABLE, packages));
-
}
}
@@ -449,7 +553,7 @@ public class LauncherModel extends BroadcastReceiver {
}
if (DEBUG_LOADERS) {
Log.d(TAG, "waited "
- + (SystemClock.uptimeMillis()-workspaceWaitTime)
+ + (SystemClock.uptimeMillis()-workspaceWaitTime)
+ "ms for previous step to finish binding");
}
}
@@ -469,7 +573,6 @@ public class LauncherModel extends BroadcastReceiver {
android.os.Process.setThreadPriority(mIsLaunching
? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND);
}
-
if (loadWorkspaceFirst) {
if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");
loadAndBindWorkspace();
@@ -571,14 +674,13 @@ public class LauncherModel extends BroadcastReceiver {
if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
return true;
}
-
for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {
for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {
if (occupied[item.screen][x][y] != null) {
Log.e(TAG, "Error loading shortcut " + item
- + " into cell (" + item.screen + ":"
+ + " into cell (" + item.screen + ":"
+ x + "," + y
- + ") occupied by "
+ + ") occupied by "
+ occupied[item.screen][x][y]);
return false;
}
@@ -645,6 +747,11 @@ public class LauncherModel extends BroadcastReceiver {
final int displayModeIndex = c.getColumnIndexOrThrow(
LauncherSettings.Favorites.DISPLAY_MODE);
+
+ LauncherModelOrientationHelper.Coordinates localCoords;
+ int cellX;
+ int cellY;
+
ShortcutInfo info;
String intentDescription;
LauncherAppWidgetInfo appWidgetInfo;
@@ -678,13 +785,17 @@ public class LauncherModel extends BroadcastReceiver {
if (info != null) {
updateSavedIcon(context, info, c, iconIndex);
+ cellX = c.getInt(cellXIndex);
+ cellY = c.getInt(cellYIndex);
+ localCoords = mModelOrientationHelper.getLocalCoordinates(cellX, cellY, 1, 1);
+
info.intent = intent;
info.id = c.getLong(idIndex);
container = c.getInt(containerIndex);
info.container = container;
info.screen = c.getInt(screenIndex);
- info.cellX = c.getInt(cellXIndex);
- info.cellY = c.getInt(cellYIndex);
+ info.cellX = localCoords.x;
+ info.cellY = localCoords.y;
// check & update map of what's occupied
if (!checkItemPlacement(occupied, info)) {
@@ -718,20 +829,22 @@ public class LauncherModel extends BroadcastReceiver {
id = c.getLong(idIndex);
UserFolderInfo folderInfo = findOrMakeUserFolder(mFolders, id);
- folderInfo.title = c.getString(titleIndex);
+ cellX = c.getInt(cellXIndex);
+ cellY = c.getInt(cellYIndex);
+ localCoords = mModelOrientationHelper.getLocalCoordinates(cellX, cellY, 1, 1);
+ folderInfo.title = c.getString(titleIndex);
folderInfo.id = id;
container = c.getInt(containerIndex);
folderInfo.container = container;
folderInfo.screen = c.getInt(screenIndex);
- folderInfo.cellX = c.getInt(cellXIndex);
- folderInfo.cellY = c.getInt(cellYIndex);
+ folderInfo.cellX = localCoords.x;
+ folderInfo.cellY = localCoords.y;
// check & update map of what's occupied
if (!checkItemPlacement(occupied, folderInfo)) {
break;
}
-
switch (container) {
case LauncherSettings.Favorites.CONTAINER_DESKTOP:
mItems.add(folderInfo);
@@ -754,7 +867,6 @@ public class LauncherModel extends BroadcastReceiver {
itemsToRemove.add(id);
} else {
LiveFolderInfo liveFolderInfo = findOrMakeLiveFolder(mFolders, id);
-
intentDescription = c.getString(intentIndex);
intent = null;
if (intentDescription != null) {
@@ -765,14 +877,18 @@ public class LauncherModel extends BroadcastReceiver {
}
}
+ cellX = c.getInt(cellXIndex);
+ cellY = c.getInt(cellYIndex);
+ localCoords = mModelOrientationHelper.getLocalCoordinates(cellX, cellY, 1, 1);
+
liveFolderInfo.title = c.getString(titleIndex);
liveFolderInfo.id = id;
liveFolderInfo.uri = uri;
container = c.getInt(containerIndex);
liveFolderInfo.container = container;
liveFolderInfo.screen = c.getInt(screenIndex);
- liveFolderInfo.cellX = c.getInt(cellXIndex);
- liveFolderInfo.cellY = c.getInt(cellYIndex);
+ liveFolderInfo.cellX = localCoords.x;
+ liveFolderInfo.cellY = localCoords.y;
liveFolderInfo.baseIntent = intent;
liveFolderInfo.displayMode = c.getInt(displayModeIndex);
@@ -800,20 +916,26 @@ public class LauncherModel extends BroadcastReceiver {
final AppWidgetProviderInfo provider =
widgets.getAppWidgetInfo(appWidgetId);
-
+
if (!isSafeMode && (provider == null || provider.provider == null ||
provider.provider.getPackageName() == null)) {
Log.e(TAG, "Deleting widget that isn't installed anymore: id="
+ id + " appWidgetId=" + appWidgetId);
itemsToRemove.add(id);
} else {
+ cellX = c.getInt(cellXIndex);
+ cellY = c.getInt(cellYIndex);
+ int spanX = c.getInt(spanXIndex);
+ int spanY = c.getInt(spanYIndex);
+ localCoords = mModelOrientationHelper.getLocalCoordinates(cellX, cellY, spanX, spanY);
+
appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId);
appWidgetInfo.id = id;
appWidgetInfo.screen = c.getInt(screenIndex);
- appWidgetInfo.cellX = c.getInt(cellXIndex);
- appWidgetInfo.cellY = c.getInt(cellYIndex);
- appWidgetInfo.spanX = c.getInt(spanXIndex);
- appWidgetInfo.spanY = c.getInt(spanYIndex);
+ appWidgetInfo.cellX = localCoords.x;
+ appWidgetInfo.cellY = localCoords.y;
+ appWidgetInfo.spanX = spanX;
+ appWidgetInfo.spanY = spanY;
container = c.getInt(containerIndex);
if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
diff --git a/src/com/android/launcher2/LauncherModelOrientationHelper.java b/src/com/android/launcher2/LauncherModelOrientationHelper.java
new file mode 100644
index 0000000..6a9473d
--- /dev/null
+++ b/src/com/android/launcher2/LauncherModelOrientationHelper.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2010 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.Context;
+import android.view.Display;
+import android.view.Surface;
+import android.view.WindowManager;
+
+public class LauncherModelOrientationHelper {
+
+ static final String TAG = "LauncherModelOrientationHelper";
+
+ public class Coordinates {
+ public Coordinates(int newX, int newY) {
+ x = newX;
+ y = newY;
+ }
+
+ public int x;
+ public int y;
+ }
+
+ private int mOrientation;
+ private int mLocalDeviceWidth;
+ private int mLocalDeviceHeight;
+ private int mPreviousOrientation;
+ private int mPreviousLocalDeviceWidth;
+ private int mPreviousLocalDeviceHeight;
+ private int mCanonicalDeviceWidth;
+ private int mCanonicalDeviceHeight;
+
+ protected LauncherModelOrientationHelper(Context ctx) {
+ updateOrientation(ctx);
+ }
+
+ public int getCurrentOrientation() {
+ return mOrientation;
+ }
+
+ public int getPreviousOrientationRelativeToCurrent() {
+ int orientationDifference = -(mOrientation - mPreviousOrientation);
+
+ if (Math.abs(orientationDifference) > 180) {
+ orientationDifference = (int) -Math.signum(orientationDifference)
+ * (360 - Math.abs(orientationDifference));
+ }
+ return orientationDifference;
+ }
+
+ private void updateLocalDeviceDimensions() {
+ mPreviousLocalDeviceHeight = mLocalDeviceHeight;
+ mPreviousLocalDeviceWidth = mLocalDeviceWidth;
+
+ if (mOrientation % 180 != 0) {
+ mLocalDeviceWidth = mCanonicalDeviceHeight;
+ mLocalDeviceHeight = mCanonicalDeviceWidth;
+ } else {
+ mLocalDeviceWidth = mCanonicalDeviceWidth;
+ mLocalDeviceHeight = mCanonicalDeviceHeight;
+ }
+ }
+
+ public void updateOrientation(Context ctx) {
+ Display display = ((WindowManager) ctx
+ .getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
+
+ mPreviousOrientation = mOrientation;
+ switch (display.getRotation()) {
+ case Surface.ROTATION_0:
+ mOrientation = 0;
+ break;
+ case Surface.ROTATION_90:
+ mOrientation = 90;
+ break;
+ case Surface.ROTATION_180:
+ mOrientation = 180;
+ break;
+ case Surface.ROTATION_270:
+ mOrientation = 270;
+ break;
+ }
+ updateLocalDeviceDimensions();
+ }
+
+ public void updateDeviceDimensions(int deviceWidth, int deviceHeight) {
+ mCanonicalDeviceWidth = deviceWidth;
+ mCanonicalDeviceHeight = deviceHeight;
+
+ updateLocalDeviceDimensions();
+ }
+
+ public Coordinates getLocalCoordinatesFromPreviousLocalCoordinates(
+ int cellX, int cellY, int spanX, int spanY) {
+ return getTransformedLayoutParams(cellX, cellY, spanX, spanY,
+ getPreviousOrientationRelativeToCurrent(),
+ mPreviousLocalDeviceWidth, mPreviousLocalDeviceHeight);
+ }
+
+ public Coordinates getCanonicalCoordinates(ItemInfo localItem) {
+ return getTransformedLayoutParams(localItem.cellX, localItem.cellY,
+ localItem.spanX, localItem.spanY, mOrientation,
+ mLocalDeviceWidth, mLocalDeviceHeight);
+ }
+
+ public Coordinates getCanonicalCoordinates(int cellX, int cellY,
+ int spanX, int spanY) {
+ return getTransformedLayoutParams(cellX, cellY, spanX, spanY,
+ mOrientation, mLocalDeviceWidth, mLocalDeviceHeight);
+ }
+
+ public Coordinates getLocalCoordinates(int cellX, int cellY, int spanX,
+ int spanY) {
+ return getTransformedLayoutParams(cellX, cellY, spanX, spanY,
+ -mOrientation, mCanonicalDeviceWidth, mCanonicalDeviceHeight);
+ }
+
+ public int getLocalDeviceWidth() {
+ return mLocalDeviceWidth;
+ }
+
+ public int getLocalDeviceHeight() {
+ return mLocalDeviceHeight;
+ }
+
+ /**
+ * Transform the coordinates based on the current device rotation
+ */
+ private Coordinates getTransformedLayoutParams(int cellX, int cellY,
+ int spanX, int spanY, int deviceRotationClockwise,
+ int initialDeviceWidth, int initialDeviceHeight) {
+ if (LauncherApplication.isScreenXLarge()) {
+ int x = cellX;
+ int y = cellY;
+ int width = spanX;
+ int height = spanY;
+ int finalDeviceWidth = initialDeviceWidth;
+ int finalDeviceHeight = initialDeviceHeight;
+
+ // item rotation is opposite of device rotation to maintain an
+ // absolute
+ // spatial layout
+ double phi = Math.toRadians(-deviceRotationClockwise);
+
+ double x1 = x + width / 2.0f - initialDeviceWidth / 2.0f;
+ double y1 = y + height / 2.0f - initialDeviceHeight / 2.0f;
+
+ // multiply x and y by a clockwise rotation matrix
+ double x2 = x1 * Math.cos(phi) + y1 * Math.sin(phi);
+ double y2 = -x1 * Math.sin(phi) + y1 * Math.cos(phi);
+
+ // Get the rotated device dimensions
+ if (deviceRotationClockwise % 180 != 0) {
+ finalDeviceWidth = initialDeviceHeight;
+ finalDeviceHeight = initialDeviceWidth;
+ }
+
+ x2 = x2 + finalDeviceWidth / 2.0f - width / 2.0f;
+ y2 = y2 + finalDeviceHeight / 2.0f - height / 2.0f;
+
+ return new Coordinates((int) Math.round(x2), (int) Math.round(y2));
+ } else {
+ return new Coordinates(cellX, cellY);
+ }
+ }
+}
diff --git a/src/com/android/launcher2/LiveFolderInfo.java b/src/com/android/launcher2/LiveFolderInfo.java
index 7d0a0f5..74b0217 100644
--- a/src/com/android/launcher2/LiveFolderInfo.java
+++ b/src/com/android/launcher2/LiveFolderInfo.java
@@ -18,7 +18,6 @@ package com.android.launcher2;
import android.content.ContentValues;
import android.content.Intent;
-import android.graphics.drawable.Drawable;
import android.graphics.Bitmap;
import android.net.Uri;
diff --git a/src/com/android/launcher2/ShortcutChooser.java b/src/com/android/launcher2/ShortcutChooser.java
new file mode 100644
index 0000000..1e3e5d0
--- /dev/null
+++ b/src/com/android/launcher2/ShortcutChooser.java
@@ -0,0 +1,37 @@
+package com.android.launcher2;
+
+import com.android.launcher.R;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.AdapterView;
+
+public class ShortcutChooser extends HomeCustomizationItemGallery {
+
+ public ShortcutChooser(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
+ // todo: this code sorta overlaps with other places
+ ResolveInfo info = (ResolveInfo)getAdapter().getItem(position);
+ mLauncher.prepareAddItemFromHomeCustomizationDrawer();
+
+ Intent createShortcutIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
+ if (info.labelRes == R.string.group_applications) {
+ // Create app shortcuts is a special built-in case of shortcuts
+ createShortcutIntent.putExtra(
+ Intent.EXTRA_SHORTCUT_NAME,getContext().getString(R.string.group_applications));
+ } else {
+ ComponentName name = new ComponentName(info.activityInfo.packageName, info.activityInfo.name);
+ createShortcutIntent.setComponent(name);
+ }
+ mLauncher.processShortcut(createShortcutIntent);
+
+ return true;
+ }
+}
diff --git a/src/com/android/launcher2/ShortcutInfo.java b/src/com/android/launcher2/ShortcutInfo.java
index 5c322ba..b0da3a5 100644
--- a/src/com/android/launcher2/ShortcutInfo.java
+++ b/src/com/android/launcher2/ShortcutInfo.java
@@ -16,16 +16,14 @@
package com.android.launcher2;
+import java.util.ArrayList;
+
import android.content.ComponentName;
import android.content.ContentValues;
-import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
-import android.graphics.drawable.Drawable;
import android.util.Log;
-import java.util.ArrayList;
-
/**
* Represents a launchable icon on the workspaces and in folders.
*/
diff --git a/src/com/android/launcher2/ShortcutListAdapter.java b/src/com/android/launcher2/ShortcutListAdapter.java
new file mode 100644
index 0000000..be05ca4
--- /dev/null
+++ b/src/com/android/launcher2/ShortcutListAdapter.java
@@ -0,0 +1,26 @@
+package com.android.launcher2;
+
+import com.android.launcher.R;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.Intent.ShortcutIconResource;
+import android.content.pm.ResolveInfo;
+
+import java.util.ArrayList;
+
+
+public class ShortcutListAdapter extends IntentListAdapter {
+
+ public ShortcutListAdapter(Context context, String actionFilter) {
+ super(context, actionFilter);
+
+ // Manually create a separate entry for creating an Application shortcut
+ ResolveInfo folder = new ResolveInfo();
+
+ folder.icon = R.drawable.ic_launcher_application;
+ folder.labelRes = R.string.group_applications;
+ folder.resolvePackageName = context.getPackageName();
+ mIntentList.add(0, folder);
+ }
+}
diff --git a/src/com/android/launcher2/ShortcutsAdapter.java b/src/com/android/launcher2/ShortcutsAdapter.java
index 19c3af0..93c500a 100644
--- a/src/com/android/launcher2/ShortcutsAdapter.java
+++ b/src/com/android/launcher2/ShortcutsAdapter.java
@@ -16,16 +16,15 @@
package com.android.launcher2;
+import java.util.ArrayList;
+
import android.content.Context;
-import android.content.pm.PackageManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
-import java.util.ArrayList;
-
import com.android.launcher.R;
/**
diff --git a/src/com/android/launcher2/SymmetricalLinearTween.java b/src/com/android/launcher2/SymmetricalLinearTween.java
index 2e0ed8f..da02242 100644
--- a/src/com/android/launcher2/SymmetricalLinearTween.java
+++ b/src/com/android/launcher2/SymmetricalLinearTween.java
@@ -17,9 +17,7 @@
package com.android.launcher2;
import android.os.Handler;
-import android.os.Message;
import android.os.SystemClock;
-import android.util.Log;
/**
* Provides an animation between 0.0f and 1.0f over a given duration.
diff --git a/src/com/android/launcher2/UserFolder.java b/src/com/android/launcher2/UserFolder.java
index d49c27a..b46e924 100644
--- a/src/com/android/launcher2/UserFolder.java
+++ b/src/com/android/launcher2/UserFolder.java
@@ -3,10 +3,8 @@ package com.android.launcher2;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
-import android.widget.ArrayAdapter;
import com.android.launcher.R;
@@ -91,4 +89,10 @@ public class UserFolder extends Folder implements DropTarget {
super.onOpen();
requestFocus();
}
+
+ @Override
+ public DropTarget getDropTargetDelegate(DragSource source, int x, int y, int xOffset, int yOffset,
+ DragView dragView, Object dragInfo) {
+ return null;
+ }
}
diff --git a/src/com/android/launcher2/Utilities.java b/src/com/android/launcher2/Utilities.java
index 757e48e..c67ff99 100644
--- a/src/com/android/launcher2/Utilities.java
+++ b/src/com/android/launcher2/Utilities.java
@@ -16,9 +16,8 @@
package com.android.launcher2;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.PaintDrawable;
+import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
@@ -26,19 +25,19 @@ import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
-import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.TableMaskFilter;
import android.graphics.Typeface;
-import android.text.Layout.Alignment;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.PaintDrawable;
import android.text.StaticLayout;
import android.text.TextPaint;
+import android.text.Layout.Alignment;
import android.util.DisplayMetrics;
import android.util.Log;
-import android.content.res.Resources;
-import android.content.Context;
import com.android.launcher.R;
diff --git a/src/com/android/launcher2/WidgetChooser.java b/src/com/android/launcher2/WidgetChooser.java
new file mode 100644
index 0000000..ea6888e
--- /dev/null
+++ b/src/com/android/launcher2/WidgetChooser.java
@@ -0,0 +1,47 @@
+package com.android.launcher2;
+
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.TextView;
+
+public class WidgetChooser extends HomeCustomizationItemGallery implements DragSource {
+ private DragController mDragController;
+
+ public WidgetChooser(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public void setDragController(DragController dragger) {
+ mDragController = dragger;
+ }
+
+ public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
+ Drawable[] drawables = ((TextView)view).getCompoundDrawables();
+ Bitmap bmp = ((BitmapDrawable)drawables[1]).getBitmap();
+ final int w = bmp.getWidth();
+ final int h = bmp.getHeight();
+
+ // We don't really have an accurate location to use. This will do.
+ int screenX = mMotionDownRawX - (w / 2);
+ int screenY = mMotionDownRawY - h;
+
+ AppWidgetProviderInfo info = (AppWidgetProviderInfo)getAdapter().getItem(position);
+ LauncherAppWidgetInfo dragInfo = new LauncherAppWidgetInfo(info.provider);
+ // TODO: Is this really the best place to do this?
+ dragInfo.minWidth = info.minWidth;
+ dragInfo.minHeight = info.minHeight;
+ mDragController.startDrag(bmp, screenX, screenY,
+ 0, 0, w, h, this, dragInfo, DragController.DRAG_ACTION_COPY);
+ return true;
+ }
+
+ public void onDropCompleted(View target, boolean success) {
+ }
+}
+
diff --git a/src/com/android/launcher2/WidgetListAdapter.java b/src/com/android/launcher2/WidgetListAdapter.java
new file mode 100644
index 0000000..597ecf9
--- /dev/null
+++ b/src/com/android/launcher2/WidgetListAdapter.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2010 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 com.android.launcher.R;
+
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.Region.Op;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.TextView;
+
+import java.util.List;
+
+public class WidgetListAdapter extends BaseAdapter {
+ private final Launcher mLauncher;
+ private List<AppWidgetProviderInfo> mWidgets;
+ private final Canvas mCanvas = new Canvas();
+
+ private final int[] mTempSize = new int[2];
+ private final Rect mTempRect = new Rect();
+
+ private static final String TAG = "Launcher.WidgetGalleryAdapter";
+
+ WidgetListAdapter(Launcher launcher) {
+ mLauncher = launcher;
+ mWidgets = AppWidgetManager.getInstance(launcher).getInstalledProviders();
+ }
+
+ public int getCount() {
+ return mWidgets.size();
+ }
+
+ public Object getItem(int position) {
+ return mWidgets.get(position);
+ }
+
+ public long getItemId(int position) {
+ return position;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ TextView textView;
+
+ if (convertView == null) {
+ LayoutInflater inflater =
+ (LayoutInflater)mLauncher.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ textView = (TextView) inflater.inflate(
+ R.layout.home_customization_drawer_item, parent, false);
+ } else {
+ textView = (TextView) convertView;
+ }
+
+ AppWidgetProviderInfo info = mWidgets.get(position);
+ PackageManager packageManager = mLauncher.getPackageManager();
+ String packageName = info.provider.getPackageName();
+ Drawable drawable = null;
+ if (info.previewImage != 0) {
+ drawable = packageManager.getDrawable(packageName, info.previewImage, null);
+ if (drawable == null) {
+ Log.w(TAG, "Can't load icon drawable 0x" + Integer.toHexString(info.icon)
+ + " for provider: " + info.provider);
+ }
+ }
+ // If we don't have a preview image, create a default one
+ if (drawable == null) {
+ Resources resources = mLauncher.getResources();
+
+ // Determine the size the widget will take in the layout
+ mLauncher.getWorkspace().estimateChildSize(info.minWidth, info.minHeight, mTempSize);
+
+ // Create a new bitmap to hold the widget preview
+ final int width = mTempSize[0];
+ final int height = mTempSize[1];
+ Bitmap bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
+ mCanvas.setBitmap(bitmap);
+ // For some reason, we must re-set the clip rect here, otherwise it will be wrong
+ mCanvas.clipRect(0, 0, width, height, Op.REPLACE);
+
+ Drawable background = resources.getDrawable(R.drawable.default_widget_preview);
+ background.setBounds(0, 0, width, height);
+ background.draw(mCanvas);
+
+ // Draw the icon vertically centered, flush left
+ Drawable icon = packageManager.getDrawable(packageName, info.icon, null);
+ background.getPadding(mTempRect);
+
+ final int left = mTempRect.left;
+ final int top = (height - icon.getIntrinsicHeight()) / 2;
+ icon.setBounds(
+ left, top, left + icon.getIntrinsicWidth(), top + icon.getIntrinsicHeight());
+ icon.draw(mCanvas);
+
+ drawable = new BitmapDrawable(resources, bitmap);
+ }
+ drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
+ textView.setCompoundDrawables(null, drawable, null, null);
+ textView.setText(info.label);
+ // Store the widget info on the associated view so we can easily fetch it later
+ textView.setTag(info);
+
+ return textView;
+ }
+}
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index c337c30..79fb4a9 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -16,8 +16,7 @@
package com.android.launcher2;
-import java.util.ArrayList;
-import java.util.HashSet;
+import com.android.launcher.R;
import android.app.WallpaperManager;
import android.appwidget.AppWidgetManager;
@@ -29,6 +28,7 @@ import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.content.res.TypedArray;
import android.graphics.Canvas;
+import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.net.Uri;
@@ -43,29 +43,35 @@ import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewParent;
+import android.view.animation.Animation;
+import android.view.animation.Animation.AnimationListener;
import android.view.animation.Interpolator;
+import android.view.animation.RotateAnimation;
import android.widget.Scroller;
import android.widget.TextView;
+import android.widget.Toast;
-import com.android.launcher.R;
+import java.util.ArrayList;
+import java.util.HashSet;
/**
- * The workspace is a wide area with a wallpaper and a finite number of screens. Each
- * screen contains a number of icons, folders or widgets the user can interact with.
- * A workspace is meant to be used with a fixed width only.
+ * The workspace is a wide area with a wallpaper and a finite number of screens.
+ * Each screen contains a number of icons, folders or widgets the user can
+ * interact with. A workspace is meant to be used with a fixed width only.
*/
public class Workspace extends ViewGroup implements DropTarget, DragSource, DragScroller {
@SuppressWarnings({"UnusedDeclaration"})
private static final String TAG = "Launcher.Workspace";
private static final int INVALID_SCREEN = -1;
-
+
/**
- * The velocity at which a fling gesture will cause us to snap to the next screen
+ * The velocity at which a fling gesture will cause us to snap to the next
+ * screen
*/
private static final int SNAP_VELOCITY = 600;
private final WallpaperManager mWallpaperManager;
-
+
private int mDefaultScreen;
private boolean mFirstLayout = true;
@@ -79,31 +85,37 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
* CellInfo for the cell that is currently being dragged
*/
private CellLayout.CellInfo mDragInfo;
-
+
/**
* Target drop area calculated during last acceptDrop call.
*/
private int[] mTargetCell = null;
+ /**
+ * The CellLayout that is currently being dragged over
+ */
+ private CellLayout mDragTargetLayout = null;
+
private float mLastMotionX;
private float mLastMotionY;
-
+
private final static int TOUCH_STATE_REST = 0;
private final static int TOUCH_STATE_SCROLLING = 1;
private int mTouchState = TOUCH_STATE_REST;
+ private OnTouchListener mInterceptTouchListener;
private OnLongClickListener mLongClickListener;
private Launcher mLauncher;
private IconCache mIconCache;
private DragController mDragController;
-
+
/**
* Cache of vacant cells, used during drag events and invalidated as needed.
*/
private CellLayout.CellInfo mVacantCache = null;
-
+
private int[] mTempCell = new int[2];
private int[] mTempEstimate = new int[2];
@@ -111,14 +123,14 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
private int mTouchSlop;
private int mMaximumVelocity;
-
+
private static final int INVALID_POINTER = -1;
private int mActivePointerId = INVALID_POINTER;
-
+
private Drawable mPreviousIndicator;
private Drawable mNextIndicator;
-
+
private static final float NANOTIME_DIV = 1000000000.0f;
private static final float SMOOTHING_SPEED = 0.75f;
private static final float SMOOTHING_CONSTANT = (float) (0.016 / Math.log(SMOOTHING_SPEED));
@@ -129,7 +141,9 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
private static final float BASELINE_FLING_VELOCITY = 2500.f;
private static final float FLING_VELOCITY_INFLUENCE = 0.4f;
-
+
+ private Paint mDropIndicatorPaint;
+
private static class WorkspaceOvershootInterpolator implements Interpolator {
private static final float DEFAULT_TENSION = 1.3f;
private float mTension;
@@ -137,7 +151,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
public WorkspaceOvershootInterpolator() {
mTension = DEFAULT_TENSION;
}
-
+
public void setDistance(int distance) {
mTension = distance > 0 ? DEFAULT_TENSION / distance : DEFAULT_TENSION;
}
@@ -153,7 +167,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
return t * t * ((mTension + 1) * t + mTension) + 1.0f;
}
}
-
+
/**
* Used to inflate the Workspace from XML.
*
@@ -175,11 +189,16 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
super(context, attrs, defStyle);
mWallpaperManager = WallpaperManager.getInstance(context);
-
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Workspace, defStyle, 0);
+
+ TypedArray a = context.obtainStyledAttributes(attrs,
+ R.styleable.Workspace, defStyle, 0);
+ int canonicalDeviceWidth = a.getInt(R.styleable.Workspace_canonicalDeviceWidth, 4);
+ int canonicalDeviceHeight = a.getInt(R.styleable.Workspace_canonicalDeviceHeight, 4);
mDefaultScreen = a.getInt(R.styleable.Workspace_defaultScreen, 1);
a.recycle();
+ LauncherModel.updateWorkspaceLayoutCells(canonicalDeviceWidth,
+ canonicalDeviceHeight);
setHapticFeedbackEnabled(false);
initWorkspace();
}
@@ -249,9 +268,10 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
int count = currentScreen.getChildCount();
for (int i = 0; i < count; i++) {
View child = currentScreen.getChildAt(i);
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
- if (lp.cellHSpan == 4 && lp.cellVSpan == 4 && child instanceof Folder) {
- return (Folder) child;
+ if (child instanceof Folder) {
+ Folder folder = (Folder) child;
+ if (folder.getInfo().opened)
+ return folder;
}
}
return null;
@@ -266,9 +286,12 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
int count = currentScreen.getChildCount();
for (int i = 0; i < count; i++) {
View child = currentScreen.getChildAt(i);
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
- if (lp.cellHSpan == 4 && lp.cellVSpan == 4 && child instanceof Folder) {
- folders.add((Folder) child);
+ CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child
+ .getLayoutParams();
+ if (child instanceof Folder) {
+ Folder folder = (Folder) child;
+ if (folder.getInfo().opened)
+ folders.add(folder);
break;
}
}
@@ -296,11 +319,15 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
* @param currentScreen
*/
void setCurrentScreen(int currentScreen) {
- if (!mScroller.isFinished()) mScroller.abortAnimation();
+ if (!mScroller.isFinished())
+ mScroller.abortAnimation();
clearVacantCache();
mCurrentScreen = Math.max(0, Math.min(currentScreen, getChildCount() - 1));
- mPreviousIndicator.setLevel(mCurrentScreen);
- mNextIndicator.setLevel(mCurrentScreen);
+ if (mPreviousIndicator != null) {
+ mPreviousIndicator.setLevel(mCurrentScreen);
+ mNextIndicator.setLevel(mCurrentScreen);
+ }
+
scrollTo(mCurrentScreen * getWidth(), 0);
updateWallpaperOffset();
invalidate();
@@ -350,6 +377,85 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
addInScreen(child, screen, x, y, spanX, spanY, false);
}
+ void addInFullScreen(View child, int screen) {
+ addInScreen(child, screen, 0, 0, -1, -1);
+ }
+
+ public void rotateCurrentScreensChildren() {
+
+ // close all the folders first
+ final ArrayList<Folder> openFolders = getOpenFolders();
+
+ WorkspaceOvershootInterpolator wi = new WorkspaceOvershootInterpolator();
+ RotateAnimation ra = new RotateAnimation((float) LauncherModel
+ .getPreviousOrientationRelativeToCurrent(), 0,
+ Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
+ 0.5f);
+ ra.setInterpolator(wi);
+ CellLayout currentScreen = (CellLayout) getChildAt(mCurrentScreen);
+ ra.setStartOffset(150);
+ ra.setDuration(650 + (int) (Math.random() * 400) - 200);
+
+ CellLayout.CellLayoutAnimationController animationController = new CellLayout.CellLayoutAnimationController(
+ ra, 0.0f);
+ currentScreen.setLayoutAnimation(animationController);
+ currentScreen.setLayoutAnimationListener(new AnimationListener() {
+ public void onAnimationStart(Animation animation) {
+ // do nothing
+ }
+
+ public void onAnimationRepeat(Animation animation) {
+ // do nothing
+ }
+
+ public void onAnimationEnd(Animation animation) {
+ for (int j = 0; j < openFolders.size(); ++j) {
+ Folder folder = openFolders.get(j);
+ if (!folder.getInfo().opened) {
+ mLauncher.openFolder(folder.getInfo());
+ }
+ }
+ }
+ });
+ animationController.start();
+
+ for (int j = 0; j < openFolders.size(); ++j) {
+ mLauncher.closeFolder(openFolders.get(j));
+ }
+ }
+
+ public void refreshWorkspaceChildren() {
+ final int count = getChildCount();
+ View child;
+
+ CellLayout.LayoutParams lp;
+ int widthMeasureSpec = MeasureSpec.makeMeasureSpec(LauncherModel
+ .getLocalDeviceWidth(), MeasureSpec.EXACTLY);
+ int heightMeasureSpec = MeasureSpec.makeMeasureSpec(LauncherModel
+ .getLocalDeviceHeight(), MeasureSpec.EXACTLY);
+
+ clearVacantCache();
+
+ for (int i = 0; i < count; i++) {
+ final CellLayout layout = (CellLayout) getChildAt(i);
+ int numChildren = layout.getChildCount();
+
+ // save reference to all current children
+ for (int j = 0; j < numChildren; j++) {
+ child = layout.getChildAt(j);
+
+ lp = (CellLayout.LayoutParams) child.getLayoutParams();
+ LauncherModelOrientationHelper.Coordinates localCoord = LauncherModel
+ .getLocalCoordinatesFromPreviousLocalCoordinates(lp);
+
+ lp.cellX = localCoord.x;
+ lp.cellY = localCoord.y;
+ }
+
+ layout.measure(widthMeasureSpec, heightMeasureSpec);
+ }
+ }
+
/**
* Adds the specified child in the specified screen. The position and dimension of
* the child are defined by x, y, spanX and spanY.
@@ -381,13 +487,22 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
lp.cellHSpan = spanX;
lp.cellVSpan = spanY;
}
- group.addView(child, insert ? 0 : -1, lp);
+
+ // Get the canonical child id to uniquely represent this view in this screen
+ int childId = LauncherModel.getCanonicalCellLayoutChildId(child.getId(), screen, x, y, spanX, spanY);
+ if (!group.addViewToCellLayout(child, insert ? 0 : -1, childId, lp)) {
+ // TODO: This branch occurs when the workspace is adding views
+ // outside of the defined grid
+ // maybe we should be deleting these items from the LauncherModel?
+ Log.w(TAG, "Failed to add to item at (" + lp.cellX + "," + lp.cellY + ") to CellLayout");
+ }
+
if (!(child instanceof Folder)) {
child.setHapticFeedbackEnabled(false);
child.setOnLongClickListener(mLongClickListener);
}
if (child instanceof DropTarget) {
- mDragController.addDropTarget((DropTarget)child);
+ mDragController.addDropTarget((DropTarget) child);
}
}
@@ -406,6 +521,10 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
}
}
+ public void setOnInterceptTouchListener(View.OnTouchListener listener) {
+ mInterceptTouchListener = listener;
+ }
+
/**
* Registers the specified listener on each screen contained in this workspace.
*
@@ -432,14 +551,14 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
Math.max(0.f, Math.min(mScrollX/(float)scrollRange, 1.f)), 0);
}
}
-
+
@Override
public void scrollTo(int x, int y) {
super.scrollTo(x, y);
mTouchX = x;
mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
}
-
+
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
@@ -450,8 +569,10 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
postInvalidate();
} else if (mNextScreen != INVALID_SCREEN) {
mCurrentScreen = Math.max(0, Math.min(mNextScreen, getChildCount() - 1));
- mPreviousIndicator.setLevel(mCurrentScreen);
- mNextIndicator.setLevel(mCurrentScreen);
+ if (mPreviousIndicator != null) {
+ mPreviousIndicator.setLevel(mCurrentScreen);
+ mNextIndicator.setLevel(mCurrentScreen);
+ }
Launcher.setScreen(mCurrentScreen);
mNextScreen = INVALID_SCREEN;
clearChildrenCache();
@@ -529,7 +650,6 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
}
-
if (mFirstLayout) {
setHorizontalScrollBarEnabled(false);
scrollTo(mCurrentScreen * width, 0);
@@ -552,6 +672,12 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
childLeft += childWidth;
}
}
+
+ if (LauncherApplication.isInPlaceRotationEnabled()) {
+ // When the device is rotated, the scroll position of the current screen
+ // needs to be refreshed
+ setCurrentScreen(getCurrentScreen());
+ }
}
@Override
@@ -611,7 +737,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
if (mCurrentScreen > 0) {
getChildAt(mCurrentScreen - 1).addFocusables(views, direction);
}
- } else if (direction == View.FOCUS_RIGHT){
+ } else if (direction == View.FOCUS_RIGHT) {
if (mCurrentScreen < getChildCount() - 1) {
getChildAt(mCurrentScreen + 1).addFocusables(views, direction);
}
@@ -634,6 +760,9 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
+ if (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev)) {
+ return true;
+ }
final boolean workspaceLocked = mLauncher.isWorkspaceLocked();
final boolean allAppsVisible = mLauncher.isAllAppsVisible();
if (workspaceLocked || allAppsVisible) {
@@ -660,7 +789,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(ev);
-
+
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_MOVE: {
/*
@@ -681,9 +810,9 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
final int touchSlop = mTouchSlop;
boolean xMoved = xDiff > touchSlop;
boolean yMoved = yDiff > touchSlop;
-
+
if (xMoved || yMoved) {
-
+
if (xMoved) {
// Scroll if the user moved far enough along the X axis
mTouchState = TOUCH_STATE_SCROLLING;
@@ -705,14 +834,14 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
break;
}
- case MotionEvent.ACTION_DOWN: {
- final float x = ev.getX();
- final float y = ev.getY();
- // Remember location of down touch
- mLastMotionX = x;
- mLastMotionY = y;
- mActivePointerId = ev.getPointerId(0);
- mAllowLongPress = true;
+ case MotionEvent.ACTION_DOWN: {
+ final float x = ev.getX();
+ final float y = ev.getY();
+ // Remember location of down touch
+ mLastMotionX = x;
+ mLastMotionY = y;
+ mActivePointerId = ev.getPointerId(0);
+ mAllowLongPress = true;
/*
* If being flinged and user touches the screen, initiate drag;
@@ -725,36 +854,36 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
-
+
if (mTouchState != TOUCH_STATE_SCROLLING) {
final CellLayout currentScreen = (CellLayout)getChildAt(mCurrentScreen);
if (!currentScreen.lastDownOnOccupiedCell()) {
getLocationOnScreen(mTempCell);
// Send a tap to the wallpaper if the last down was on empty space
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
- mWallpaperManager.sendWallpaperCommand(getWindowToken(),
+ mWallpaperManager.sendWallpaperCommand(getWindowToken(),
"android.wallpaper.tap",
mTempCell[0] + (int) ev.getX(pointerIndex),
mTempCell[1] + (int) ev.getY(pointerIndex), 0, null);
}
}
-
+
// Release the drag
clearChildrenCache();
mTouchState = TOUCH_STATE_REST;
mActivePointerId = INVALID_POINTER;
mAllowLongPress = false;
-
+
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
- break;
-
- case MotionEvent.ACTION_POINTER_UP:
- onSecondaryPointerUp(ev);
- break;
+ break;
+
+ case MotionEvent.ACTION_POINTER_UP:
+ onSecondaryPointerUp(ev);
+ break;
}
/*
@@ -763,7 +892,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
*/
return mTouchState != TOUCH_STATE_REST;
}
-
+
private void onSecondaryPointerUp(MotionEvent ev) {
final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >>
MotionEvent.ACTION_POINTER_INDEX_SHIFT;
@@ -803,7 +932,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
}
ViewParent parent = v.getParent();
if (parent instanceof View) {
- v = (View)v.getParent();
+ v = (View) v.getParent();
} else {
return;
}
@@ -816,7 +945,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
fromScreen = toScreen;
toScreen = temp;
}
-
+
final int count = getChildCount();
fromScreen = Math.max(fromScreen, 0);
@@ -839,7 +968,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
@Override
public boolean onTouchEvent(MotionEvent ev) {
-
+
if (mLauncher.isWorkspaceLocked()) {
return false; // We don't want the events. Let them fall through to the all apps view.
}
@@ -908,11 +1037,11 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
final VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
final int velocityX = (int) velocityTracker.getXVelocity(mActivePointerId);
-
+
final int screenWidth = getWidth();
final int whichScreen = (mScrollX + (screenWidth / 2)) / screenWidth;
final float scrolledPos = (float) mScrollX / screenWidth;
-
+
if (velocityX > SNAP_VELOCITY && mCurrentScreen > 0) {
// Fling hard enough to move left.
// Don't fling across more than one screen at a time.
@@ -948,30 +1077,32 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
return true;
}
-
+
void snapToScreen(int whichScreen) {
snapToScreen(whichScreen, 0, false);
}
private void snapToScreen(int whichScreen, int velocity, boolean settle) {
- //if (!mScroller.isFinished()) return;
+ // if (!mScroller.isFinished()) return;
whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));
-
+
clearVacantCache();
enableChildrenCache(mCurrentScreen, whichScreen);
mNextScreen = whichScreen;
- mPreviousIndicator.setLevel(mNextScreen);
- mNextIndicator.setLevel(mNextScreen);
+ if (mPreviousIndicator != null) {
+ mPreviousIndicator.setLevel(mNextScreen);
+ mNextIndicator.setLevel(mNextScreen);
+ }
View focusedChild = getFocusedChild();
if (focusedChild != null && whichScreen != mCurrentScreen &&
focusedChild == getChildAt(mCurrentScreen)) {
focusedChild.clearFocus();
}
-
+
final int screenDelta = Math.max(1, Math.abs(whichScreen - mCurrentScreen));
final int newX = whichScreen * getWidth();
final int delta = newX - mScrollX;
@@ -980,13 +1111,13 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
-
+
if (settle) {
mScrollInterpolator.setDistance(screenDelta);
} else {
mScrollInterpolator.disableSettle();
}
-
+
velocity = Math.abs(velocity);
if (velocity > 0) {
duration += (duration / (velocity / BASELINE_FLING_VELOCITY))
@@ -1002,15 +1133,15 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
void startDrag(CellLayout.CellInfo cellInfo) {
View child = cellInfo.cell;
-
+
// Make sure the drag was started by a long press as opposed to a long click.
if (!child.isInTouchMode()) {
return;
}
-
+
mDragInfo = cellInfo;
mDragInfo.screen = mCurrentScreen;
-
+
CellLayout current = ((CellLayout) getChildAt(mCurrentScreen));
current.onDragChild(child);
@@ -1057,81 +1188,164 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
// Move internally
if (mDragInfo != null) {
final View cell = mDragInfo.cell;
- int index = mScroller.isFinished() ? mCurrentScreen : mNextScreen;
+ int index = mScroller.isFinished() ? mCurrentScreen : mNextScreen;
if (index != mDragInfo.screen) {
final CellLayout originalCellLayout = (CellLayout) getChildAt(mDragInfo.screen);
originalCellLayout.removeView(cell);
- cellLayout.addView(cell);
+ addInScreen(cell, index, mDragInfo.cellX, mDragInfo.cellY,
+ mDragInfo.spanX, mDragInfo.spanY);
}
mTargetCell = estimateDropCell(x - xOffset, y - yOffset,
- mDragInfo.spanX, mDragInfo.spanY, cell, cellLayout, mTargetCell);
- cellLayout.onDropChild(cell, mTargetCell);
+ mDragInfo.spanX, mDragInfo.spanY, cell, cellLayout,
+ mTargetCell);
+ cellLayout.onDropChild(cell);
+ // update the item's position after drop
final ItemInfo info = (ItemInfo) cell.getTag();
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams();
+ CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell
+ .getLayoutParams();
+ lp.cellX = mTargetCell[0];
+ lp.cellY = mTargetCell[1];
+
LauncherModel.moveItemInDatabase(mLauncher, info,
- LauncherSettings.Favorites.CONTAINER_DESKTOP, index, lp.cellX, lp.cellY);
+ LauncherSettings.Favorites.CONTAINER_DESKTOP, index,
+ lp.cellX, lp.cellY);
}
}
}
- public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
- DragView dragView, Object dragInfo) {
+ public void onDragEnter(DragSource source, int x, int y, int xOffset,
+ int yOffset, DragView dragView, Object dragInfo) {
clearVacantCache();
}
- public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
+ public DropTarget getDropTargetDelegate(DragSource source, int x, int y, int xOffset, int yOffset,
DragView dragView, Object dragInfo) {
+
+ // We may need to delegate the drag to a child view. If a 1x1 item
+ // would land in a cell occupied by a DragTarget (e.g. a Folder),
+ // then drag events should be handled by that child.
+
+ ItemInfo item = (ItemInfo)dragInfo;
+ CellLayout currentLayout = getCurrentDropLayout();
+
+ int dragPointX, dragPointY;
+ if (item.spanX == 1 && item.spanY == 1) {
+ // For a 1x1, calculate the drop cell exactly as in onDragOver
+ dragPointX = x - xOffset;
+ dragPointY = y - yOffset;
+ } else {
+ // Otherwise, use the exact drag coordinates
+ dragPointX = x;
+ dragPointY = y;
+ }
+
+ // If we are dragging over a cell that contains a DropTarget that will
+ // accept the drop, delegate to that DropTarget.
+ final int[] cellXY = mTempCell;
+ currentLayout.estimateDropCell(dragPointX, dragPointY, item.spanX, item.spanY, cellXY);
+ View child = currentLayout.getChildAt(cellXY[0], cellXY[1]);
+ if (child instanceof DropTarget) {
+ DropTarget target = (DropTarget)child;
+ if (target.acceptDrop(source, x, y, xOffset, yOffset, dragView, dragInfo)) {
+ return target;
+ }
+ }
+ return null;
}
- public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset,
+ public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
DragView dragView, Object dragInfo) {
+
+ ItemInfo item = (ItemInfo)dragInfo;
+ CellLayout currentLayout = getCurrentDropLayout();
+
+ if (dragInfo instanceof LauncherAppWidgetInfo) {
+ LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo)dragInfo;
+
+ if (widgetInfo.spanX == -1) {
+ // Calculate the grid spans needed to fit this widget
+ int[] spans = currentLayout.rectToCell(widgetInfo.minWidth, widgetInfo.minHeight, null);
+ item.spanX = spans[0];
+ item.spanY = spans[1];
+ }
+ }
+ if (currentLayout != mDragTargetLayout) {
+ if (mDragTargetLayout != null) {
+ mDragTargetLayout.onDragComplete();
+ }
+ mDragTargetLayout = currentLayout;
+ }
+
+ // Find the top left corner of the item
+ int originX = x - xOffset;
+ int originY = y - yOffset;
+
+ final View child = (mDragInfo == null) ? null : mDragInfo.cell;
+ currentLayout.visualizeDropLocation(child, originX, originY, item.spanX, item.spanY);
+ }
+
+ public void onDragExit(DragSource source, int x, int y, int xOffset,
+ int yOffset, DragView dragView, Object dragInfo) {
clearVacantCache();
+ if (mDragTargetLayout != null) {
+ mDragTargetLayout.onDragComplete();
+ mDragTargetLayout = null;
+ }
}
- private void onDropExternal(int x, int y, Object dragInfo, CellLayout cellLayout) {
+ private void onDropExternal(int x, int y, Object dragInfo,
+ CellLayout cellLayout) {
onDropExternal(x, y, dragInfo, cellLayout, false);
}
-
- private void onDropExternal(int x, int y, Object dragInfo, CellLayout cellLayout,
- boolean insertAtFirst) {
+
+ private void onDropExternal(int x, int y, Object dragInfo,
+ CellLayout cellLayout, boolean insertAtFirst) {
// Drag from somewhere else
ItemInfo info = (ItemInfo) dragInfo;
- View view;
+ View view = null;
switch (info.itemType) {
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
if (info.container == NO_ID && info instanceof ApplicationInfo) {
// Came from all apps -- make a copy
- info = new ShortcutInfo((ApplicationInfo)info);
+ info = new ShortcutInfo((ApplicationInfo) info);
}
- view = mLauncher.createShortcut(R.layout.application, cellLayout, (ShortcutInfo)info);
+ view = mLauncher.createShortcut(R.layout.application, cellLayout,
+ (ShortcutInfo) info);
break;
case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER:
view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher,
- (ViewGroup) getChildAt(mCurrentScreen), ((UserFolderInfo) info));
+ (ViewGroup) getChildAt(mCurrentScreen),
+ ((UserFolderInfo) info));
+ break;
+ case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
+ cellLayout.setTagToCellInfoForPoint(x, y);
+ mLauncher.addAppWidgetFromDrop(((LauncherAppWidgetInfo)dragInfo).providerName, cellLayout.getTag());
break;
default:
- throw new IllegalStateException("Unknown item type: " + info.itemType);
+ throw new IllegalStateException("Unknown item type: "
+ + info.itemType);
}
- cellLayout.addView(view, insertAtFirst ? 0 : -1);
- view.setHapticFeedbackEnabled(false);
- view.setOnLongClickListener(mLongClickListener);
- if (view instanceof DropTarget) {
- mDragController.addDropTarget((DropTarget) view);
- }
-
- mTargetCell = estimateDropCell(x, y, 1, 1, view, cellLayout, mTargetCell);
- cellLayout.onDropChild(view, mTargetCell);
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
+ // If the view is null, it has already been added.
+ if (view == null) {
+ cellLayout.onDragComplete();
+ } else {
+ mTargetCell = estimateDropCell(x, y, 1, 1, view, cellLayout, mTargetCell);
+ addInScreen(view, indexOfChild(cellLayout), mTargetCell[0],
+ mTargetCell[1], info.spanX, info.spanY, insertAtFirst);
+ cellLayout.onDropChild(view);
+ CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
- LauncherModel.addOrMoveItemInDatabase(mLauncher, info,
- LauncherSettings.Favorites.CONTAINER_DESKTOP, mCurrentScreen, lp.cellX, lp.cellY);
+ LauncherModel.addOrMoveItemInDatabase(mLauncher, info,
+ LauncherSettings.Favorites.CONTAINER_DESKTOP, mCurrentScreen,
+ lp.cellX, lp.cellY);
+ }
}
-
+
/**
* Return the current {@link CellLayout}, correctly picking the destination
* screen while a scroll is in progress.
@@ -1156,39 +1370,44 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
mVacantCache = layout.findAllVacantCells(null, ignoreView);
}
- return mVacantCache.findCellForSpan(mTempEstimate, spanX, spanY, false);
+ if (mVacantCache.findCellForSpan(mTempEstimate, spanX, spanY, false)) {
+ return true;
+ } else {
+ Toast.makeText(getContext(), getContext().getString(R.string.out_of_space), Toast.LENGTH_SHORT).show();
+ return false;
+ }
}
-
+
/**
* {@inheritDoc}
*/
public Rect estimateDropLocation(DragSource source, int x, int y,
int xOffset, int yOffset, DragView dragView, Object dragInfo, Rect recycle) {
final CellLayout layout = getCurrentDropLayout();
-
+
final CellLayout.CellInfo cellInfo = mDragInfo;
final int spanX = cellInfo == null ? 1 : cellInfo.spanX;
final int spanY = cellInfo == null ? 1 : cellInfo.spanY;
final View ignoreView = cellInfo == null ? null : cellInfo.cell;
-
+
final Rect location = recycle != null ? recycle : new Rect();
-
+
// Find drop cell and convert into rectangle
- int[] dropCell = estimateDropCell(x - xOffset, y - yOffset,
- spanX, spanY, ignoreView, layout, mTempCell);
-
+ int[] dropCell = estimateDropCell(x - xOffset, y - yOffset, spanX,
+ spanY, ignoreView, layout, mTempCell);
+
if (dropCell == null) {
return null;
}
-
+
layout.cellToPoint(dropCell[0], dropCell[1], mTempEstimate);
location.left = mTempEstimate[0];
location.top = mTempEstimate[1];
-
+
layout.cellToPoint(dropCell[0] + spanX, dropCell[1] + spanY, mTempEstimate);
location.right = mTempEstimate[0];
location.bottom = mTempEstimate[1];
-
+
return location;
}
@@ -1197,16 +1416,27 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
*/
private int[] estimateDropCell(int pixelX, int pixelY,
int spanX, int spanY, View ignoreView, CellLayout layout, int[] recycle) {
+
+ final int[] cellXY = mTempCell;
+ layout.estimateDropCell(pixelX, pixelY, spanX, spanY, cellXY);
+ layout.cellToPoint(cellXY[0], cellXY[1], mTempEstimate);
+
// Create vacant cell cache if none exists
if (mVacantCache == null) {
mVacantCache = layout.findAllVacantCells(null, ignoreView);
}
// Find the best target drop location
- return layout.findNearestVacantArea(pixelX, pixelY,
- spanX, spanY, mVacantCache, recycle);
+ return layout.findNearestVacantArea(mTempEstimate[0], mTempEstimate[1], spanX, spanY, mVacantCache, recycle);
}
-
+
+ /**
+ * Estimate the size that a child with the given dimensions will take in the current screen.
+ */
+ void estimateChildSize(int minWidth, int minHeight, int[] result) {
+ ((CellLayout)getChildAt(mCurrentScreen)).estimateChildSize(minWidth, minHeight, result);
+ }
+
void setLauncher(Launcher launcher) {
mLauncher = launcher;
}
@@ -1218,14 +1448,14 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
public void onDropCompleted(View target, boolean success) {
clearVacantCache();
- if (success){
+ if (success) {
if (target != this && mDragInfo != null) {
final CellLayout cellLayout = (CellLayout) getChildAt(mDragInfo.screen);
cellLayout.removeView(mDragInfo.cell);
if (mDragInfo.cell instanceof DropTarget) {
mDragController.removeDropTarget((DropTarget)mDragInfo.cell);
}
- //final Object tag = mDragInfo.cell.getTag();
+ // final Object tag = mDragInfo.cell.getTag();
}
} else {
if (mDragInfo != null) {
@@ -1240,18 +1470,22 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
public void scrollLeft() {
clearVacantCache();
if (mScroller.isFinished()) {
- if (mCurrentScreen > 0) snapToScreen(mCurrentScreen - 1);
+ if (mCurrentScreen > 0)
+ snapToScreen(mCurrentScreen - 1);
} else {
- if (mNextScreen > 0) snapToScreen(mNextScreen - 1);
+ if (mNextScreen > 0)
+ snapToScreen(mNextScreen - 1);
}
}
public void scrollRight() {
clearVacantCache();
if (mScroller.isFinished()) {
- if (mCurrentScreen < getChildCount() -1) snapToScreen(mCurrentScreen + 1);
+ if (mCurrentScreen < getChildCount() - 1)
+ snapToScreen(mCurrentScreen + 1);
} else {
- if (mNextScreen < getChildCount() -1) snapToScreen(mNextScreen + 1);
+ if (mNextScreen < getChildCount() - 1)
+ snapToScreen(mNextScreen + 1);
}
}
@@ -1279,7 +1513,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
if (lp.cellHSpan == 4 && lp.cellVSpan == 4 && child instanceof Folder) {
Folder f = (Folder) child;
- if (f.getInfo() == tag) {
+ if (f.getInfo() == tag && f.getInfo().opened) {
return f;
}
}
@@ -1309,7 +1543,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
public boolean allowLongPress() {
return mAllowLongPress;
}
-
+
/**
* Set true to allow long-press events to be triggered, usually checked by
* {@link Launcher} to accept or block dpad-initiated long-presses.
@@ -1337,17 +1571,17 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
public void run() {
final ArrayList<View> childrenToRemove = new ArrayList<View>();
childrenToRemove.clear();
-
+
int childCount = layout.getChildCount();
for (int j = 0; j < childCount; j++) {
final View view = layout.getChildAt(j);
Object tag = view.getTag();
-
+
if (tag instanceof ShortcutInfo) {
final ShortcutInfo info = (ShortcutInfo) tag;
final Intent intent = info.intent;
final ComponentName name = intent.getComponent();
-
+
if (Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) {
for (String packageName: packageNames) {
if (packageName.equals(name.getPackageName())) {
@@ -1363,12 +1597,12 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
final ArrayList<ShortcutInfo> toRemove = new ArrayList<ShortcutInfo>(1);
final int contentsCount = contents.size();
boolean removedFromFolder = false;
-
+
for (int k = 0; k < contentsCount; k++) {
final ShortcutInfo appInfo = contents.get(k);
final Intent intent = appInfo.intent;
final ComponentName name = intent.getComponent();
-
+
if (Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) {
for (String packageName: packageNames) {
if (packageName.equals(name.getPackageName())) {
@@ -1381,11 +1615,12 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
}
}
}
-
+
contents.removeAll(toRemove);
if (removedFromFolder) {
final Folder folder = getOpenFolder();
- if (folder != null) folder.notifyDataSetChanged();
+ if (folder != null)
+ folder.notifyDataSetChanged();
}
} else if (tag instanceof LiveFolderInfo) {
final LiveFolderInfo info = (LiveFolderInfo) tag;
@@ -1398,7 +1633,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
if (packageName.equals(providerInfo.packageName)) {
// TODO: This should probably be done on a worker thread
LauncherModel.deleteItemFromDatabase(mLauncher, info);
- childrenToRemove.add(view);
+ childrenToRemove.add(view);
}
}
}
@@ -1411,13 +1646,13 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
if (packageName.equals(provider.provider.getPackageName())) {
// TODO: This should probably be done on a worker thread
LauncherModel.deleteItemFromDatabase(mLauncher, info);
- childrenToRemove.add(view);
+ childrenToRemove.add(view);
}
}
}
}
}
-
+
childCount = childrenToRemove.size();
for (int j = 0; j < childCount; j++) {
View child = childrenToRemove.get(j);
@@ -1426,7 +1661,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
mDragController.removeDropTarget((DropTarget)child);
}
}
-
+
if (childCount > 0) {
layout.requestLayout();
layout.invalidate();
@@ -1456,7 +1691,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION &&
Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) {
final int appCount = apps.size();
- for (int k=0; k<appCount; k++) {
+ for (int k = 0; k < appCount; k++) {
ApplicationInfo app = apps.get(k);
if (app.componentName.equals(name)) {
info.setIcon(mIconCache.getIcon(info.intent));
diff --git a/src/com/android/launcher2/allapps.rs b/src/com/android/launcher2/allapps.rs
new file mode 100644
index 0000000..fad8907
--- /dev/null
+++ b/src/com/android/launcher2/allapps.rs
@@ -0,0 +1,390 @@
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.launcher2)
+
+#include "rs_graphics.rsh"
+
+#define PI 3.14159f
+
+// Constants from Java
+int COLUMNS_PER_PAGE_PORTRAIT;
+int ROWS_PER_PAGE_PORTRAIT;
+int COLUMNS_PER_PAGE_LANDSCAPE;
+int ROWS_PER_PAGE_LANDSCAPE;
+
+int gIconCount;
+int gSelectedIconIndex = -1;
+rs_allocation gSelectedIconTexture;
+rs_allocation gHomeButton;
+
+rs_program_fragment gPFTexNearest;
+rs_program_fragment gPFTexMip;
+rs_program_fragment gPFTexMipAlpha;
+rs_program_vertex gPVCurve;
+rs_program_store gPS;
+rs_mesh gSMCell;
+
+rs_allocation *gIconIDs;
+rs_allocation *gLabelIDs;
+
+typedef struct VpConsts {
+ float4 Position;
+ float4 ScaleOffset;
+ float2 BendPos;
+ float2 ImgSize;
+} VpConsts_t;
+VpConsts_t *vpConstants;
+
+
+#pragma rs export_var(COLUMNS_PER_PAGE_PORTRAIT, ROWS_PER_PAGE_PORTRAIT, COLUMNS_PER_PAGE_LANDSCAPE, ROWS_PER_PAGE_LANDSCAPE, gIconCount, gSelectedIconIndex, gSelectedIconTexture, gHomeButton, gTargetPos, gPFTexNearest, gPFTexMip, gPFTexMipAlpha, gPVCurve, gPS, gSMCell, gIconIDs, gLabelIDs, vpConstants)
+#pragma rs export_func(move, moveTo, setZoom, fling)
+
+
+// Attraction to center values from page edge to page center.
+static float g_AttractionTable[9] = {20.f, 20.f, 20.f, 10.f, -10.f, -20.f, -20.f, -20.f, -20.f};
+static float g_FrictionTable[9] = {10.f, 10.f, 11.f, 15.f, 15.f, 11.f, 10.f, 10.f, 10.f};
+static float g_PhysicsTableSize = 7;
+
+static float gZoomTarget;
+static float gTargetPos;
+static float g_PosPage = 0.f;
+static float g_PosVelocity = 0.f;
+static float g_LastPositionX = 0.f;
+static bool g_LastTouchDown = false;
+static float g_DT;
+static int64_t g_LastTime;
+static int g_PosMax;
+static float g_Zoom = 0.f;
+static float g_Animation = 1.f;
+static float g_OldPosPage;
+static float g_OldPosVelocity;
+static float g_OldZoom;
+static float g_MoveToTotalTime = 0.2f;
+static float g_MoveToTime = 0.f;
+static float g_MoveToOldPos = 0.f;
+
+static int g_Cols;
+static int g_Rows;
+
+// Drawing constants, should be parameters ======
+#define VIEW_ANGLE 1.28700222f
+
+
+static void updateReadback() {
+ if ((g_OldPosPage != g_PosPage) ||
+ (g_OldPosVelocity != g_PosVelocity) ||
+ (g_OldZoom != g_Zoom)) {
+
+ g_OldPosPage = g_PosPage;
+ g_OldPosVelocity = g_PosVelocity;
+ g_OldZoom = g_Zoom;
+
+ int i[3];
+ i[0] = g_PosPage * (1 << 16);
+ i[1] = g_PosVelocity * (1 << 16);
+ i[2] = g_OldZoom * (1 << 16);
+ rsSendToClient(&i[0], 1, 12, 1);
+ }
+}
+
+void init() {
+}
+
+void move(float newPos) {
+ if (g_LastTouchDown) {
+ float dx = -(newPos - g_LastPositionX);
+ g_PosVelocity = 0;
+ g_PosPage += dx * 5.2f;
+
+ float pmin = -0.49f;
+ float pmax = g_PosMax + 0.49f;
+ g_PosPage = clamp(g_PosPage, pmin, pmax);
+ }
+ g_LastTouchDown = true;
+ g_LastPositionX = newPos;
+ g_MoveToTime = 0;
+}
+
+void moveTo(float targetPos) {
+ gTargetPos = targetPos;
+ g_MoveToTime = g_MoveToTotalTime;
+ g_PosVelocity = 0;
+ g_MoveToOldPos = g_PosPage;
+}
+
+void setZoom(float z, /*bool*/ int animate) {
+ gZoomTarget = z;
+ if (gZoomTarget < 0.001f) {
+ gZoomTarget = 0;
+ }
+ if (!animate) {
+ g_Zoom = gZoomTarget;
+ }
+ updateReadback();
+}
+
+void fling(float newPos, float vel) {
+ move(newPos);
+
+ g_LastTouchDown = false;
+ g_PosVelocity = -vel * 4;
+ float av = fabs(g_PosVelocity);
+ float minVel = 3.5f;
+
+ minVel *= 1.f - (fabs(rsFrac(g_PosPage + 0.5f) - 0.5f) * 0.45f);
+
+ if (av < minVel && av > 0.2f) {
+ if (g_PosVelocity > 0) {
+ g_PosVelocity = minVel;
+ } else {
+ g_PosVelocity = -minVel;
+ }
+ }
+
+ if (g_PosPage <= 0) {
+ g_PosVelocity = max(0.f, g_PosVelocity);
+ }
+ if (g_PosPage > g_PosMax) {
+ g_PosVelocity = min(0.f, g_PosVelocity);
+ }
+}
+
+// Interpolates values in the range 0..1 to a curve that eases in
+// and out.
+static float getInterpolation(float input) {
+ return (cos((input + 1) * PI) * 0.5f) + 0.5f;
+}
+
+
+static void updatePos() {
+ if (g_LastTouchDown) {
+ return;
+ }
+
+ float tablePosNorm = rsFrac(g_PosPage + 0.5f);
+ float tablePosF = tablePosNorm * g_PhysicsTableSize;
+ int tablePosI = tablePosF;
+ float tablePosFrac = tablePosF - tablePosI;
+ float accel = mix(g_AttractionTable[tablePosI],
+ g_AttractionTable[tablePosI + 1],
+ tablePosFrac) * g_DT;
+ float friction = mix(g_FrictionTable[tablePosI],
+ g_FrictionTable[tablePosI + 1],
+ tablePosFrac) * g_DT;
+
+ if (g_MoveToTime) {
+ // New position is old posiition + (total distance) * (interpolated time)
+ g_PosPage = g_MoveToOldPos + (gTargetPos - g_MoveToOldPos) * getInterpolation((g_MoveToTotalTime - g_MoveToTime) / g_MoveToTotalTime);
+ g_MoveToTime -= g_DT;
+ if (g_MoveToTime <= 0) {
+ g_MoveToTime = 0;
+ g_PosPage = gTargetPos;
+ }
+ return;
+ }
+
+ // If our velocity is low OR acceleration is opposing it, apply it.
+ if (fabs(g_PosVelocity) < 4.0f || (g_PosVelocity * accel) < 0) {
+ g_PosVelocity += accel;
+ }
+ //RS_DEBUG(g_PosPage);
+ //RS_DEBUG(g_PosVelocity);
+ //RS_DEBUG(friction);
+ //RS_DEBUG(accel);
+
+ // Normal physics
+ if (g_PosVelocity > 0) {
+ g_PosVelocity -= friction;
+ g_PosVelocity = max(g_PosVelocity, 0.f);
+ } else {
+ g_PosVelocity += friction;
+ g_PosVelocity = min(g_PosVelocity, 0.f);
+ }
+
+ if ((friction > fabs(g_PosVelocity)) && (friction > fabs(accel))) {
+ // Special get back to center and overcome friction physics.
+ float t = tablePosNorm - 0.5f;
+ if (fabs(t) < (friction * g_DT)) {
+ // really close, just snap
+ g_PosPage = round(g_PosPage);
+ g_PosVelocity = 0;
+ } else {
+ if (t > 0) {
+ g_PosVelocity = -friction;
+ } else {
+ g_PosVelocity = friction;
+ }
+ }
+ }
+
+ // Check for out of boundry conditions.
+ if (g_PosPage < 0 && g_PosVelocity < 0) {
+ float damp = 1.0f + (g_PosPage * 4);
+ damp = clamp(damp, 0.f, 0.9f);
+ g_PosVelocity *= damp;
+ }
+ if (g_PosPage > g_PosMax && g_PosVelocity > 0) {
+ float damp = 1.0f - ((g_PosPage - g_PosMax) * 4);
+ damp = clamp(damp, 0.f, 0.9f);
+ g_PosVelocity *= damp;
+ }
+
+ g_PosPage += g_PosVelocity * g_DT;
+ g_PosPage = clamp(g_PosPage, -0.49f, g_PosMax + 0.49f);
+}
+
+static void
+draw_home_button()
+{
+ color(1.0f, 1.0f, 1.0f, 1.0f);
+ rsgBindTexture(gPFTexNearest, 0, gHomeButton);
+
+ float w = rsgGetWidth();
+ float h = rsgGetHeight();
+ float tw = rsAllocationGetDimX(gHomeButton);
+ float th = rsAllocationGetDimY(gHomeButton);
+
+ float x;
+ float y;
+ if (w > h) {
+ x = w - (tw * (1 - g_Animation)) + 20;
+ y = (h - th) * 0.5f;
+ } else {
+ x = (w - tw) / 2;
+ y = -g_Animation * th;
+ y -= 30; // move the house to the edge of the screen as it doesn't fill the texture.
+ }
+
+ rsgDrawSpriteScreenspace(x, y, 0, tw, th);
+}
+
+static void drawFrontGrid(float rowOffset, float p)
+{
+ float h = rsgGetHeight();
+ float w = rsgGetWidth();
+
+ int intRowOffset = rowOffset;
+ float rowFrac = rowOffset - intRowOffset;
+ float colWidth = 120.f;//w / 4;
+ float rowHeight = colWidth + 25.f;
+ float yoff = 0.5f * h + 1.5f * rowHeight;
+
+ int row, col;
+ int colCount = 4;
+ if (w > h) {
+ colCount = 6;
+ rowHeight -= 12.f;
+ yoff = 0.47f * h + 1.0f * rowHeight;
+ }
+
+ int iconNum = (intRowOffset - 5) * colCount;
+
+ rsgBindProgramVertex(gPVCurve);
+
+ vpConstants->Position.z = p;
+
+ color(1.0f, 1.0f, 1.0f, 1.0f);
+ for (row = -5; row < 15; row++) {
+ float y = yoff - ((-rowFrac + row) * rowHeight);
+
+ for (col=0; col < colCount; col++) {
+ if (iconNum >= gIconCount) {
+ return;
+ }
+
+ if (iconNum >= 0) {
+ float x = colWidth * col + (colWidth / 2);
+ vpConstants->Position.x = x + 0.2f;
+
+ if (gSelectedIconIndex == iconNum && !p && gSelectedIconTexture.p) {
+ rsgBindProgramFragment(gPFTexNearest);
+ rsgBindTexture(gPFTexNearest, 0, gSelectedIconTexture);
+ vpConstants->ImgSize.x = rsAllocationGetDimX(gSelectedIconTexture);
+ vpConstants->ImgSize.y = rsAllocationGetDimY(gSelectedIconTexture);
+ vpConstants->Position.y = y - (rsAllocationGetDimY(gSelectedIconTexture)
+ - rsAllocationGetDimY(gIconIDs[iconNum])) * 0.5f;
+ rsgDrawMesh(gSMCell);
+ }
+
+ rsgBindProgramFragment(gPFTexMip);
+ vpConstants->ImgSize.x = rsAllocationGetDimX(gIconIDs[iconNum]);
+ vpConstants->ImgSize.y = rsAllocationGetDimY(gIconIDs[iconNum]);
+ vpConstants->Position.y = y - 0.2f;
+ rsgBindTexture(gPFTexMip, 0, gIconIDs[iconNum]);
+ rsgDrawMesh(gSMCell);
+
+ rsgBindProgramFragment(gPFTexMipAlpha);
+ vpConstants->ImgSize.x = rsAllocationGetDimX(gLabelIDs[iconNum]);
+ vpConstants->ImgSize.y = rsAllocationGetDimY(gLabelIDs[iconNum]);
+ vpConstants->Position.y = y - 64.f - 0.2f;
+ rsgBindTexture(gPFTexMipAlpha, 0, gLabelIDs[iconNum]);
+ rsgDrawMesh(gSMCell);
+ }
+ iconNum++;
+ }
+ }
+}
+
+
+int root()
+{
+ // Compute dt in seconds.
+ int64_t newTime = rsUptimeMillis();
+ g_DT = (newTime - g_LastTime) * 0.001f;
+ g_LastTime = newTime;
+
+ // physics may break if DT is large.
+ g_DT = min(g_DT, 0.1f);
+
+ if (g_Zoom != gZoomTarget) {
+ float dz = g_DT * 1.7f;
+ if (gZoomTarget < 0.5f) {
+ dz = -dz;
+ }
+ if (fabs(g_Zoom - gZoomTarget) < fabs(dz)) {
+ g_Zoom = gZoomTarget;
+ } else {
+ g_Zoom += dz;
+ }
+ updateReadback();
+ }
+ g_Animation = pow(1.f - g_Zoom, 3.f);
+
+ // Set clear value to dim the background based on the zoom position.
+ if ((g_Zoom < 0.001f) && (gZoomTarget < 0.001f)) {
+ rsgClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ // When we're zoomed out and not tracking motion events, reset the pos to 0.
+ if (!g_LastTouchDown) {
+ g_PosPage = 0;
+ }
+ return 0;
+ } else {
+ rsgClearColor(0.0f, 0.0f, 0.0f, g_Zoom);
+ }
+
+ rsgBindProgramStore(gPS);
+
+ // icons & labels
+ if (rsgGetWidth() > rsgGetHeight()) {
+ g_Cols = COLUMNS_PER_PAGE_LANDSCAPE;
+ g_Rows = ROWS_PER_PAGE_LANDSCAPE;
+ } else {
+ g_Cols = COLUMNS_PER_PAGE_PORTRAIT;
+ g_Rows = ROWS_PER_PAGE_PORTRAIT;
+ }
+
+ g_PosMax = ((gIconCount + (g_Cols-1)) / g_Cols) - g_Rows;
+ if (g_PosMax < 0) g_PosMax = 0;
+
+ updatePos();
+ updateReadback();
+
+ // Draw the icons ========================================
+ drawFrontGrid(g_PosPage, g_Animation);
+
+ rsgBindProgramFragment(gPFTexNearest);
+ draw_home_button();
+ return (g_PosVelocity != 0) || rsFrac(g_PosPage) || g_Zoom != gZoomTarget || (g_MoveToTime != 0);
+}
+
+