blob: 3dd8627177be382f46320e0caa006fa9e3a21ea5 [file] [log] [blame]
package com.android.launcher3;
import static android.os.Process.myUserHandle;
import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.WorkerThread;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.model.LoaderTask;
import com.android.launcher3.model.ModelDbController;
import com.android.launcher3.model.WidgetsModel;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.provider.LauncherDbUtils;
import com.android.launcher3.provider.RestoreDbTask;
import com.android.launcher3.util.ContentWriter;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.widget.LauncherWidgetHolder;
public class AppWidgetsRestoredReceiver extends BroadcastReceiver {
private static final String TAG = "AWRestoredReceiver";
@Override
public void onReceive(final Context context, Intent intent) {
if (AppWidgetManager.ACTION_APPWIDGET_HOST_RESTORED.equals(intent.getAction())) {
int hostId = intent.getIntExtra(AppWidgetManager.EXTRA_HOST_ID, 0);
Log.d(TAG, "Widget ID map received for host:" + hostId);
if (hostId != LauncherWidgetHolder.APPWIDGET_HOST_ID) {
return;
}
final int[] oldIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_OLD_IDS);
final int[] newIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
if (oldIds != null && newIds != null && oldIds.length == newIds.length) {
RestoreDbTask.setRestoredAppWidgetIds(context, oldIds, newIds);
} else {
Log.e(TAG, "Invalid host restored received");
}
}
}
/**
* Updates the app widgets whose id has changed during the restore process.
*/
@WorkerThread
public static void restoreAppWidgetIds(Context context, ModelDbController controller,
int[] oldWidgetIds, int[] newWidgetIds, @NonNull AppWidgetHost host) {
if (WidgetsModel.GO_DISABLE_WIDGETS) {
Log.e(TAG, "Skipping widget ID remap as widgets not supported");
host.deleteHost();
return;
}
if (!RestoreDbTask.isPending(context)) {
// Someone has already gone through our DB once, probably LoaderTask. Skip any further
// modifications of the DB.
Log.e(TAG, "Skipping widget ID remap as DB already in use");
for (int widgetId : newWidgetIds) {
Log.d(TAG, "Deleting widgetId: " + widgetId);
host.deleteAppWidgetId(widgetId);
}
return;
}
final AppWidgetManager widgets = AppWidgetManager.getInstance(context);
Log.d(TAG, "restoreAppWidgetIds: "
+ "oldWidgetIds=" + IntArray.wrap(oldWidgetIds).toConcatString()
+ ", newWidgetIds=" + IntArray.wrap(newWidgetIds).toConcatString());
try {
IntArray result = LauncherDbUtils.queryIntArray(false, controller.getDb(),
Favorites.TABLE_NAME, Favorites.APPWIDGET_ID,
Favorites.APPWIDGET_ID + "!=" + LauncherAppWidgetInfo.NO_ID, null, null);
// TODO(b/234700507): Remove the logs after the bug is fixed
Log.d(TAG, "restoreAppWidgetIds: all widget ids in database: "
+ result.toConcatString());
} catch (Exception ex) {
Log.e(TAG, "Getting widget ids from the database failed", ex);
}
for (int i = 0; i < oldWidgetIds.length; i++) {
Log.i(TAG, "Widget state restore id " + oldWidgetIds[i] + " => " + newWidgetIds[i]);
final AppWidgetProviderInfo provider = widgets.getAppWidgetInfo(newWidgetIds[i]);
final int state;
if (LoaderTask.isValidProvider(provider)) {
// This will ensure that we show 'Click to setup' UI if required.
state = LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
} else {
state = LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;
}
// b/135926478: Work profile widget restore is broken in platform. This forces us to
// recreate the widget during loading with the correct host provider.
long mainProfileId = UserCache.INSTANCE.get(context)
.getSerialNumberForUser(myUserHandle());
String oldWidgetId = Integer.toString(oldWidgetIds[i]);
final String where = "appWidgetId=? and (restored & 1) = 1 and profileId=?";
final String[] args = new String[] { oldWidgetId, Long.toString(mainProfileId) };
int result = new ContentWriter(context,
new ContentWriter.CommitParams(controller, where, args))
.put(LauncherSettings.Favorites.APPWIDGET_ID, newWidgetIds[i])
.put(LauncherSettings.Favorites.RESTORED, state)
.commit();
if (result == 0) {
// TODO(b/234700507): Remove the logs after the bug is fixed
Log.e(TAG, "restoreAppWidgetIds: remapping failed since the widget is not in"
+ " the database anymore");
try (Cursor cursor = controller.getDb().query(
Favorites.TABLE_NAME,
new String[]{Favorites.APPWIDGET_ID},
"appWidgetId=?", new String[]{oldWidgetId}, null, null, null)) {
if (!cursor.moveToFirst()) {
// The widget no long exists.
Log.d(TAG, "Deleting widgetId: " + newWidgetIds[i] + " with old id: "
+ oldWidgetId);
host.deleteAppWidgetId(newWidgetIds[i]);
}
}
}
}
LauncherAppState app = LauncherAppState.getInstanceNoCreate();
if (app != null) {
app.getModel().forceReload();
}
}
}