1package com.android.launcher3;
2
3import android.appwidget.AppWidgetHost;
4import android.appwidget.AppWidgetManager;
5import android.appwidget.AppWidgetProviderInfo;
6import android.content.BroadcastReceiver;
7import android.content.ContentResolver;
8import android.content.ContentValues;
9import android.content.Context;
10import android.content.Intent;
11import android.database.Cursor;
12import android.os.AsyncTask;
13import android.util.Log;
14
15import com.android.launcher3.LauncherSettings.Favorites;
16
17import java.util.ArrayList;
18import java.util.List;
19
20public class AppWidgetsRestoredReceiver extends BroadcastReceiver {
21
22    private static final String TAG = "AppWidgetsRestoredReceiver";
23
24    @Override
25    public void onReceive(Context context, Intent intent) {
26        if (AppWidgetManager.ACTION_APPWIDGET_HOST_RESTORED.equals(intent.getAction())) {
27            int[] oldIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_OLD_IDS);
28            int[] newIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
29            if (oldIds.length == newIds.length) {
30                restoreAppWidgetIds(context, oldIds, newIds);
31            } else {
32                Log.e(TAG, "Invalid host restored received");
33            }
34        }
35    }
36
37    /**
38     * Updates the app widgets whose id has changed during the restore process.
39     */
40    static void restoreAppWidgetIds(Context context, int[] oldWidgetIds, int[] newWidgetIds) {
41        final ContentResolver cr = context.getContentResolver();
42        final List<Integer> idsToRemove = new ArrayList<Integer>();
43        final AppWidgetManager widgets = AppWidgetManager.getInstance(context);
44
45        for (int i = 0; i < oldWidgetIds.length; i++) {
46            Log.i(TAG, "Widget state restore id " + oldWidgetIds[i] + " => " + newWidgetIds[i]);
47
48            final AppWidgetProviderInfo provider = widgets.getAppWidgetInfo(newWidgetIds[i]);
49            final int state;
50            if (LauncherModel.isValidProvider(provider)) {
51                state = LauncherAppWidgetInfo.RESTORE_COMPLETED;
52            } else {
53                state = LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;
54            }
55
56            ContentValues values = new ContentValues();
57            values.put(LauncherSettings.Favorites.APPWIDGET_ID, newWidgetIds[i]);
58            values.put(LauncherSettings.Favorites.RESTORED, state);
59
60            String[] widgetIdParams = new String[] { Integer.toString(oldWidgetIds[i]) };
61
62            int result = cr.update(Favorites.CONTENT_URI, values,
63                    "appWidgetId=? and (restored & 1) = 1", widgetIdParams);
64            if (result == 0) {
65                Cursor cursor = cr.query(Favorites.CONTENT_URI,
66                        new String[] {Favorites.APPWIDGET_ID},
67                        "appWidgetId=?", widgetIdParams, null);
68                try {
69                    if (!cursor.moveToFirst()) {
70                        // The widget no long exists.
71                        idsToRemove.add(newWidgetIds[i]);
72                    }
73                } finally {
74                    cursor.close();
75                }
76            }
77        }
78        // Unregister the widget IDs which are not present on the workspace. This could happen
79        // when a widget place holder is removed from workspace, before this method is called.
80        if (!idsToRemove.isEmpty()) {
81            final AppWidgetHost appWidgetHost =
82                    new AppWidgetHost(context, Launcher.APPWIDGET_HOST_ID);
83            new AsyncTask<Void, Void, Void>() {
84                public Void doInBackground(Void ... args) {
85                    for (Integer id : idsToRemove) {
86                        appWidgetHost.deleteAppWidgetId(id);
87                        Log.e(TAG, "Widget no longer present, appWidgetId=" + id);
88                    }
89                    return null;
90                }
91            }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
92        }
93    }
94}
95