Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ff572277 authored by Sunny Goyal's avatar Sunny Goyal
Browse files

Adding support to restore widgets even for jelly beans.

> Show 'widget-not-ready' until the widget app is installed
> Once the app is installed, bind a new widget id (not required on L if
  id-remap was received).
  **Remove the widget if bind failed
> If the widget has no configuration screen, show the widget, otherwise
  show 'setup-widget'.
> Clicking 'setup-widget' shows the config screen, and updates the
  widget on RESULT_OK.

issue: 10779035

Change-Id: I2f8b06d09dd6acbc498cdd93edc59c26e5ce17af
parent 6075170b
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -193,9 +193,12 @@ s -->
    <!-- Text to show user in place of a gadget when we can't display it properly -->
    <string name="gadget_error_text">Problem loading widget</string>

    <!-- Text to show user in place of a gadget when it is not yet ready/initialized. -->
    <!-- Text to show user in place of a gadget when it is not yet ready. -->
    <string name="gadget_pending_text" translatable="false">Widget not ready</string>

    <!-- Text to show user in place of a gadget when it is not yet initialized. -->
    <string name="gadget_setup_text" translatable="false">Setup widget</string>

    <!-- Text to inform the user that they can't uninstall a system application -->
    <string name="uninstall_system_app_text">This is a system app and can\'t be uninstalled.</string>

+8 −4
Original line number Diff line number Diff line
@@ -46,17 +46,21 @@ public class AppWidgetsRestoredReceiver extends BroadcastReceiver {
            Log.i(TAG, "Widget state restore id " + oldWidgetIds[i] + " => " + newWidgetIds[i]);

            final AppWidgetProviderInfo provider = widgets.getAppWidgetInfo(newWidgetIds[i]);
            final int state;
            if (LauncherModel.isValidProvider(provider)) {
                state = LauncherAppWidgetInfo.RESTORE_COMPLETED;
            } else {
                state = LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;
            }

            ContentValues values = new ContentValues();
            values.put(LauncherSettings.Favorites.APPWIDGET_ID, newWidgetIds[i]);
            values.put(LauncherSettings.Favorites.RESTORED, LauncherModel.isValidProvider(provider)
                    ? LauncherAppWidgetInfo.RESTORE_COMPLETED
                            : LauncherAppWidgetInfo.RESTORE_PROVIDER_PENDING);
            values.put(LauncherSettings.Favorites.RESTORED, state);

            String[] widgetIdParams = new String[] { Integer.toString(oldWidgetIds[i]) };

            int result = cr.update(Favorites.CONTENT_URI, values,
                    "appWidgetId=? and restored=1", widgetIdParams);
                    "appWidgetId=? and (restored & 1) = 1", widgetIdParams);
            if (result == 0) {
                Cursor cursor = cr.query(Favorites.CONTENT_URI,
                        new String[] {Favorites.APPWIDGET_ID},
+10 −10
Original line number Diff line number Diff line
@@ -148,6 +148,8 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
        LauncherTransitionable {
    static final String TAG = "AppsCustomizePagedView";

    private static Rect sTmpRect = new Rect();

    /**
     * The different content types that this paged view can show.
     */
@@ -223,8 +225,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
    private ArrayList<Runnable> mDeferredPrepareLoadWidgetPreviewsTasks =
        new ArrayList<Runnable>();

    private Rect mTmpRect = new Rect();

    WidgetPreviewLoader mWidgetPreviewLoader;

    private boolean mInBulkBind;
@@ -540,26 +540,26 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
        mLauncher.getWorkspace().beginDragShared(v, this);
    }

    Bundle getDefaultOptionsForWidget(Launcher launcher, PendingAddWidgetInfo info) {
    static Bundle getDefaultOptionsForWidget(Launcher launcher, PendingAddWidgetInfo info) {
        Bundle options = null;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            AppWidgetResizeFrame.getWidgetSizeRanges(mLauncher, info.spanX, info.spanY, mTmpRect);
            Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(mLauncher,
            AppWidgetResizeFrame.getWidgetSizeRanges(launcher, info.spanX, info.spanY, sTmpRect);
            Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(launcher,
                    info.componentName, null);

            float density = getResources().getDisplayMetrics().density;
            float density = launcher.getResources().getDisplayMetrics().density;
            int xPaddingDips = (int) ((padding.left + padding.right) / density);
            int yPaddingDips = (int) ((padding.top + padding.bottom) / density);

            options = new Bundle();
            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH,
                    mTmpRect.left - xPaddingDips);
                    sTmpRect.left - xPaddingDips);
            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT,
                    mTmpRect.top - yPaddingDips);
                    sTmpRect.top - yPaddingDips);
            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH,
                    mTmpRect.right - xPaddingDips);
                    sTmpRect.right - xPaddingDips);
            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT,
                    mTmpRect.bottom - yPaddingDips);
                    sTmpRect.bottom - yPaddingDips);
        }
        return options;
    }
+6 −2
Original line number Diff line number Diff line
@@ -124,6 +124,12 @@ public class ItemInfo {
    }

    ItemInfo(ItemInfo info) {
        copyFrom(info);
        // tempdebug:
        LauncherModel.checkItemInfo(this);
    }

    public void copyFrom(ItemInfo info) {
        id = info.id;
        cellX = info.cellX;
        cellY = info.cellY;
@@ -134,8 +140,6 @@ public class ItemInfo {
        container = info.container;
        user = info.user;
        contentDescription = info.contentDescription;
        // tempdebug:
        LauncherModel.checkItemInfo(this);
    }

    public Intent getIntent() {
+127 −3
Original line number Diff line number Diff line
@@ -65,7 +65,6 @@ import android.os.Handler;
import android.os.Message;
import android.os.StrictMode;
import android.os.SystemClock;
import android.provider.Settings;
import android.speech.RecognizerIntent;
import android.text.Selection;
import android.text.SpannableStringBuilder;
@@ -153,6 +152,7 @@ public class Launcher extends Activity
    private static final int REQUEST_PICK_WALLPAPER = 10;

    private static final int REQUEST_BIND_APPWIDGET = 11;
    private static final int REQUEST_RECONFIGURE_APPWIDGET = 12;

    /**
     * IntentStarter uses request codes starting with this. This must be greater than all activity
@@ -752,6 +752,9 @@ public class Launcher extends Activity
            case REQUEST_CREATE_APPWIDGET:
                completeAddAppWidget(args.appWidgetId, args.container, screenId, null, null);
                break;
            case REQUEST_RECONFIGURE_APPWIDGET:
                completeRestoreAppWidget(args.appWidgetId);
                break;
        }
        // Before adding this resetAddInfo(), after a shortcut was added to a workspace screen,
        // if you turned the screen off and then back while in All Apps, Launcher would not
@@ -854,6 +857,21 @@ public class Launcher extends Activity
            return;
        }

        if (requestCode == REQUEST_RECONFIGURE_APPWIDGET) {
            if (resultCode == RESULT_OK) {
                // Update the widget view.
                PendingAddArguments args = preparePendingAddArgs(requestCode, data,
                        pendingAddWidgetId, mPendingAddInfo);
                if (workspaceLocked) {
                    sPendingAddItem = args;
                } else {
                    completeAdd(args);
                }
            }
            // Leave the widget in the pending state if the user canceled the configure.
            return;
        }

        // The pattern used here is that a user PICKs a specific application,
        // which, depending on the target, might need to CREATE the actual target.

@@ -2446,6 +2464,10 @@ public class Launcher extends Activity
            }
        } else if (v == mAllAppsButton) {
            onClickAllAppsButton(v);
        } else if (tag instanceof LauncherAppWidgetInfo) {
            if (v instanceof PendingAppWidgetHostView) {
                onClickPendingWidget((PendingAppWidgetHostView) v);
            }
        }
    }

@@ -2453,6 +2475,27 @@ public class Launcher extends Activity
        return false;
    }

    /**
     * Event handler for the app widget view which has not fully restored.
     */
    public void onClickPendingWidget(PendingAppWidgetHostView v) {
        if (v.isReadyForClickSetup()) {
            LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) v.getTag();
            int widgetId = info.appWidgetId;
            AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(widgetId);
            if (appWidgetInfo != null) {
                mPendingAddWidgetInfo = appWidgetInfo;
                mPendingAddInfo.copyFrom(info);
                mPendingAddWidgetId = widgetId;

                Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
                intent.setComponent(appWidgetInfo.configure);
                intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, info.appWidgetId);
                Utilities.startActivityForResultSafely(this, intent, REQUEST_RECONFIGURE_APPWIDGET);
            }
        }
    }

    /**
     * Event handler for the search button
     *
@@ -4398,7 +4441,64 @@ public class Launcher extends Activity
        }
        final Workspace workspace = mWorkspace;

        final AppWidgetProviderInfo appWidgetInfo;
        AppWidgetProviderInfo appWidgetInfo;
        if (((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
                            + " belongs to component " + item.providerName
                            + ", as the povider is null");
                }
                LauncherModel.deleteItemFromDatabase(this, item);
                return;
            }
            // 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);
            pendingInfo.spanX = item.spanX;
            pendingInfo.spanY = item.spanY;
            pendingInfo.minSpanX = item.minSpanX;
            pendingInfo.minSpanY = item.minSpanY;
            Bundle options =
                    AppsCustomizePagedView.getDefaultOptionsForWidget(this, pendingInfo);

            boolean success = false;
            int newWidgetId = mAppWidgetHost.allocateAppWidgetId();
            if (options != null) {
                success = mAppWidgetManager.bindAppWidgetIdIfAllowed(newWidgetId,
                        appWidgetInfo.provider, options);
            } else {
                success = mAppWidgetManager.bindAppWidgetIdIfAllowed(newWidgetId,
                        appWidgetInfo.provider);
            }

            // TODO consider showing a permission dialog when the widget is clicked.
            if (!success) {
                mAppWidgetHost.deleteAppWidgetId(newWidgetId);
                if (DEBUG_WIDGETS) {
                    Log.d(TAG, "Removing restored widget: id=" + item.appWidgetId
                            + " belongs to component " + item.providerName
                            + ", as the launcher is unable to bing a new widget id");
                }
                LauncherModel.deleteItemFromDatabase(this, item);
                return;
            }

            item.appWidgetId = newWidgetId;

            // If the widget has a configure activity, it is still needs to set it up, otherwise
            // the widget is ready to go.
            item.restoreStatus = (appWidgetInfo.configure == null)
                    ? LauncherAppWidgetInfo.RESTORE_COMPLETED
                    : LauncherAppWidgetInfo.FLAG_UI_NOT_READY;

            LauncherModel.updateItemInDatabase(this, item);
        }

        if (item.restoreStatus == LauncherAppWidgetInfo.RESTORE_COMPLETED) {
            final int appWidgetId = item.appWidgetId;
            appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
@@ -4409,8 +4509,9 @@ public class Launcher extends Activity
            item.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
        } else {
            appWidgetInfo = null;
            item.hostView = new LauncherAppWidgetHostView(this, false);
            item.hostView = new PendingAppWidgetHostView(this, item.restoreStatus);
            item.hostView.updateAppWidget(null);
            item.hostView.setOnClickListener(this);
        }

        item.hostView.setTag(item);
@@ -4428,6 +4529,29 @@ public class Launcher extends Activity
        }
    }

    /**
     * Restores a pending widget.
     *
     * @param appWidgetId The app widget id
     * @param cellInfo The position on screen where to create the widget.
     */
    private void completeRestoreAppWidget(final int appWidgetId) {
        LauncherAppWidgetHostView view = mWorkspace.getWidgetForAppWidgetId(appWidgetId);
        if ((view == null) || !(view instanceof PendingAppWidgetHostView)) {
            Log.e(TAG, "Widget update called, when the widget no longer exists.");
            return;
        }

        PendingAppWidgetHostView pendingView = (PendingAppWidgetHostView) view;
        pendingView.setStatus(LauncherAppWidgetInfo.RESTORE_COMPLETED);

        LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) pendingView.getTag();
        info.restoreStatus = LauncherAppWidgetInfo.RESTORE_COMPLETED;

        mWorkspace.reinflateWidgetsIfNecessary();
        LauncherModel.updateItemInDatabase(this, info);
    }

    public void onPageBoundSynchronously(int page) {
        mSynchronouslyBoundPages.add(page);
    }
Loading