From 5940042d39b576553c2499bcf3d0641281e6ad52 Mon Sep 17 00:00:00 2001 From: Adam Cohen Date: Wed, 5 Mar 2014 18:07:04 -0800 Subject: Supporting custom widgets provided by launcher -> This change provides integration for widgets provided by the launcher package which can run arbitrary code. Change-Id: I6052da5c4afed7ee72e3b44d045b9c46f2d84c42 --- .../android/launcher3/AppWidgetResizeFrame.java | 24 ++-- .../android/launcher3/AppsCustomizePagedView.java | 55 +++++---- src/com/android/launcher3/CellLayout.java | 14 ++- src/com/android/launcher3/CustomAppWidget.java | 14 +++ src/com/android/launcher3/DeleteDropTarget.java | 6 +- src/com/android/launcher3/DeviceProfile.java | 25 ++-- src/com/android/launcher3/DummyWidget.java | 50 ++++++++ src/com/android/launcher3/Launcher.java | 136 +++++++++------------ .../android/launcher3/LauncherAppWidgetHost.java | 27 ++++ .../launcher3/LauncherAppWidgetHostView.java | 17 ++- .../android/launcher3/LauncherAppWidgetInfo.java | 16 ++- .../launcher3/LauncherAppWidgetProviderInfo.java | 89 ++++++++++++++ .../android/launcher3/LauncherBackupHelper.java | 16 +-- src/com/android/launcher3/LauncherModel.java | 123 ++++++++++++------- src/com/android/launcher3/LauncherSettings.java | 5 + src/com/android/launcher3/PagedViewWidget.java | 8 +- src/com/android/launcher3/PendingAddItemInfo.java | 31 ++--- .../launcher3/ShortcutAndWidgetContainer.java | 9 ++ src/com/android/launcher3/WidgetPreviewLoader.java | 18 ++- src/com/android/launcher3/Workspace.java | 26 ++-- .../launcher3/compat/AppWidgetManagerCompat.java | 9 +- .../compat/AppWidgetManagerCompatV16.java | 9 +- .../launcher3/compat/AppWidgetManagerCompatVL.java | 18 +-- 23 files changed, 514 insertions(+), 231 deletions(-) create mode 100644 src/com/android/launcher3/CustomAppWidget.java create mode 100644 src/com/android/launcher3/DummyWidget.java create mode 100644 src/com/android/launcher3/LauncherAppWidgetProviderInfo.java (limited to 'src/com/android') diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java index f57f4d036..240250750 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 c8187f068..9e7e523e0 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); - - // 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()); + LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo) rawInfo; + createItemInfo = new PendingAddWidgetInfo(info, null); + + 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 0ff1ef4ad..7424d61c1 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 000000000..1b4ed79c0 --- /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 ea058ea71..5a5c0027e 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 d6aadcee1..34e1f3c5f 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 000000000..59cd80501 --- /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 ac46fd33d..0ceb862a7 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) { - if (appWidgetInfo == null) { - appWidgetInfo = 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); + private void completeAddAppWidget(int appWidgetId, long container, long screenId, + AppWidgetHostView hostView, LauncherAppWidgetProviderInfo 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]); + ItemInfo info = mPendingAddInfo; + if (appWidgetInfo == null) { + appWidgetInfo = LauncherAppWidgetProviderInfo.fromProviderInfo(this, + mAppWidgetManager.getAppWidgetInfo(appWidgetId)); } - 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; + if (appWidgetInfo.isCustomWidget) { + appWidgetId = LauncherAppWidgetInfo.CUSTOM_WIDGET_ID; } - // 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 a309f268c..840508a1d 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 e39727b17..ebe55ab78 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 5c6535a24..aad18b578 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 000000000..e7f49b2ce --- /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 c260fbc33..7f3a7985e 100644 --- a/src/com/android/launcher3/LauncherBackupHelper.java +++ b/src/com/android/launcher3/LauncherBackupHelper.java @@ -906,7 +906,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; @@ -1074,19 +1075,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 954887dc3..3c1cf485d 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 getSortedWidgetsAndShortcuts(Context context) { PackageManager packageManager = context.getPackageManager(); final ArrayList widgetsAndShortcuts = new ArrayList(); - widgetsAndShortcuts.addAll(AppWidgetManagerCompat.getInstance(context).getAllProviders()); - + widgetsAndShortcuts.addAll(getWidgetProviders(context)); Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT); widgetsAndShortcuts.addAll(packageManager.queryIntentActivities(shortcutsIntent, 0)); Collections.sort(widgetsAndShortcuts, new WidgetAndShortcutNameComparator(context)); @@ -3583,21 +3635,6 @@ public class LauncherModel extends BroadcastReceiver } } - /** - * Attempts to find an AppWidgetProviderInfo that matches the given component. - */ - static AppWidgetProviderInfo findAppWidgetProviderInfoWithComponent(Context context, - ComponentName component) { - List widgets = - AppWidgetManager.getInstance(context).getInstalledProviders(); - for (AppWidgetProviderInfo info : widgets) { - if (info.provider.equals(component)) { - return info; - } - } - return null; - } - ShortcutInfo infoFromShortcutIntent(Context context, Intent data) { Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT); String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME); @@ -3783,16 +3820,16 @@ public class LauncherModel extends BroadcastReceiver if (mLabelCache.containsKey(a)) { labelA = mLabelCache.get(a); } else { - labelA = (a instanceof AppWidgetProviderInfo) - ? mManager.loadLabel((AppWidgetProviderInfo) a) + labelA = (a instanceof LauncherAppWidgetProviderInfo) + ? mManager.loadLabel((LauncherAppWidgetProviderInfo) a) : ((ResolveInfo) a).loadLabel(mPackageManager).toString().trim(); mLabelCache.put(a, labelA); } if (mLabelCache.containsKey(b)) { labelB = mLabelCache.get(b); } else { - labelB = (b instanceof AppWidgetProviderInfo) - ? mManager.loadLabel((AppWidgetProviderInfo) b) + labelB = (b instanceof LauncherAppWidgetProviderInfo) + ? mManager.loadLabel((LauncherAppWidgetProviderInfo) a) : ((ResolveInfo) b).loadLabel(mPackageManager).toString().trim(); mLabelCache.put(b, labelB); } diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java index 355370283..65e3d2848 100644 --- a/src/com/android/launcher3/LauncherSettings.java +++ b/src/com/android/launcher3/LauncherSettings.java @@ -238,6 +238,11 @@ class LauncherSettings { */ static final int ITEM_TYPE_APPWIDGET = 4; + /** + * The favorite is a custom widget provided by the launcher + */ + static final int ITEM_TYPE_CUSTOM_APPWIDGET = 5; + /** * The favorite is a clock */ diff --git a/src/com/android/launcher3/PagedViewWidget.java b/src/com/android/launcher3/PagedViewWidget.java index e6e11a312..41270e3be 100644 --- a/src/com/android/launcher3/PagedViewWidget.java +++ b/src/com/android/launcher3/PagedViewWidget.java @@ -117,8 +117,8 @@ public class PagedViewWidget extends LinearLayout { } } - public void applyFromAppWidgetProviderInfo(AppWidgetProviderInfo info, - int maxWidth, int[] cellSpan, WidgetPreviewLoader loader) { + public void applyFromAppWidgetProviderInfo(LauncherAppWidgetProviderInfo info, + int maxWidth, WidgetPreviewLoader loader) { LauncherAppState app = LauncherAppState.getInstance(); DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); @@ -132,8 +132,8 @@ public class PagedViewWidget extends LinearLayout { name.setText(AppWidgetManagerCompat.getInstance(getContext()).loadLabel(info)); final TextView dims = (TextView) findViewById(R.id.widget_dims); if (dims != null) { - int hSpan = Math.min(cellSpan[0], (int) grid.numColumns); - int vSpan = Math.min(cellSpan[1], (int) grid.numRows); + int hSpan = Math.min(info.spanX, (int) grid.numColumns); + int vSpan = Math.min(info.spanY, (int) grid.numRows); dims.setText(String.format(mDimensionsFormatString, hSpan, vSpan)); } mWidgetPreviewLoader = loader; diff --git a/src/com/android/launcher3/PendingAddItemInfo.java b/src/com/android/launcher3/PendingAddItemInfo.java index 967cc928e..ac54a262f 100644 --- a/src/com/android/launcher3/PendingAddItemInfo.java +++ b/src/com/android/launcher3/PendingAddItemInfo.java @@ -17,7 +17,6 @@ package com.android.launcher3; import android.appwidget.AppWidgetHostView; -import android.appwidget.AppWidgetProviderInfo; import android.content.ComponentName; import android.content.pm.ActivityInfo; import android.os.Bundle; @@ -54,17 +53,16 @@ class PendingAddWidgetInfo extends PendingAddItemInfo { int minResizeHeight; int previewImage; int icon; - AppWidgetProviderInfo info; + LauncherAppWidgetProviderInfo info; AppWidgetHostView boundWidget; Bundle bindOptions = null; - // Any configuration data that we want to pass to a configuration activity when - // starting up a widget - String mimeType; - Parcelable configurationData; - - public PendingAddWidgetInfo(AppWidgetProviderInfo i, String dataMimeType, Parcelable data) { - itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET; + public PendingAddWidgetInfo(LauncherAppWidgetProviderInfo i, Parcelable data) { + if (i.isCustomWidget) { + itemType = LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET; + } else { + itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET; + } this.info = i; componentName = i.provider; minWidth = i.minWidth; @@ -73,10 +71,15 @@ class PendingAddWidgetInfo extends PendingAddItemInfo { minResizeHeight = i.minResizeHeight; previewImage = i.previewImage; icon = i.icon; - if (dataMimeType != null && data != null) { - mimeType = dataMimeType; - configurationData = data; - } + + spanX = i.spanX; + spanY = i.spanY; + minSpanX = i.minSpanX; + minSpanY = i.minSpanY; + } + + public boolean isCustomWidget() { + return itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET; } // Copy constructor @@ -89,8 +92,6 @@ class PendingAddWidgetInfo extends PendingAddItemInfo { icon = copy.icon; info = copy.info; boundWidget = copy.boundWidget; - mimeType = copy.mimeType; - configurationData = copy.configurationData; componentName = copy.componentName; itemType = copy.itemType; spanX = copy.spanX; diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java index bb5601e90..ff0604540 100644 --- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java +++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java @@ -23,6 +23,7 @@ import android.graphics.Paint; import android.graphics.Rect; import android.view.View; import android.view.ViewGroup; +import android.view.ViewGroup.LayoutParams; public class ShortcutAndWidgetContainer extends ViewGroup { static final String TAG = "CellLayoutChildren"; @@ -75,6 +76,14 @@ public class ShortcutAndWidgetContainer extends ViewGroup { return null; } + public void addView(View child, int index, LayoutParams params, boolean inLayout) { + if (!inLayout) { + addView(child, index, params); + } else { + addViewInLayout(child, index, params, false); + } + } + @Override protected void dispatchDraw(Canvas canvas) { @SuppressWarnings("all") // suppress dead code warning diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java index 9cedae0f9..8f2d3edc3 100644 --- a/src/com/android/launcher3/WidgetPreviewLoader.java +++ b/src/com/android/launcher3/WidgetPreviewLoader.java @@ -333,7 +333,6 @@ public class WidgetPreviewLoader { sb.setLength(0); } else { sb.append(SHORTCUT_PREFIX); - ResolveInfo info = (ResolveInfo) o; sb.append(new ComponentName(info.activityInfo.packageName, info.activityInfo.name).flattenToString()); @@ -479,20 +478,19 @@ public class WidgetPreviewLoader { preview.getHeight() != mPreviewBitmapHeight)) { throw new RuntimeException("Improperly sized bitmap passed as argument"); } - if (info instanceof AppWidgetProviderInfo) { - return generateWidgetPreview((AppWidgetProviderInfo) info, preview); + if (info instanceof LauncherAppWidgetProviderInfo) { + return generateWidgetPreview((LauncherAppWidgetProviderInfo) info, preview); } else { return generateShortcutPreview( (ResolveInfo) info, mPreviewBitmapWidth, mPreviewBitmapHeight, preview); } } - public Bitmap generateWidgetPreview(AppWidgetProviderInfo info, Bitmap preview) { - int[] cellSpans = Launcher.getSpanForWidget(mContext, info); - int maxWidth = maxWidthForWidgetPreview(cellSpans[0]); - int maxHeight = maxHeightForWidgetPreview(cellSpans[1]); - return generateWidgetPreview(info, cellSpans[0], cellSpans[1], - maxWidth, maxHeight, preview, null); + public Bitmap generateWidgetPreview(LauncherAppWidgetProviderInfo info, Bitmap preview) { + int maxWidth = maxWidthForWidgetPreview(info.spanX); + int maxHeight = maxHeightForWidgetPreview(info.spanY); + return generateWidgetPreview(info, info.spanX, info.spanY, maxWidth, + maxHeight, preview, null); } public int maxWidthForWidgetPreview(int spanX) { @@ -505,7 +503,7 @@ public class WidgetPreviewLoader { mWidgetSpacingLayout.estimateCellHeight(spanY)); } - public Bitmap generateWidgetPreview(AppWidgetProviderInfo info, int cellHSpan, int cellVSpan, + public Bitmap generateWidgetPreview(LauncherAppWidgetProviderInfo info, int cellHSpan, int cellVSpan, int maxPreviewWidth, int maxPreviewHeight, Bitmap preview, int[] preScaledWidthOut) { // Load the preview image if possible if (maxPreviewWidth < 0) maxPreviewWidth = Integer.MAX_VALUE; diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 8bd799198..b6e85f304 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -3178,9 +3178,9 @@ public class Workspace extends SmoothPagedView // in its final location final LauncherAppWidgetHostView hostView = (LauncherAppWidgetHostView) cell; - AppWidgetProviderInfo pinfo = hostView.getAppWidgetInfo(); - if (pinfo != null && - pinfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE) { + LauncherAppWidgetProviderInfo pInfo = (LauncherAppWidgetProviderInfo) + hostView.getAppWidgetInfo(); + if (pInfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE) { final Runnable addResizeFrame = new Runnable() { public void run() { DragLayer dragLayer = mLauncher.getDragLayer(); @@ -3228,7 +3228,9 @@ public class Workspace extends SmoothPagedView mAnimatingViewIntoPlace = true; if (d.dragView.hasDrawn()) { final ItemInfo info = (ItemInfo) cell.getTag(); - if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET) { + boolean isWidget = info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET + || info.itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET; + if (isWidget) { int animationType = resizeOnDrop ? ANIMATE_INTO_POSITION_AND_RESIZE : ANIMATE_INTO_POSITION_AND_DISAPPEAR; animateWidgetDrop(info, parent, d.dragView, @@ -3951,6 +3953,7 @@ public class Workspace extends SmoothPagedView // When dragging and dropping from customization tray, we deal with creating // widgets/shortcuts/folders in a slightly different way switch (pendingInfo.itemType) { + case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET: case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: int span[] = new int[2]; span[0] = item.spanX; @@ -3968,8 +3971,10 @@ public class Workspace extends SmoothPagedView } } }; - View finalView = pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET - ? ((PendingAddWidgetInfo) pendingInfo).boundWidget : null; + boolean isWidget = pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET + || pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET; + + View finalView = isWidget ? ((PendingAddWidgetInfo) pendingInfo).boundWidget : null; if (finalView instanceof AppWidgetHostView && updateWidgetSize) { AppWidgetHostView awhv = (AppWidgetHostView) finalView; @@ -3978,7 +3983,7 @@ public class Workspace extends SmoothPagedView } int animationStyle = ANIMATE_INTO_POSITION_AND_DISAPPEAR; - if (pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET && + if (isWidget && ((PendingAddWidgetInfo) pendingInfo).info != null && ((PendingAddWidgetInfo) pendingInfo).info.configure != null) { animationStyle = ANIMATE_INTO_POSITION_AND_REMAIN; } @@ -4130,11 +4135,14 @@ public class Workspace extends SmoothPagedView Log.d(TAG, "6557954 Animate widget drop, final view is appWidgetHostView"); mLauncher.getDragLayer().removeView(finalView); } + + boolean isWidget = info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET || + info.itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET; if ((animationType == ANIMATE_INTO_POSITION_AND_RESIZE || external) && finalView != null) { Bitmap crossFadeBitmap = createWidgetBitmap(info, finalView); dragView.setCrossFadeBitmap(crossFadeBitmap); dragView.crossFade((int) (duration * 0.8f)); - } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET && external) { + } else if (isWidget && external) { scaleXY[0] = scaleXY[1] = Math.min(scaleXY[0], scaleXY[1]); } @@ -4984,7 +4992,7 @@ public class Workspace extends SmoothPagedView if (!changedInfo.isEmpty()) { DeferredWidgetRefresh widgetRefresh = new DeferredWidgetRefresh(changedInfo, mLauncher.getAppWidgetHost()); - if (LauncherModel.findAppWidgetProviderInfoWithComponent(getContext(), + if (LauncherModel.getProviderInfo(getContext(), changedInfo.get(0).providerName) != null) { // Re-inflate the widgets which have changed status widgetRefresh.run(); diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java index 6512d427e..e41a66fb4 100644 --- a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java +++ b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java @@ -26,6 +26,7 @@ import android.graphics.drawable.Drawable; import android.os.Bundle; import com.android.launcher3.IconCache; +import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.Utilities; import java.util.List; @@ -63,20 +64,20 @@ public abstract class AppWidgetManagerCompat { public abstract List getAllProviders(); - public abstract String loadLabel(AppWidgetProviderInfo info); + public abstract String loadLabel(LauncherAppWidgetProviderInfo info); public abstract boolean bindAppWidgetIdIfAllowed( int appWidgetId, AppWidgetProviderInfo info, Bundle options); - public abstract UserHandleCompat getUser(AppWidgetProviderInfo info); + public abstract UserHandleCompat getUser(LauncherAppWidgetProviderInfo info); public abstract void startConfigActivity(AppWidgetProviderInfo info, int widgetId, Activity activity, AppWidgetHost host, int requestCode); public abstract Drawable loadPreview(AppWidgetProviderInfo info); - public abstract Drawable loadIcon(AppWidgetProviderInfo info, IconCache cache); + public abstract Drawable loadIcon(LauncherAppWidgetProviderInfo info, IconCache cache); - public abstract Bitmap getBadgeBitmap(AppWidgetProviderInfo info, Bitmap bitmap); + public abstract Bitmap getBadgeBitmap(LauncherAppWidgetProviderInfo info, Bitmap bitmap); } diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java index f599f4303..767f16f62 100644 --- a/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java +++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java @@ -28,6 +28,7 @@ import android.os.Build; import android.os.Bundle; import com.android.launcher3.IconCache; +import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.Utilities; import java.util.List; @@ -44,7 +45,7 @@ class AppWidgetManagerCompatV16 extends AppWidgetManagerCompat { } @Override - public String loadLabel(AppWidgetProviderInfo info) { + public String loadLabel(LauncherAppWidgetProviderInfo info) { return info.label.trim(); } @@ -59,7 +60,7 @@ class AppWidgetManagerCompatV16 extends AppWidgetManagerCompat { } @Override - public UserHandleCompat getUser(AppWidgetProviderInfo info) { + public UserHandleCompat getUser(LauncherAppWidgetProviderInfo info) { return UserHandleCompat.myUserHandle(); } @@ -79,12 +80,12 @@ class AppWidgetManagerCompatV16 extends AppWidgetManagerCompat { } @Override - public Drawable loadIcon(AppWidgetProviderInfo info, IconCache cache) { + public Drawable loadIcon(LauncherAppWidgetProviderInfo info, IconCache cache) { return cache.getFullResIcon(info.provider.getPackageName(), info.icon); } @Override - public Bitmap getBadgeBitmap(AppWidgetProviderInfo info, Bitmap bitmap) { + public Bitmap getBadgeBitmap(LauncherAppWidgetProviderInfo info, Bitmap bitmap) { return bitmap; } } diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java index c3853ab62..158607adf 100644 --- a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java +++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java @@ -38,6 +38,7 @@ import android.view.View; import android.widget.Toast; import com.android.launcher3.IconCache; +import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.R; import java.util.ArrayList; @@ -65,8 +66,8 @@ class AppWidgetManagerCompatVL extends AppWidgetManagerCompat { } @Override - public String loadLabel(AppWidgetProviderInfo info) { - return info.loadLabel(mPm); + public String loadLabel(LauncherAppWidgetProviderInfo info) { + return info.getLabel(mPm); } @Override @@ -77,7 +78,10 @@ class AppWidgetManagerCompatVL extends AppWidgetManagerCompat { } @Override - public UserHandleCompat getUser(AppWidgetProviderInfo info) { + public UserHandleCompat getUser(LauncherAppWidgetProviderInfo info) { + if (info.isCustomWidget) { + return UserHandleCompat.myUserHandle(); + } return UserHandleCompat.fromUser(info.getProfile()); } @@ -99,13 +103,13 @@ class AppWidgetManagerCompatVL extends AppWidgetManagerCompat { } @Override - public Drawable loadIcon(AppWidgetProviderInfo info, IconCache cache) { - return info.loadIcon(mContext, cache.getFullResIconDpi()); + public Drawable loadIcon(LauncherAppWidgetProviderInfo info, IconCache cache) { + return info.getIcon(mContext, cache); } @Override - public Bitmap getBadgeBitmap(AppWidgetProviderInfo info, Bitmap bitmap) { - if (info.getProfile().equals(android.os.Process.myUserHandle())) { + public Bitmap getBadgeBitmap(LauncherAppWidgetProviderInfo info, Bitmap bitmap) { + if (info.isCustomWidget || info.getProfile().equals(android.os.Process.myUserHandle())) { return bitmap; } -- cgit v1.2.3