1 package com.android.launcher3; 2 3 import android.appwidget.AppWidgetHost; 4 import android.appwidget.AppWidgetManager; 5 import android.appwidget.AppWidgetProviderInfo; 6 import android.content.BroadcastReceiver; 7 import android.content.ContentResolver; 8 import android.content.Context; 9 import android.content.Intent; 10 import android.database.Cursor; 11 import android.util.Log; 12 13 import com.android.launcher3.LauncherSettings.Favorites; 14 import com.android.launcher3.config.FeatureFlags; 15 import com.android.launcher3.model.LoaderTask; 16 import com.android.launcher3.provider.RestoreDbTask; 17 import com.android.launcher3.util.ContentWriter; 18 19 import androidx.annotation.WorkerThread; 20 21 public class AppWidgetsRestoredReceiver extends BroadcastReceiver { 22 23 private static final String TAG = "AWRestoredReceiver"; 24 25 @Override onReceive(final Context context, Intent intent)26 public void onReceive(final Context context, Intent intent) { 27 if (AppWidgetManager.ACTION_APPWIDGET_HOST_RESTORED.equals(intent.getAction())) { 28 int hostId = intent.getIntExtra(AppWidgetManager.EXTRA_HOST_ID, 0); 29 Log.d(TAG, "Widget ID map received for host:" + hostId); 30 if (hostId != LauncherAppWidgetHost.APPWIDGET_HOST_ID) { 31 return; 32 } 33 34 final int[] oldIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_OLD_IDS); 35 final int[] newIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS); 36 if (oldIds != null && newIds != null && oldIds.length == newIds.length) { 37 RestoreDbTask.setRestoredAppWidgetIds(context, oldIds, newIds); 38 } else { 39 Log.e(TAG, "Invalid host restored received"); 40 } 41 } 42 } 43 44 /** 45 * Updates the app widgets whose id has changed during the restore process. 46 */ 47 @WorkerThread restoreAppWidgetIds(Context context, int[] oldWidgetIds, int[] newWidgetIds)48 public static void restoreAppWidgetIds(Context context, int[] oldWidgetIds, int[] newWidgetIds) { 49 AppWidgetHost appWidgetHost = new LauncherAppWidgetHost(context); 50 if (FeatureFlags.GO_DISABLE_WIDGETS) { 51 Log.e(TAG, "Skipping widget ID remap as widgets not supported"); 52 appWidgetHost.deleteHost(); 53 return; 54 } 55 if (!RestoreDbTask.isPending(context)) { 56 // Someone has already gone through our DB once, probably LoaderTask. Skip any further 57 // modifications of the DB. 58 Log.e(TAG, "Skipping widget ID remap as DB already in use"); 59 for (int widgetId : newWidgetIds) { 60 Log.d(TAG, "Deleting widgetId: " + widgetId); 61 appWidgetHost.deleteAppWidgetId(widgetId); 62 } 63 return; 64 } 65 final ContentResolver cr = context.getContentResolver(); 66 final AppWidgetManager widgets = AppWidgetManager.getInstance(context); 67 68 for (int i = 0; i < oldWidgetIds.length; i++) { 69 Log.i(TAG, "Widget state restore id " + oldWidgetIds[i] + " => " + newWidgetIds[i]); 70 71 final AppWidgetProviderInfo provider = widgets.getAppWidgetInfo(newWidgetIds[i]); 72 final int state; 73 if (LoaderTask.isValidProvider(provider)) { 74 // This will ensure that we show 'Click to setup' UI if required. 75 state = LauncherAppWidgetInfo.FLAG_UI_NOT_READY; 76 } else { 77 state = LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY; 78 } 79 80 String[] widgetIdParams = new String[] { Integer.toString(oldWidgetIds[i]) }; 81 int result = new ContentWriter(context, new ContentWriter.CommitParams( 82 "appWidgetId=? and (restored & 1) = 1", widgetIdParams)) 83 .put(LauncherSettings.Favorites.APPWIDGET_ID, newWidgetIds[i]) 84 .put(LauncherSettings.Favorites.RESTORED, state) 85 .commit(); 86 87 if (result == 0) { 88 Cursor cursor = cr.query(Favorites.CONTENT_URI, 89 new String[] {Favorites.APPWIDGET_ID}, 90 "appWidgetId=?", widgetIdParams, null); 91 try { 92 if (!cursor.moveToFirst()) { 93 // The widget no long exists. 94 appWidgetHost.deleteAppWidgetId(newWidgetIds[i]); 95 } 96 } finally { 97 cursor.close(); 98 } 99 } 100 } 101 102 LauncherAppState app = LauncherAppState.getInstanceNoCreate(); 103 if (app != null) { 104 app.getModel().forceReload(); 105 } 106 } 107 } 108