Adding app widget restore support in Launcher3 for android L

When the app is restored, it displays placeholders for all pending widgets.
These placeholders can be moved and removed similar to a widget (size is fixed
to what defined in backup). Once the system notifies the launcher of the new
widget ids, the place holders are replaced with actual widgets.

issue: 10779035

Change-Id: I68cbe4da01e9ca2978cb4471a7c645d2aa592055
This commit is contained in:
Sunny Goyal
2014-06-30 14:15:31 -07:00
parent 82cc3fe6c7
commit 651077bdd6
12 changed files with 326 additions and 39 deletions
+53 -11
View File
@@ -30,6 +30,8 @@ import android.app.WallpaperManager;
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
@@ -47,6 +49,7 @@ import android.net.Uri;
import android.os.AsyncTask;
import android.os.IBinder;
import android.os.Parcelable;
import android.provider.BaseColumns;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.util.Log;
@@ -61,15 +64,16 @@ import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.TextView;
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.FolderIcon.FolderRingAnimator;
import com.android.launcher3.Launcher.CustomContentCallbacks;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.compat.UserHandleCompat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* The workspace is a wide area with a wallpaper and a finite number of pages.
@@ -4574,7 +4578,7 @@ public class Workspace extends SmoothPagedView
public Folder getFolderForTag(final Object tag) {
final Folder[] value = new Folder[1];
mapOverShortcuts(MAP_NO_RECURSE, new ShortcutOperator() {
mapOverItems(MAP_NO_RECURSE, new ItemOperator() {
@Override
public boolean evaluate(ItemInfo info, View v, View parent) {
if (v instanceof Folder) {
@@ -4592,7 +4596,7 @@ public class Workspace extends SmoothPagedView
public View getViewForTag(final Object tag) {
final View[] value = new View[1];
mapOverShortcuts(MAP_NO_RECURSE, new ShortcutOperator() {
mapOverItems(MAP_NO_RECURSE, new ItemOperator() {
@Override
public boolean evaluate(ItemInfo info, View v, View parent) {
if (v.getTag() == tag) {
@@ -4606,7 +4610,7 @@ public class Workspace extends SmoothPagedView
}
void clearDropTargets() {
mapOverShortcuts(MAP_NO_RECURSE, new ShortcutOperator() {
mapOverItems(MAP_NO_RECURSE, new ItemOperator() {
@Override
public boolean evaluate(ItemInfo info, View v, View parent) {
if (v instanceof DropTarget) {
@@ -4760,9 +4764,9 @@ public class Workspace extends SmoothPagedView
}
}
interface ShortcutOperator {
interface ItemOperator {
/**
* Process the next shortcut, possibly with side-effect on {@link ShortcutOperator#value}.
* Process the next itemInfo, possibly with side-effect on {@link ItemOperator#value}.
*
* @param info info for the shortcut
* @param view view for the shortcut
@@ -4773,12 +4777,12 @@ public class Workspace extends SmoothPagedView
}
/**
* Map the operator over the shortcuts, return the first-non-null value.
* Map the operator over the shortcuts and widgets, return the first-non-null value.
*
* @param recurse true: iterate over folder children. false: op get the folders themselves.
* @param op the operator to map over the shortcuts
*/
void mapOverShortcuts(boolean recurse, ShortcutOperator op) {
void mapOverItems(boolean recurse, ItemOperator op) {
ArrayList<ShortcutAndWidgetContainer> containers = getAllShortcutAndWidgetContainers();
final int containerCount = containers.size();
for (int containerIdx = 0; containerIdx < containerCount; containerIdx++) {
@@ -4809,14 +4813,16 @@ public class Workspace extends SmoothPagedView
}
}
void updateShortcuts(ArrayList<AppInfo> apps) {
void updateShortcutsAndWidgets(ArrayList<AppInfo> apps) {
// Create a map of the apps to test against
final HashMap<ComponentName, AppInfo> appsMap = new HashMap<ComponentName, AppInfo>();
final HashSet<String> pkgNames = new HashSet<>();
for (AppInfo ai : apps) {
appsMap.put(ai.componentName, ai);
pkgNames.add(ai.componentName.getPackageName());
}
mapOverShortcuts(MAP_RECURSE, new ShortcutOperator() {
mapOverItems(MAP_RECURSE, new ItemOperator() {
@Override
public boolean evaluate(ItemInfo info, View v, View parent) {
if (info instanceof ShortcutInfo) {
@@ -4829,6 +4835,8 @@ public class Workspace extends SmoothPagedView
return false;
}
});
restorePendingWidgets(pkgNames);
}
public void removeAbandonedPromise(BubbleTextView abandonedIcon, UserHandleCompat user) {
@@ -4844,7 +4852,7 @@ public class Workspace extends SmoothPagedView
}
public void updatePackageState(final String pkgName, final int state) {
mapOverShortcuts(MAP_RECURSE, new ShortcutOperator() {
mapOverItems(MAP_RECURSE, new ItemOperator() {
@Override
public boolean evaluate(ItemInfo info, View v, View parent) {
if (info instanceof ShortcutInfo
@@ -4857,6 +4865,40 @@ public class Workspace extends SmoothPagedView
return false;
}
});
if (state == ShortcutInfo.PACKAGE_STATE_DEFAULT) {
// Update any pending widget
HashSet<String> packages = new HashSet<>();
packages.add(pkgName);
restorePendingWidgets(packages);
}
}
private void restorePendingWidgets(final Set<String> installedPackaged) {
final ContentResolver contentResolver = getContext().getContentResolver();
// Iterate non recursively as widgets can't be inside a folder.
mapOverItems(MAP_NO_RECURSE, new ItemOperator() {
@Override
public boolean evaluate(ItemInfo info, View v, View parent) {
if (info instanceof LauncherAppWidgetInfo) {
LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) info;
if (widgetInfo.restoreStatus == LauncherAppWidgetInfo.RESTORE_PROVIDER_PENDING
&& installedPackaged.contains(widgetInfo.providerName.getPackageName())) {
// Package installed. Update pending widgets.
ContentValues values = new ContentValues();
values.put(LauncherSettings.Favorites.RESTORED,
LauncherAppWidgetInfo.RESTORE_COMPLETED);
String where = BaseColumns._ID + "= ?";
String[] args = {Long.toString(widgetInfo.id)};
contentResolver.update(LauncherSettings.Favorites.CONTENT_URI,
values, where, args);
}
}
// process all the widget
return false;
}
});
}
private void moveToScreen(int page, boolean animate) {