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