diff --git a/.gitignore b/.gitignore
index f830c66eb2..fc1b944b25 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,5 @@
db_files
+*.iml
+gen/
+tests/stress/gen/
+WallpaperPicker/gen/
diff --git a/res/layout/dummy_widget.xml b/res/layout/dummy_widget.xml
new file mode 100644
index 0000000000..a0fa8fc3e4
--- /dev/null
+++ b/res/layout/dummy_widget.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index f12cb57ba9..54689ec250 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -28,6 +28,8 @@
80dp
20dp
+ 8dp
+
240dp
165dp
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index f57f4d0361..240250750f 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -8,6 +8,7 @@ import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Rect;
import android.view.Gravity;
import android.widget.FrameLayout;
@@ -78,13 +79,13 @@ public class AppWidgetResizeFrame extends FrameLayout {
mLauncher = (Launcher) context;
mCellLayout = cellLayout;
mWidgetView = widgetView;
- mResizeMode = widgetView.getAppWidgetInfo().resizeMode;
+ LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo)
+ widgetView.getAppWidgetInfo();
+ mResizeMode = info.resizeMode;
mDragLayer = dragLayer;
- final AppWidgetProviderInfo info = widgetView.getAppWidgetInfo();
- int[] result = Launcher.getMinSpanForWidget(mLauncher, info);
- mMinHSpan = result[0];
- mMinVSpan = result[1];
+ mMinHSpan = info.minSpanX;
+ mMinVSpan = info.minSpanY;
setBackgroundResource(R.drawable.widget_resize_frame_holo);
setPadding(0, 0, 0, 0);
@@ -114,8 +115,16 @@ public class AppWidgetResizeFrame extends FrameLayout {
Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
addView(mBottomHandle, lp);
- Rect p = AppWidgetHostView.getDefaultPaddingForWidget(context,
- widgetView.getAppWidgetInfo().provider, null);
+ Rect p = new Rect(0, 0, 0, 0);
+ if (!info.isCustomWidget) {
+ p = AppWidgetHostView.getDefaultPaddingForWidget(context,
+ widgetView.getAppWidgetInfo().provider, null);
+ } else {
+ Resources r = context.getResources();
+ int padding = r.getDimensionPixelSize(R.dimen.default_widget_padding);
+ p.set(padding, padding, padding, padding);
+ }
+
mWidgetPaddingLeft = p.left;
mWidgetPaddingTop = p.top;
mWidgetPaddingRight = p.right;
@@ -335,7 +344,6 @@ public class AppWidgetResizeFrame extends FrameLayout {
static void updateWidgetSizeRanges(AppWidgetHostView widgetView, Launcher launcher,
int spanX, int spanY) {
-
getWidgetSizeRanges(launcher, spanX, spanY, mTmpRect);
widgetView.updateAppWidgetSize(null, mTmpRect.left, mTmpRect.top,
mTmpRect.right, mTmpRect.bottom);
diff --git a/src/com/android/launcher3/AppsCustomizePagedView.java b/src/com/android/launcher3/AppsCustomizePagedView.java
index c8187f0684..9e7e523e03 100644
--- a/src/com/android/launcher3/AppsCustomizePagedView.java
+++ b/src/com/android/launcher3/AppsCustomizePagedView.java
@@ -383,12 +383,13 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
// Get the list of widgets and shortcuts
mWidgets.clear();
for (Object o : widgetsAndShortcuts) {
- if (o instanceof AppWidgetProviderInfo) {
- AppWidgetProviderInfo widget = (AppWidgetProviderInfo) o;
- if (!app.shouldShowAppOrWidgetProvider(widget.provider)) {
+ if (o instanceof LauncherAppWidgetProviderInfo) {
+ LauncherAppWidgetProviderInfo widget = (LauncherAppWidgetProviderInfo) o;
+ if (!app.shouldShowAppOrWidgetProvider(widget.provider) && !widget.isCustomWidget) {
continue;
}
- if (widget.minWidth > 0 && widget.minHeight > 0) {
+
+ if (widget.minSpanX > 0 && widget.minSpanY > 0) {
// Ensure that all widgets we show can be added on a workspace of this size
int[] spanXY = Launcher.getSpanForWidget(mLauncher, widget);
int[] minSpanXY = Launcher.getMinSpanForWidget(mLauncher, widget);
@@ -410,6 +411,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
mWidgets.add(o);
}
}
+
updatePageCountsAndInvalidateData();
}
@@ -503,8 +505,9 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
}
private void preloadWidget(final PendingAddWidgetInfo info) {
- final AppWidgetProviderInfo pInfo = info.info;
- final Bundle options = getDefaultOptionsForWidget(mLauncher, info);
+ final LauncherAppWidgetProviderInfo pInfo = info.info;
+ final Bundle options = pInfo.isCustomWidget ? null :
+ getDefaultOptionsForWidget(mLauncher, info);
if (pInfo.configure != null) {
info.bindOptions = options;
@@ -515,11 +518,17 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
mBindWidgetRunnable = new Runnable() {
@Override
public void run() {
+ if (pInfo.isCustomWidget) {
+ mWidgetCleanupState = WIDGET_BOUND;
+ return;
+ }
+
mWidgetLoadingId = mLauncher.getAppWidgetHost().allocateAppWidgetId();
if(AppWidgetManagerCompat.getInstance(mLauncher).bindAppWidgetIdIfAllowed(
mWidgetLoadingId, pInfo, options)) {
mWidgetCleanupState = WIDGET_BOUND;
}
+
}
};
post(mBindWidgetRunnable);
@@ -530,8 +539,8 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
if (mWidgetCleanupState != WIDGET_BOUND) {
return;
}
- AppWidgetHostView hostView = mLauncher.
- getAppWidgetHost().createView(getContext(), mWidgetLoadingId, pInfo);
+ AppWidgetHostView hostView = mLauncher.getAppWidgetHost().createView(
+ getContext(), mWidgetLoadingId, pInfo);
info.boundWidget = hostView;
mWidgetCleanupState = WIDGET_INFLATED;
hostView.setVisibility(INVISIBLE);
@@ -575,7 +584,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
removeCallbacks(mInflateWidgetRunnable);
} else if (mWidgetCleanupState == WIDGET_BOUND) {
// Delete the widget id which was allocated
- if (mWidgetLoadingId != -1) {
+ if (mWidgetLoadingId != -1 && !info.isCustomWidget()) {
mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId);
}
@@ -583,7 +592,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
removeCallbacks(mInflateWidgetRunnable);
} else if (mWidgetCleanupState == WIDGET_INFLATED) {
// Delete the widget id which was allocated
- if (mWidgetLoadingId != -1) {
+ if (mWidgetLoadingId != -1 && !info.isCustomWidget()) {
mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId);
}
@@ -645,7 +654,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
maxHeight = Math.min((int) (previewDrawable.getIntrinsicHeight() * minScale), size[1]);
int[] previewSizeBeforeScale = new int[1];
-
preview = getWidgetPreviewLoader().generateWidgetPreview(createWidgetInfo.info,
spanX, spanY, maxWidth, maxHeight, null, previewSizeBeforeScale);
@@ -1125,20 +1133,13 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
PendingAddItemInfo createItemInfo = null;
PagedViewWidget widget = (PagedViewWidget) mLayoutInflater.inflate(
R.layout.apps_customize_widget, layout, false);
- if (rawInfo instanceof AppWidgetProviderInfo) {
+
+ if (rawInfo instanceof LauncherAppWidgetProviderInfo) {
// Fill in the widget information
- AppWidgetProviderInfo info = (AppWidgetProviderInfo) rawInfo;
- createItemInfo = new PendingAddWidgetInfo(info, null, null);
+ LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo) rawInfo;
+ createItemInfo = new PendingAddWidgetInfo(info, null);
- // Determine the widget spans and min resize spans.
- int[] spanXY = Launcher.getSpanForWidget(mLauncher, info);
- createItemInfo.spanX = spanXY[0];
- createItemInfo.spanY = spanXY[1];
- int[] minSpanXY = Launcher.getMinSpanForWidget(mLauncher, info);
- createItemInfo.minSpanX = minSpanXY[0];
- createItemInfo.minSpanY = minSpanXY[1];
-
- widget.applyFromAppWidgetProviderInfo(info, -1, spanXY, getWidgetPreviewLoader());
+ widget.applyFromAppWidgetProviderInfo(info, -1, getWidgetPreviewLoader());
widget.setTag(createItemInfo);
widget.setShortPressListener(this);
} else if (rawInfo instanceof ResolveInfo) {
@@ -1151,6 +1152,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
widget.applyFromResolveInfo(mPackageManager, info, getWidgetPreviewLoader());
widget.setTag(createItemInfo);
}
+
widget.setOnClickListener(this);
widget.setOnLongClickListener(this);
widget.setOnTouchListener(this);
@@ -1421,6 +1423,11 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
updatePageCountsAndInvalidateData();
}
}
+
+ public ArrayList getApps() {
+ return mApps;
+ }
+
private void addAppsWithoutInvalidate(ArrayList list) {
// We add it in place, in alphabetical order
int count = list.size();
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 0ff1ef4adf..7424d61c10 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -592,7 +592,7 @@ public class CellLayout extends ViewGroup {
}
public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params,
- boolean markCells) {
+ boolean markCells, boolean inLayout) {
final LayoutParams lp = params;
// Hotseat icons - remove text
@@ -613,8 +613,11 @@ public class CellLayout extends ViewGroup {
if (lp.cellVSpan < 0) lp.cellVSpan = mCountY;
child.setId(childId);
-
- mShortcutsAndWidgets.addView(child, index, lp);
+ if (inLayout) {
+ mShortcutsAndWidgets.addView(child, index, lp, true);
+ } else {
+ mShortcutsAndWidgets.addView(child, index, lp, false);
+ }
if (markCells) markCellsAsOccupiedForView(child);
@@ -623,6 +626,11 @@ public class CellLayout extends ViewGroup {
return false;
}
+ public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params,
+ boolean markCells) {
+ return addViewToCellLayout(child, index, childId, params, markCells, false);
+ }
+
@Override
public void removeAllViews() {
clearOccupiedCells();
diff --git a/src/com/android/launcher3/CustomAppWidget.java b/src/com/android/launcher3/CustomAppWidget.java
new file mode 100644
index 0000000000..1b4ed79c0b
--- /dev/null
+++ b/src/com/android/launcher3/CustomAppWidget.java
@@ -0,0 +1,14 @@
+package com.android.launcher3;
+
+public interface CustomAppWidget {
+ public String getLabel();
+ public int getPreviewImage();
+ public int getIcon();
+ public int getWidgetLayout();
+
+ public int getSpanX();
+ public int getSpanY();
+ public int getMinSpanX();
+ public int getMinSpanY();
+ public int getResizeMode();
+}
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index ea058ea71a..5a5c0027ed 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -105,6 +105,7 @@ public class DeleteDropTarget extends ButtonDropTarget {
switch (addInfo.itemType) {
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
+ case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:
return true;
}
}
@@ -146,6 +147,7 @@ public class DeleteDropTarget extends ButtonDropTarget {
if (info instanceof ItemInfo) {
ItemInfo item = (ItemInfo) info;
if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET ||
+ item.itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET ||
item.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
return true;
}
@@ -341,7 +343,9 @@ public class DeleteDropTarget extends ButtonDropTarget {
final LauncherAppWidgetInfo launcherAppWidgetInfo = (LauncherAppWidgetInfo) item;
final LauncherAppWidgetHost appWidgetHost = mLauncher.getAppWidgetHost();
- if ((appWidgetHost != null) && launcherAppWidgetInfo.isWidgetIdValid()) {
+
+ if (appWidgetHost != null && !launcherAppWidgetInfo.isCustomWidget()
+ && launcherAppWidgetInfo.isWidgetIdValid()) {
// Deleting an app widget ID is a void call but writes to disk before returning
// to the caller...
new AsyncTask() {
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index d6aadcee1e..34e1f3c5f7 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -67,8 +67,8 @@ public class DeviceProfile {
String name;
float minWidthDps;
float minHeightDps;
- float numRows;
- float numColumns;
+ public float numRows;
+ public float numColumns;
float numHotseatIcons;
float iconSize;
private float iconTextSize;
@@ -84,13 +84,13 @@ public class DeviceProfile {
boolean transposeLayoutWithOrientation;
int desiredWorkspaceLeftRightMarginPx;
- int edgeMarginPx;
+ public int edgeMarginPx;
Rect defaultWidgetPadding;
int widthPx;
int heightPx;
- int availableWidthPx;
- int availableHeightPx;
+ public int availableWidthPx;
+ public int availableHeightPx;
int defaultPageSpacingPx;
int overviewModeMinIconZoneHeightPx;
@@ -100,11 +100,12 @@ public class DeviceProfile {
float overviewModeIconZoneRatio;
float overviewModeScaleFactor;
+ public int cellWidthPx;
+ public int cellHeightPx;
+
int iconSizePx;
int iconTextSizePx;
int iconDrawablePaddingPx;
- int cellWidthPx;
- int cellHeightPx;
int allAppsIconSizePx;
int allAppsIconTextSizePx;
int allAppsCellWidthPx;
@@ -578,6 +579,16 @@ public class DeviceProfile {
}
}
+ public int getWorkspaceGridHeight() {
+ Rect p = getWorkspacePadding();
+ return availableHeightPx - p.top - p.bottom;
+ }
+
+ public int getWorkspaceGridWidth() {
+ Rect p = getWorkspacePadding();
+ return availableWidthPx - p.left - p.right;
+ }
+
/** Returns the workspace padding in the specified orientation */
Rect getWorkspacePadding() {
return getWorkspacePadding(isLandscape ? CellLayout.LANDSCAPE : CellLayout.PORTRAIT);
diff --git a/src/com/android/launcher3/DummyWidget.java b/src/com/android/launcher3/DummyWidget.java
new file mode 100644
index 0000000000..59cd805012
--- /dev/null
+++ b/src/com/android/launcher3/DummyWidget.java
@@ -0,0 +1,50 @@
+package com.android.launcher3;
+
+import android.appwidget.AppWidgetProviderInfo;
+
+public class DummyWidget implements CustomAppWidget {
+ @Override
+ public String getLabel() {
+ return "Dumb Launcher Widget";
+ }
+
+ @Override
+ public int getPreviewImage() {
+ return 0;
+ }
+
+ @Override
+ public int getIcon() {
+ return 0;
+ }
+
+ @Override
+ public int getWidgetLayout() {
+ return R.layout.dummy_widget;
+ }
+
+ @Override
+ public int getSpanX() {
+ return 2;
+ }
+
+ @Override
+ public int getSpanY() {
+ return 2;
+ }
+
+ @Override
+ public int getMinSpanX() {
+ return 1;
+ }
+
+ @Override
+ public int getMinSpanY() {
+ return 1;
+ }
+
+ @Override
+ public int getResizeMode() {
+ return AppWidgetProviderInfo.RESIZE_BOTH;
+ }
+}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index ac46fd33d7..0ceb862a78 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -260,7 +260,7 @@ public class Launcher extends Activity
private LauncherAppWidgetHost mAppWidgetHost;
private ItemInfo mPendingAddInfo = new ItemInfo();
- private AppWidgetProviderInfo mPendingAddWidgetInfo;
+ private LauncherAppWidgetProviderInfo mPendingAddWidgetInfo;
private int mPendingAddWidgetId = -1;
private int[] mTmpAddItemCellCoordinates = new int[2];
@@ -351,6 +351,16 @@ public class Launcher extends Activity
private BubbleTextView mWaitingForResume;
+ protected static HashMap sCustomAppWidgets =
+ new HashMap();
+
+ private static final boolean ENABLE_CUSTOM_WIDGET_TEST = false;
+ static {
+ if (ENABLE_CUSTOM_WIDGET_TEST) {
+ sCustomAppWidgets.put(DummyWidget.class.getName(), new DummyWidget());
+ }
+ }
+
private Runnable mBuildLayersRunnable = new Runnable() {
public void run() {
if (mWorkspace != null) {
@@ -760,7 +770,7 @@ public class Launcher extends Activity
mWorkspace.removeExtraEmptyScreenDelayed(true, exitSpringLoaded,
ON_ACTIVITY_RESULT_ANIMATION_DELAY, false);
} else if (resultCode == RESULT_OK) {
- addAppWidgetImpl(appWidgetId, mPendingAddInfo, null,
+ addAppWidgetImpl(appWidgetId, (PendingAddWidgetInfo) mPendingAddInfo, null,
mPendingAddWidgetInfo, ON_ACTIVITY_RESULT_ANIMATION_DELAY);
}
return;
@@ -1487,7 +1497,7 @@ public class Launcher extends Activity
*
* @return A View inflated from layoutResId.
*/
- View createShortcut(int layoutResId, ViewGroup parent, ShortcutInfo info) {
+ public View createShortcut(int layoutResId, ViewGroup parent, ShortcutInfo info) {
BubbleTextView favorite = (BubbleTextView) mInflater.inflate(layoutResId, parent, false);
favorite.applyFromShortcutInfo(info, mIconCache, true);
favorite.setOnClickListener(this);
@@ -1586,86 +1596,45 @@ public class Launcher extends Activity
* @param appWidgetId The app widget id
* @param cellInfo The position on screen where to create the widget.
*/
- private void completeAddAppWidget(final int appWidgetId, long container, long screenId,
- AppWidgetHostView hostView, AppWidgetProviderInfo appWidgetInfo) {
+ private void completeAddAppWidget(int appWidgetId, long container, long screenId,
+ AppWidgetHostView hostView, LauncherAppWidgetProviderInfo appWidgetInfo) {
+
+ ItemInfo info = mPendingAddInfo;
if (appWidgetInfo == null) {
- appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
+ appWidgetInfo = LauncherAppWidgetProviderInfo.fromProviderInfo(this,
+ mAppWidgetManager.getAppWidgetInfo(appWidgetId));
}
- // Calculate the grid spans needed to fit this widget
- CellLayout layout = getCellLayout(container, screenId);
-
- int[] minSpanXY = getMinSpanForWidget(this, appWidgetInfo);
- int[] spanXY = getSpanForWidget(this, appWidgetInfo);
-
- // Try finding open space on Launcher screen
- // We have saved the position to which the widget was dragged-- this really only matters
- // if we are placing widgets on a "spring-loaded" screen
- int[] cellXY = mTmpAddItemCellCoordinates;
- int[] touchXY = mPendingAddInfo.dropPos;
- int[] finalSpan = new int[2];
- boolean foundCellSpan = false;
- if (mPendingAddInfo.cellX >= 0 && mPendingAddInfo.cellY >= 0) {
- cellXY[0] = mPendingAddInfo.cellX;
- cellXY[1] = mPendingAddInfo.cellY;
- spanXY[0] = mPendingAddInfo.spanX;
- spanXY[1] = mPendingAddInfo.spanY;
- foundCellSpan = true;
- } else if (touchXY != null) {
- // when dragging and dropping, just find the closest free spot
- int[] result = layout.findNearestVacantArea(
- touchXY[0], touchXY[1], minSpanXY[0], minSpanXY[1], spanXY[0],
- spanXY[1], cellXY, finalSpan);
- spanXY[0] = finalSpan[0];
- spanXY[1] = finalSpan[1];
- foundCellSpan = (result != null);
- } else {
- foundCellSpan = layout.findCellForSpan(cellXY, minSpanXY[0], minSpanXY[1]);
+ if (appWidgetInfo.isCustomWidget) {
+ appWidgetId = LauncherAppWidgetInfo.CUSTOM_WIDGET_ID;
}
- if (!foundCellSpan) {
- if (appWidgetId != -1) {
- // Deleting an app widget ID is a void call but writes to disk before returning
- // to the caller...
- new AsyncTask() {
- public Void doInBackground(Void ... args) {
- mAppWidgetHost.deleteAppWidgetId(appWidgetId);
- return null;
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
- }
- showOutOfSpaceMessage(isHotseatLayout(layout));
- return;
- }
-
- // Build Launcher-specific widget info and save to database
- LauncherAppWidgetInfo launcherInfo = new LauncherAppWidgetInfo(appWidgetId,
- appWidgetInfo.provider);
- launcherInfo.spanX = spanXY[0];
- launcherInfo.spanY = spanXY[1];
- launcherInfo.minSpanX = mPendingAddInfo.minSpanX;
- launcherInfo.minSpanY = mPendingAddInfo.minSpanY;
+ LauncherAppWidgetInfo launcherInfo;
+ launcherInfo = new LauncherAppWidgetInfo(appWidgetId, appWidgetInfo.provider);
+ launcherInfo.spanX = info.spanX;
+ launcherInfo.spanY = info.spanY;
+ launcherInfo.minSpanX = info.minSpanX;
+ launcherInfo.minSpanY = info.minSpanY;
launcherInfo.user = mAppWidgetManager.getUser(appWidgetInfo);
LauncherModel.addItemToDatabase(this, launcherInfo,
- container, screenId, cellXY[0], cellXY[1], false);
+ container, screenId, info.cellX, info.cellY, false);
if (!mRestoring) {
if (hostView == null) {
// Perform actual inflation because we're live
- launcherInfo.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
- launcherInfo.hostView.setAppWidget(appWidgetId, appWidgetInfo);
+ launcherInfo.hostView = mAppWidgetHost.createView(this, appWidgetId,
+ appWidgetInfo);
} else {
// The AppWidgetHostView has already been inflated and instantiated
launcherInfo.hostView = hostView;
}
-
launcherInfo.hostView.setTag(launcherInfo);
launcherInfo.hostView.setVisibility(View.VISIBLE);
launcherInfo.notifyWidgetSizeChanged(this);
- mWorkspace.addInScreen(launcherInfo.hostView, container, screenId, cellXY[0], cellXY[1],
- launcherInfo.spanX, launcherInfo.spanY, isWorkspaceLocked());
+ mWorkspace.addInScreen(launcherInfo.hostView, container, screenId, info.cellX,
+ info.cellY, launcherInfo.spanX, launcherInfo.spanY, isWorkspaceLocked());
addWidgetToAutoAdvanceIfNeeded(launcherInfo.hostView, appWidgetInfo);
}
@@ -1896,6 +1865,10 @@ public class Launcher extends Activity
Toast.makeText(this, getString(strId), Toast.LENGTH_SHORT).show();
}
+ public ArrayList getAllAppsList() {
+ return mAppsCustomizeContent.getApps();
+ }
+
public DragLayer getDragLayer() {
return mDragLayer;
}
@@ -2284,14 +2257,14 @@ public class Launcher extends Activity
mPendingAddInfo.dropPos = null;
}
- void addAppWidgetImpl(final int appWidgetId, final ItemInfo info,
- final AppWidgetHostView boundWidget, final AppWidgetProviderInfo appWidgetInfo) {
+ void addAppWidgetImpl(final int appWidgetId, final PendingAddWidgetInfo info, final
+ AppWidgetHostView boundWidget, final LauncherAppWidgetProviderInfo appWidgetInfo) {
addAppWidgetImpl(appWidgetId, info, boundWidget, appWidgetInfo, 0);
}
- void addAppWidgetImpl(final int appWidgetId, final ItemInfo info,
- final AppWidgetHostView boundWidget, final AppWidgetProviderInfo appWidgetInfo, int
- delay) {
+ void addAppWidgetImpl(final int appWidgetId, final PendingAddWidgetInfo info,
+ final AppWidgetHostView boundWidget, final LauncherAppWidgetProviderInfo appWidgetInfo,
+ int delay) {
if (appWidgetInfo.configure != null) {
mPendingAddWidgetInfo = appWidgetInfo;
mPendingAddWidgetId = appWidgetId;
@@ -2585,7 +2558,8 @@ public class Launcher extends Activity
int widgetId = info.appWidgetId;
AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(widgetId);
if (appWidgetInfo != null) {
- mPendingAddWidgetInfo = appWidgetInfo;
+ mPendingAddWidgetInfo = LauncherAppWidgetProviderInfo.fromProviderInfo(
+ this, appWidgetInfo);
mPendingAddInfo.copyFrom(info);
mPendingAddWidgetId = widgetId;
@@ -4373,12 +4347,12 @@ public class Launcher extends Activity
}
final Workspace workspace = mWorkspace;
- AppWidgetProviderInfo appWidgetInfo;
+ LauncherAppWidgetProviderInfo appWidgetInfo =
+ LauncherModel.getProviderInfo(this, item.providerName);
+
if (!mIsSafeModeEnabled
&& ((item.restoreStatus & LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) == 0)
&& ((item.restoreStatus & LauncherAppWidgetInfo.FLAG_ID_NOT_VALID) != 0)) {
-
- appWidgetInfo = mModel.findAppWidgetProviderInfoWithComponent(this, item.providerName);
if (appWidgetInfo == null) {
if (DEBUG_WIDGETS) {
Log.d(TAG, "Removing restored widget: id=" + item.appWidgetId
@@ -4391,7 +4365,7 @@ public class Launcher extends Activity
// Note: This assumes that the id remap broadcast is received before this step.
// If that is not the case, the id remap will be ignored and user may see the
// click to setup view.
- PendingAddWidgetInfo pendingInfo = new PendingAddWidgetInfo(appWidgetInfo, null, null);
+ PendingAddWidgetInfo pendingInfo = new PendingAddWidgetInfo(appWidgetInfo, null);
pendingInfo.spanX = item.spanX;
pendingInfo.spanY = item.spanY;
pendingInfo.minSpanX = item.minSpanX;
@@ -4428,9 +4402,9 @@ public class Launcher extends Activity
if (!mIsSafeModeEnabled && item.restoreStatus == LauncherAppWidgetInfo.RESTORE_COMPLETED) {
final int appWidgetId = item.appWidgetId;
- appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
if (DEBUG_WIDGETS) {
- Log.d(TAG, "bindAppWidget: id=" + item.appWidgetId + " belongs to component " + appWidgetInfo.provider);
+ Log.d(TAG, "bindAppWidget: id=" + item.appWidgetId + " belongs to component "
+ + appWidgetInfo.provider);
}
item.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
@@ -4449,7 +4423,9 @@ public class Launcher extends Activity
workspace.addInScreen(item.hostView, item.container, item.screenId, item.cellX,
item.cellY, item.spanX, item.spanY, false);
- addWidgetToAutoAdvanceIfNeeded(item.hostView, appWidgetInfo);
+ if (!item.isCustomWidget()) {
+ addWidgetToAutoAdvanceIfNeeded(item.hostView, appWidgetInfo);
+ }
workspace.requestLayout();
@@ -5125,6 +5101,14 @@ public class Launcher extends Activity
}
}
+ public static CustomAppWidget getCustomAppWidget(String name) {
+ return sCustomAppWidgets.get(name);
+ }
+
+ public static HashMap getCustomAppWidgets() {
+ return sCustomAppWidgets;
+ }
+
public void dumpLogsToLocalData() {
if (DEBUG_DUMP_LOG) {
new AsyncTask() {
diff --git a/src/com/android/launcher3/LauncherAppWidgetHost.java b/src/com/android/launcher3/LauncherAppWidgetHost.java
index a309f268c8..840508a1d7 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHost.java
@@ -21,9 +21,11 @@ import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
import android.os.TransactionTooLargeException;
+import android.view.LayoutInflater;
import java.util.ArrayList;
+
/**
* Specific {@link AppWidgetHost} that creates our {@link LauncherAppWidgetHostView}
* which correctly captures all long-press events. This ensures that users can
@@ -85,4 +87,29 @@ public class LauncherAppWidgetHost extends AppWidgetHost {
callback.run();
}
}
+
+ public AppWidgetHostView createView(Context context, int appWidgetId,
+ LauncherAppWidgetProviderInfo appWidget) {
+ if (appWidget.isCustomWidget) {
+ LauncherAppWidgetHostView lahv = new LauncherAppWidgetHostView(context);
+ LayoutInflater inflater = (LayoutInflater)
+ context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ inflater.inflate(appWidget.initialLayout, lahv);
+ lahv.setAppWidget(0, appWidget);
+ lahv.updateLastInflationOrientation();
+ return lahv;
+ } else {
+ return super.createView(context, appWidgetId, appWidget);
+ }
+ }
+
+ /**
+ * Called when the AppWidget provider for a AppWidget has been upgraded to a new apk.
+ */
+ @Override
+ protected void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidget) {
+ LauncherAppWidgetProviderInfo info = LauncherAppWidgetProviderInfo.fromProviderInfo(
+ mLauncher, appWidget);
+ super.onProviderChanged(appWidgetId, info);
+ }
}
diff --git a/src/com/android/launcher3/LauncherAppWidgetHostView.java b/src/com/android/launcher3/LauncherAppWidgetHostView.java
index e39727b175..ebe55ab783 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHostView.java
@@ -17,6 +17,7 @@
package com.android.launcher3;
import android.appwidget.AppWidgetHostView;
+import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -54,10 +55,14 @@ public class LauncherAppWidgetHostView extends AppWidgetHostView implements Touc
return mInflater.inflate(R.layout.appwidget_error, this, false);
}
+ public void updateLastInflationOrientation() {
+ mPreviousOrientation = mContext.getResources().getConfiguration().orientation;
+ }
+
@Override
public void updateAppWidget(RemoteViews remoteViews) {
// Store the orientation in which the widget was inflated
- mPreviousOrientation = mContext.getResources().getConfiguration().orientation;
+ updateLastInflationOrientation();
super.updateAppWidget(remoteViews);
}
@@ -136,6 +141,16 @@ public class LauncherAppWidgetHostView extends AppWidgetHostView implements Touc
mLongPressHelper.cancelLongPress();
}
+ @Override
+ public AppWidgetProviderInfo getAppWidgetInfo() {
+ AppWidgetProviderInfo info = super.getAppWidgetInfo();
+ if (!(info instanceof LauncherAppWidgetProviderInfo)) {
+ throw new IllegalStateException("Launcher widget must have"
+ + "LauncherAppWidgetProviderInfo");
+ }
+ return info;
+ }
+
@Override
public void onTouchComplete() {
if (!mLongPressHelper.hasPerformedLongPress()) {
diff --git a/src/com/android/launcher3/LauncherAppWidgetInfo.java b/src/com/android/launcher3/LauncherAppWidgetInfo.java
index 5c6535a243..aad18b578e 100644
--- a/src/com/android/launcher3/LauncherAppWidgetInfo.java
+++ b/src/com/android/launcher3/LauncherAppWidgetInfo.java
@@ -55,6 +55,11 @@ public class LauncherAppWidgetInfo extends ItemInfo {
*/
static final int NO_ID = -1;
+ /**
+ * Indicates that this is a locally defined widget and hence has no system allocated id.
+ */
+ static final int CUSTOM_WIDGET_ID = -100;
+
/**
* Identifier for this widget when talking with
* {@link android.appwidget.AppWidgetManager} for updates.
@@ -86,7 +91,12 @@ public class LauncherAppWidgetInfo extends ItemInfo {
AppWidgetHostView hostView = null;
LauncherAppWidgetInfo(int appWidgetId, ComponentName providerName) {
- itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
+ if (appWidgetId == CUSTOM_WIDGET_ID) {
+ itemType = LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
+ } else {
+ itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
+ }
+
this.appWidgetId = appWidgetId;
this.providerName = providerName;
@@ -99,6 +109,10 @@ public class LauncherAppWidgetInfo extends ItemInfo {
restoreStatus = RESTORE_COMPLETED;
}
+ public boolean isCustomWidget() {
+ return appWidgetId == CUSTOM_WIDGET_ID;
+ }
+
@Override
void onAddToDatabase(Context context, ContentValues values) {
super.onAddToDatabase(context, values);
diff --git a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
new file mode 100644
index 0000000000..e7f49b2ce4
--- /dev/null
+++ b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
@@ -0,0 +1,89 @@
+package com.android.launcher3;
+
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.os.Parcel;
+
+import java.lang.reflect.Field;
+
+/**
+ * This class is a thin wrapper around the framework AppWidgetProviderInfo class. This class affords
+ * a common object for describing both framework provided AppWidgets as well as custom widgets
+ * (who's implementation is owned by the launcher). This object represents a widget type / class,
+ * as opposed to a widget instance, and so should not be confused with {@link LauncherAppWidgetInfo}
+ */
+public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo {
+
+ public boolean isCustomWidget = false;
+ int spanX = -1;
+ int spanY = -1;
+ int minSpanX = -1;
+ int minSpanY = -1;
+
+ public static LauncherAppWidgetProviderInfo fromProviderInfo(Context context,
+ AppWidgetProviderInfo info) {
+
+ // In lieu of a public super copy constructor, we first write the AppWidgetProviderInfo
+ // into a parcel, and then construct a new LauncherAppWidgetProvider info from the
+ // associated super parcel constructor. This allows us to copy non-public members without
+ // using reflection.
+ Parcel p = Parcel.obtain();
+ info.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ LauncherAppWidgetProviderInfo lawpi = new LauncherAppWidgetProviderInfo(p);
+
+ int[] minResizeSpan = Launcher.getMinSpanForWidget(context, lawpi);
+ int[] span = Launcher.getSpanForWidget(context, lawpi);
+
+ lawpi.spanX = span[0];
+ lawpi.spanY = span[1];
+ lawpi.minSpanX = minResizeSpan[0];
+ lawpi.minSpanY = minResizeSpan[1];
+
+ return lawpi;
+ }
+
+ public LauncherAppWidgetProviderInfo(Parcel in) {
+ super(in);
+ }
+
+ public LauncherAppWidgetProviderInfo(Context context, CustomAppWidget widget) {
+ isCustomWidget = true;
+
+ provider = new ComponentName(context, widget.getClass().getName());
+ icon = widget.getIcon();
+ label = widget.getLabel();
+ previewImage = widget.getPreviewImage();
+ initialLayout = widget.getWidgetLayout();
+ resizeMode = widget.getResizeMode();
+
+ spanX = widget.getSpanX();
+ spanY = widget.getSpanY();
+ minSpanX = widget.getMinSpanX();
+ minSpanY = widget.getMinSpanY();
+ }
+
+ public String getLabel(PackageManager packageManager) {
+ if (isCustomWidget) {
+ return label.toString().trim();
+ }
+ return super.loadLabel(packageManager);
+ }
+
+ public Drawable getIcon(Context context, IconCache cache) {
+ if (isCustomWidget) {
+ return cache.getFullResIcon(provider.getPackageName(), icon);
+ }
+ return super.loadIcon(context, cache.getFullResIconDpi());
+ }
+
+ public String toString() {
+ if (isCustomWidget) {
+ return "LauncherAppWidgetProviderInfo(" + provider + ")";
+ }
+ return super.toString();
+ }
+ }
diff --git a/src/com/android/launcher3/LauncherBackupHelper.java b/src/com/android/launcher3/LauncherBackupHelper.java
index 4374347488..895a569d29 100644
--- a/src/com/android/launcher3/LauncherBackupHelper.java
+++ b/src/com/android/launcher3/LauncherBackupHelper.java
@@ -899,7 +899,8 @@ public class LauncherBackupHelper implements BackupHelper {
/** Serialize a widget for persistence, including a checksum wrapper. */
private Widget packWidget(int dpi, WidgetPreviewLoader previewLoader, IconCache iconCache,
ComponentName provider) {
- final AppWidgetProviderInfo info = findAppWidgetProviderInfo(provider);
+ final LauncherAppWidgetProviderInfo info =
+ LauncherModel.getProviderInfo(mContext, provider);
Widget widget = new Widget();
widget.provider = provider.flattenToShortString();
widget.label = info.label;
@@ -1067,19 +1068,6 @@ public class LauncherBackupHelper implements BackupHelper {
return wrapper.payload;
}
- private AppWidgetProviderInfo findAppWidgetProviderInfo(ComponentName component) {
- if (mWidgetMap == null) {
- List widgets =
- AppWidgetManager.getInstance(mContext).getInstalledProviders();
- mWidgetMap = new HashMap(widgets.size());
- for (AppWidgetProviderInfo info : widgets) {
- mWidgetMap.put(info.provider, info);
- }
- }
- return mWidgetMap.get(component);
- }
-
-
private boolean initializeIconCache() {
if (mIconCache != null) {
return true;
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 954887dc31..3c1cf485d2 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -17,7 +17,6 @@
package com.android.launcher3;
import android.app.SearchManager;
-import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -174,6 +173,10 @@ public class LauncherModel extends BroadcastReceiver
// sBgWorkspaceScreens is the ordered set of workspace screens.
static final ArrayList sBgWorkspaceScreens = new ArrayList();
+ // sBgWidgetProviders is the set of widget providers including custom internal widgets
+ public static HashMap sBgWidgetProviders;
+ public static boolean sWidgetProvidersDirty;
+
// sPendingPackages is a set of packages which could be on sdcard and are not available yet
static final HashMap> sPendingPackages =
new HashMap>();
@@ -1265,7 +1268,6 @@ public class LauncherModel extends BroadcastReceiver
PackageUpdatedTask.OP_UNAVAILABLE, packageNames,
user));
}
-
}
/**
@@ -1837,7 +1839,6 @@ public class LauncherModel extends BroadcastReceiver
final Context context = mContext;
final ContentResolver contentResolver = context.getContentResolver();
final PackageManager manager = context.getPackageManager();
- final AppWidgetManager widgets = AppWidgetManager.getInstance(context);
final boolean isSafeMode = manager.isSafeMode();
final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);
final boolean isSdCardReady = context.registerReceiver(null,
@@ -2174,7 +2175,11 @@ public class LauncherModel extends BroadcastReceiver
break;
case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
+ case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:
// Read all Launcher-specific widget details
+ boolean customWidget = itemType ==
+ LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
+
int appWidgetId = c.getInt(appWidgetIdIndex);
String savedProvider = c.getString(appWidgetProviderIndex);
id = c.getLong(idIndex);
@@ -2188,14 +2193,16 @@ public class LauncherModel extends BroadcastReceiver
final boolean wasProviderReady = (restoreStatus &
LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) == 0;
- final AppWidgetProviderInfo provider = isIdValid
- ? widgets.getAppWidgetInfo(appWidgetId)
- : findAppWidgetProviderInfoWithComponent(context, component);
+ final LauncherAppWidgetProviderInfo provider =
+ LauncherModel.getProviderInfo(context,
+ ComponentName.unflattenFromString(savedProvider));
final boolean isProviderReady = isValidProvider(provider);
- if (!isSafeMode && wasProviderReady && !isProviderReady) {
+ if (!isSafeMode && !customWidget &&
+ wasProviderReady && !isProviderReady) {
String log = "Deleting widget that isn't installed anymore: "
+ "id=" + id + " appWidgetId=" + appWidgetId;
+
Log.e(TAG, log);
Launcher.addDumpLog(TAG, log, false);
itemsToRemove.add(id);
@@ -2203,10 +2210,13 @@ public class LauncherModel extends BroadcastReceiver
if (isProviderReady) {
appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,
provider.provider);
- int[] minSpan =
- Launcher.getMinSpanForWidget(context, provider);
- appWidgetInfo.minSpanX = minSpan[0];
- appWidgetInfo.minSpanY = minSpan[1];
+
+ if (!customWidget) {
+ int[] minSpan =
+ Launcher.getMinSpanForWidget(context, provider);
+ appWidgetInfo.minSpanX = minSpan[0];
+ appWidgetInfo.minSpanY = minSpan[1];
+ }
int status = restoreStatus;
if (!wasProviderReady) {
@@ -2251,6 +2261,12 @@ public class LauncherModel extends BroadcastReceiver
appWidgetInfo.spanX = c.getInt(spanXIndex);
appWidgetInfo.spanY = c.getInt(spanYIndex);
+ if (!customWidget) {
+ int[] minSpan = Launcher.getMinSpanForWidget(context, provider);
+ appWidgetInfo.minSpanX = minSpan[0];
+ appWidgetInfo.minSpanY = minSpan[1];
+ }
+
container = c.getInt(containerIndex);
if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&
container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
@@ -2266,17 +2282,21 @@ public class LauncherModel extends BroadcastReceiver
break;
}
- String providerName = appWidgetInfo.providerName.flattenToString();
- if (!providerName.equals(savedProvider) ||
- (appWidgetInfo.restoreStatus != restoreStatus)) {
- ContentValues values = new ContentValues();
- values.put(LauncherSettings.Favorites.APPWIDGET_PROVIDER,
- providerName);
- values.put(LauncherSettings.Favorites.RESTORED,
- appWidgetInfo.restoreStatus);
- String where = BaseColumns._ID + "= ?";
- String[] args = {Long.toString(id)};
- contentResolver.update(contentUri, values, where, args);
+ if (!customWidget) {
+ String providerName =
+ appWidgetInfo.providerName.flattenToString();
+ if (!providerName.equals(savedProvider) ||
+ (appWidgetInfo.restoreStatus != restoreStatus)) {
+ ContentValues values = new ContentValues();
+ values.put(
+ LauncherSettings.Favorites.APPWIDGET_PROVIDER,
+ providerName);
+ values.put(LauncherSettings.Favorites.RESTORED,
+ appWidgetInfo.restoreStatus);
+ String where = BaseColumns._ID + "= ?";
+ String[] args = {Long.toString(id)};
+ contentResolver.update(contentUri, values, where, args);
+ }
}
sBgItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);
sBgAppWidgets.add(appWidgetInfo);
@@ -3292,12 +3312,44 @@ public class LauncherModel extends BroadcastReceiver
}
}
+ public static List getWidgetProviders(Context context) {
+ synchronized (sBgLock) {
+ if (sBgWidgetProviders != null && !sWidgetProvidersDirty) {
+ return new ArrayList(sBgWidgetProviders.values());
+ }
+ sBgWidgetProviders = new HashMap();
+ List widgets =
+ AppWidgetManagerCompat.getInstance(context).getAllProviders();
+ LauncherAppWidgetProviderInfo info;
+ for (AppWidgetProviderInfo pInfo : widgets) {
+ info = LauncherAppWidgetProviderInfo.fromProviderInfo(context, pInfo);
+ sBgWidgetProviders.put(info.provider, info);
+ }
+
+ Collection customWidgets = Launcher.getCustomAppWidgets().values();
+ for (CustomAppWidget widget : customWidgets) {
+ info = new LauncherAppWidgetProviderInfo(context, widget);
+ sBgWidgetProviders.put(info.provider, info);
+ }
+ sWidgetProvidersDirty = false;
+ return new ArrayList(sBgWidgetProviders.values());
+ }
+ }
+
+ public static LauncherAppWidgetProviderInfo getProviderInfo(Context ctx, ComponentName name) {
+ synchronized (sBgLock) {
+ if (sBgWidgetProviders == null) {
+ getWidgetProviders(ctx);
+ }
+ return sBgWidgetProviders.get(name);
+ }
+ }
+
// Returns a list of ResolveInfos/AppWindowInfos in sorted order
public static ArrayList