Adding support to restore widgets even for jelly beans.

> Show 'widget-not-ready' until the widget app is installed
> Once the app is installed, bind a new widget id (not required on L if
  id-remap was received).
  **Remove the widget if bind failed
> If the widget has no configuration screen, show the widget, otherwise
  show 'setup-widget'.
> Clicking 'setup-widget' shows the config screen, and updates the
  widget on RESULT_OK.

issue: 10779035

Change-Id: I2f8b06d09dd6acbc498cdd93edc59c26e5ce17af
This commit is contained in:
Sunny Goyal 2014-07-23 13:58:07 -07:00
parent 6075170b83
commit ff57227711
11 changed files with 338 additions and 111 deletions

View File

@ -193,9 +193,12 @@ s -->
<!-- Text to show user in place of a gadget when we can't display it properly -->
<string name="gadget_error_text">Problem loading widget</string>
<!-- Text to show user in place of a gadget when it is not yet ready/initialized. -->
<!-- Text to show user in place of a gadget when it is not yet ready. -->
<string name="gadget_pending_text" translatable="false">Widget not ready</string>
<!-- Text to show user in place of a gadget when it is not yet initialized. -->
<string name="gadget_setup_text" translatable="false">Setup widget</string>
<!-- Text to inform the user that they can't uninstall a system application -->
<string name="uninstall_system_app_text">This is a system app and can\'t be uninstalled.</string>

View File

@ -46,17 +46,21 @@ public class AppWidgetsRestoredReceiver extends BroadcastReceiver {
Log.i(TAG, "Widget state restore id " + oldWidgetIds[i] + " => " + newWidgetIds[i]);
final AppWidgetProviderInfo provider = widgets.getAppWidgetInfo(newWidgetIds[i]);
final int state;
if (LauncherModel.isValidProvider(provider)) {
state = LauncherAppWidgetInfo.RESTORE_COMPLETED;
} else {
state = LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;
}
ContentValues values = new ContentValues();
values.put(LauncherSettings.Favorites.APPWIDGET_ID, newWidgetIds[i]);
values.put(LauncherSettings.Favorites.RESTORED, LauncherModel.isValidProvider(provider)
? LauncherAppWidgetInfo.RESTORE_COMPLETED
: LauncherAppWidgetInfo.RESTORE_PROVIDER_PENDING);
values.put(LauncherSettings.Favorites.RESTORED, state);
String[] widgetIdParams = new String[] { Integer.toString(oldWidgetIds[i]) };
int result = cr.update(Favorites.CONTENT_URI, values,
"appWidgetId=? and restored=1", widgetIdParams);
"appWidgetId=? and (restored & 1) = 1", widgetIdParams);
if (result == 0) {
Cursor cursor = cr.query(Favorites.CONTENT_URI,
new String[] {Favorites.APPWIDGET_ID},

View File

@ -148,6 +148,8 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
LauncherTransitionable {
static final String TAG = "AppsCustomizePagedView";
private static Rect sTmpRect = new Rect();
/**
* The different content types that this paged view can show.
*/
@ -223,8 +225,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
private ArrayList<Runnable> mDeferredPrepareLoadWidgetPreviewsTasks =
new ArrayList<Runnable>();
private Rect mTmpRect = new Rect();
WidgetPreviewLoader mWidgetPreviewLoader;
private boolean mInBulkBind;
@ -540,26 +540,26 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
mLauncher.getWorkspace().beginDragShared(v, this);
}
Bundle getDefaultOptionsForWidget(Launcher launcher, PendingAddWidgetInfo info) {
static Bundle getDefaultOptionsForWidget(Launcher launcher, PendingAddWidgetInfo info) {
Bundle options = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
AppWidgetResizeFrame.getWidgetSizeRanges(mLauncher, info.spanX, info.spanY, mTmpRect);
Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(mLauncher,
AppWidgetResizeFrame.getWidgetSizeRanges(launcher, info.spanX, info.spanY, sTmpRect);
Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(launcher,
info.componentName, null);
float density = getResources().getDisplayMetrics().density;
float density = launcher.getResources().getDisplayMetrics().density;
int xPaddingDips = (int) ((padding.left + padding.right) / density);
int yPaddingDips = (int) ((padding.top + padding.bottom) / density);
options = new Bundle();
options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH,
mTmpRect.left - xPaddingDips);
sTmpRect.left - xPaddingDips);
options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT,
mTmpRect.top - yPaddingDips);
sTmpRect.top - yPaddingDips);
options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH,
mTmpRect.right - xPaddingDips);
sTmpRect.right - xPaddingDips);
options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT,
mTmpRect.bottom - yPaddingDips);
sTmpRect.bottom - yPaddingDips);
}
return options;
}

View File

@ -124,6 +124,12 @@ public class ItemInfo {
}
ItemInfo(ItemInfo info) {
copyFrom(info);
// tempdebug:
LauncherModel.checkItemInfo(this);
}
public void copyFrom(ItemInfo info) {
id = info.id;
cellX = info.cellX;
cellY = info.cellY;
@ -134,8 +140,6 @@ public class ItemInfo {
container = info.container;
user = info.user;
contentDescription = info.contentDescription;
// tempdebug:
LauncherModel.checkItemInfo(this);
}
public Intent getIntent() {

View File

@ -65,7 +65,6 @@ import android.os.Handler;
import android.os.Message;
import android.os.StrictMode;
import android.os.SystemClock;
import android.provider.Settings;
import android.speech.RecognizerIntent;
import android.text.Selection;
import android.text.SpannableStringBuilder;
@ -153,6 +152,7 @@ public class Launcher extends Activity
private static final int REQUEST_PICK_WALLPAPER = 10;
private static final int REQUEST_BIND_APPWIDGET = 11;
private static final int REQUEST_RECONFIGURE_APPWIDGET = 12;
/**
* IntentStarter uses request codes starting with this. This must be greater than all activity
@ -752,6 +752,9 @@ public class Launcher extends Activity
case REQUEST_CREATE_APPWIDGET:
completeAddAppWidget(args.appWidgetId, args.container, screenId, null, null);
break;
case REQUEST_RECONFIGURE_APPWIDGET:
completeRestoreAppWidget(args.appWidgetId);
break;
}
// Before adding this resetAddInfo(), after a shortcut was added to a workspace screen,
// if you turned the screen off and then back while in All Apps, Launcher would not
@ -854,6 +857,21 @@ public class Launcher extends Activity
return;
}
if (requestCode == REQUEST_RECONFIGURE_APPWIDGET) {
if (resultCode == RESULT_OK) {
// Update the widget view.
PendingAddArguments args = preparePendingAddArgs(requestCode, data,
pendingAddWidgetId, mPendingAddInfo);
if (workspaceLocked) {
sPendingAddItem = args;
} else {
completeAdd(args);
}
}
// Leave the widget in the pending state if the user canceled the configure.
return;
}
// The pattern used here is that a user PICKs a specific application,
// which, depending on the target, might need to CREATE the actual target.
@ -2446,6 +2464,10 @@ public class Launcher extends Activity
}
} else if (v == mAllAppsButton) {
onClickAllAppsButton(v);
} else if (tag instanceof LauncherAppWidgetInfo) {
if (v instanceof PendingAppWidgetHostView) {
onClickPendingWidget((PendingAppWidgetHostView) v);
}
}
}
@ -2453,6 +2475,27 @@ public class Launcher extends Activity
return false;
}
/**
* Event handler for the app widget view which has not fully restored.
*/
public void onClickPendingWidget(PendingAppWidgetHostView v) {
if (v.isReadyForClickSetup()) {
LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) v.getTag();
int widgetId = info.appWidgetId;
AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(widgetId);
if (appWidgetInfo != null) {
mPendingAddWidgetInfo = appWidgetInfo;
mPendingAddInfo.copyFrom(info);
mPendingAddWidgetId = widgetId;
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
intent.setComponent(appWidgetInfo.configure);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, info.appWidgetId);
Utilities.startActivityForResultSafely(this, intent, REQUEST_RECONFIGURE_APPWIDGET);
}
}
}
/**
* Event handler for the search button
*
@ -4398,7 +4441,64 @@ public class Launcher extends Activity
}
final Workspace workspace = mWorkspace;
final AppWidgetProviderInfo appWidgetInfo;
AppWidgetProviderInfo appWidgetInfo;
if (((item.restoreStatus & LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) == 0) &&
((item.restoreStatus & LauncherAppWidgetInfo.FLAG_ID_NOT_VALID) != 0)) {
appWidgetInfo = mModel.findAppWidgetProviderInfoWithComponent(this, item.providerName);
if (appWidgetInfo == null) {
if (DEBUG_WIDGETS) {
Log.d(TAG, "Removing restored widget: id=" + item.appWidgetId
+ " belongs to component " + item.providerName
+ ", as the povider is null");
}
LauncherModel.deleteItemFromDatabase(this, item);
return;
}
// Note: This assumes that the id remap broadcast is received before this step.
// If that is not the case, the id remap will be ignored and user may see the
// click to setup view.
PendingAddWidgetInfo pendingInfo = new PendingAddWidgetInfo(appWidgetInfo, null, null);
pendingInfo.spanX = item.spanX;
pendingInfo.spanY = item.spanY;
pendingInfo.minSpanX = item.minSpanX;
pendingInfo.minSpanY = item.minSpanY;
Bundle options =
AppsCustomizePagedView.getDefaultOptionsForWidget(this, pendingInfo);
boolean success = false;
int newWidgetId = mAppWidgetHost.allocateAppWidgetId();
if (options != null) {
success = mAppWidgetManager.bindAppWidgetIdIfAllowed(newWidgetId,
appWidgetInfo.provider, options);
} else {
success = mAppWidgetManager.bindAppWidgetIdIfAllowed(newWidgetId,
appWidgetInfo.provider);
}
// TODO consider showing a permission dialog when the widget is clicked.
if (!success) {
mAppWidgetHost.deleteAppWidgetId(newWidgetId);
if (DEBUG_WIDGETS) {
Log.d(TAG, "Removing restored widget: id=" + item.appWidgetId
+ " belongs to component " + item.providerName
+ ", as the launcher is unable to bing a new widget id");
}
LauncherModel.deleteItemFromDatabase(this, item);
return;
}
item.appWidgetId = newWidgetId;
// If the widget has a configure activity, it is still needs to set it up, otherwise
// the widget is ready to go.
item.restoreStatus = (appWidgetInfo.configure == null)
? LauncherAppWidgetInfo.RESTORE_COMPLETED
: LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
LauncherModel.updateItemInDatabase(this, item);
}
if (item.restoreStatus == LauncherAppWidgetInfo.RESTORE_COMPLETED) {
final int appWidgetId = item.appWidgetId;
appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
@ -4409,8 +4509,9 @@ public class Launcher extends Activity
item.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
} else {
appWidgetInfo = null;
item.hostView = new LauncherAppWidgetHostView(this, false);
item.hostView = new PendingAppWidgetHostView(this, item.restoreStatus);
item.hostView.updateAppWidget(null);
item.hostView.setOnClickListener(this);
}
item.hostView.setTag(item);
@ -4428,6 +4529,29 @@ public class Launcher extends Activity
}
}
/**
* Restores a pending widget.
*
* @param appWidgetId The app widget id
* @param cellInfo The position on screen where to create the widget.
*/
private void completeRestoreAppWidget(final int appWidgetId) {
LauncherAppWidgetHostView view = mWorkspace.getWidgetForAppWidgetId(appWidgetId);
if ((view == null) || !(view instanceof PendingAppWidgetHostView)) {
Log.e(TAG, "Widget update called, when the widget no longer exists.");
return;
}
PendingAppWidgetHostView pendingView = (PendingAppWidgetHostView) view;
pendingView.setStatus(LauncherAppWidgetInfo.RESTORE_COMPLETED);
LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) pendingView.getTag();
info.restoreStatus = LauncherAppWidgetInfo.RESTORE_COMPLETED;
mWorkspace.reinflateWidgetsIfNecessary();
LauncherModel.updateItemInDatabase(this, info);
}
public void onPageBoundSynchronously(int page) {
mSynchronouslyBoundPages.add(page);
}

View File

@ -18,7 +18,6 @@ package com.android.launcher3;
import android.appwidget.AppWidgetHostView;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
@ -32,36 +31,22 @@ import com.android.launcher3.DragLayer.TouchCompleteListener;
* {@inheritDoc}
*/
public class LauncherAppWidgetHostView extends AppWidgetHostView implements TouchCompleteListener {
LayoutInflater mInflater;
private CheckLongPressHelper mLongPressHelper;
private LayoutInflater mInflater;
private Context mContext;
private int mPreviousOrientation;
private DragLayer mDragLayer;
private float mSlop;
private boolean mWidgetReady;
public LauncherAppWidgetHostView(Context context) {
this(context, true);
}
public LauncherAppWidgetHostView(Context context, boolean widgetReady) {
super(context);
mContext = context;
mLongPressHelper = new CheckLongPressHelper(this);
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mDragLayer = ((Launcher) context).getDragLayer();
mWidgetReady = widgetReady;
}
@Override
public void updateAppWidgetSize(Bundle newOptions, int minWidth, int minHeight, int maxWidth,
int maxHeight) {
// If the widget is not yet ready, the app widget size cannot be updated.
if (mWidgetReady) {
super.updateAppWidgetSize(newOptions, minWidth, minHeight, maxWidth, maxHeight);
}
}
@Override
@ -69,15 +54,6 @@ public class LauncherAppWidgetHostView extends AppWidgetHostView implements Touc
return mInflater.inflate(R.layout.appwidget_error, this, false);
}
@Override
protected View getDefaultView() {
if (mWidgetReady) {
return super.getDefaultView();
} else {
return mInflater.inflate(R.layout.appwidget_not_ready, this, false);
}
}
@Override
public void updateAppWidget(RemoteViews remoteViews) {
// Store the orientation in which the widget was inflated
@ -85,7 +61,8 @@ public class LauncherAppWidgetHostView extends AppWidgetHostView implements Touc
super.updateAppWidget(remoteViews);
}
public boolean orientationChangedSincedInflation() {
public boolean isReinflateRequired() {
// Re-inflate is required if the orientation has changed since last inflated.
int orientation = mContext.getResources().getConfiguration().orientation;
if (mPreviousOrientation != orientation) {
return true;

View File

@ -33,12 +33,17 @@ public class LauncherAppWidgetInfo extends ItemInfo {
/**
* This is set during the package backup creation.
*/
public static final int RESTORE_REMAP_PENDING = 1;
public static final int FLAG_ID_NOT_VALID = 1;
/**
* Widget provider is not yet installed.
* Indicates that the provider is not available yet.
*/
public static final int RESTORE_PROVIDER_PENDING = 2;
public static final int FLAG_PROVIDER_NOT_READY = 2;
/**
* Indicates that the widget UI is not yet ready, and user needs to set it up again.
*/
public static final int FLAG_UI_NOT_READY = 4;
/**
* Indicates that the widget hasn't been instantiated yet.
@ -89,6 +94,7 @@ public class LauncherAppWidgetInfo extends ItemInfo {
super.onAddToDatabase(context, values);
values.put(LauncherSettings.Favorites.APPWIDGET_ID, appWidgetId);
values.put(LauncherSettings.Favorites.APPWIDGET_PROVIDER, providerName.flattenToString());
values.put(LauncherSettings.Favorites.RESTORED, restoreStatus);
}
/**
@ -121,6 +127,10 @@ public class LauncherAppWidgetInfo extends ItemInfo {
}
public final boolean isWidgetIdValid() {
return restoreStatus != RESTORE_REMAP_PENDING;
return (restoreStatus & FLAG_ID_NOT_VALID) == 0;
}
public final boolean hasRestoreFlag(int flag) {
return (restoreStatus & flag) == flag;
}
}

View File

@ -874,20 +874,25 @@ public class LauncherBackupHelper implements BackupHelper {
values.put(Favorites.INTENT, favorite.intent);
}
values.put(Favorites.ITEM_TYPE, favorite.itemType);
if (favorite.itemType == Favorites.ITEM_TYPE_APPWIDGET) {
if (!TextUtils.isEmpty(favorite.appWidgetProvider)) {
values.put(Favorites.APPWIDGET_PROVIDER, favorite.appWidgetProvider);
}
values.put(Favorites.APPWIDGET_ID, favorite.appWidgetId);
}
UserHandleCompat myUserHandle = UserHandleCompat.myUserHandle();
long userSerialNumber =
UserManagerCompat.getInstance(mContext).getSerialNumberForUser(myUserHandle);
values.put(LauncherSettings.Favorites.PROFILE_ID, userSerialNumber);
// Let LauncherModel know we've been here.
values.put(LauncherSettings.Favorites.RESTORED, 1);
if (favorite.itemType == Favorites.ITEM_TYPE_APPWIDGET) {
if (!TextUtils.isEmpty(favorite.appWidgetProvider)) {
values.put(Favorites.APPWIDGET_PROVIDER, favorite.appWidgetProvider);
}
values.put(Favorites.APPWIDGET_ID, favorite.appWidgetId);
values.put(LauncherSettings.Favorites.RESTORED,
LauncherAppWidgetInfo.FLAG_ID_NOT_VALID |
LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY |
LauncherAppWidgetInfo.FLAG_UI_NOT_READY);
} else {
// Let LauncherModel know we've been here.
values.put(LauncherSettings.Favorites.RESTORED, 1);
}
return values;
}

View File

@ -2128,47 +2128,59 @@ public class LauncherModel extends BroadcastReceiver
int appWidgetId = c.getInt(appWidgetIdIndex);
String savedProvider = c.getString(appWidgetProviderIndex);
id = c.getLong(idIndex);
final ComponentName component =
ComponentName.unflattenFromString(savedProvider);
final int restoreStatus = c.getInt(restoredIndex);
final boolean restorePending = Utilities.isLmp()
&& (restoreStatus ==
LauncherAppWidgetInfo.RESTORE_REMAP_PENDING);
final boolean providerPending = Utilities.isLmp()
&& (restoreStatus ==
LauncherAppWidgetInfo.RESTORE_PROVIDER_PENDING);
final boolean isIdValid = (restoreStatus &
LauncherAppWidgetInfo.FLAG_ID_NOT_VALID) == 0;
// Do not try to get the provider if restore is pending, as the
// widget id is invalid, and it might point to some other provider.
final AppWidgetProviderInfo provider = restorePending ? null
: widgets.getAppWidgetInfo(appWidgetId);
boolean providerValid = isValidProvider(provider);
final boolean wasProviderReady = (restoreStatus &
LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) == 0;
// Skip provider check,
// 1. when the widget id re-map is pending
// 2. provider is pending install for a restored widget
if (!isSafeMode && !providerPending && !restorePending
&& !providerValid) {
final AppWidgetProviderInfo provider = isIdValid
? widgets.getAppWidgetInfo(appWidgetId)
: findAppWidgetProviderInfoWithComponent(context, component);
final boolean isProviderReady = isValidProvider(provider);
if (!isSafeMode && wasProviderReady && !isProviderReady) {
String log = "Deleting widget that isn't installed anymore: "
+ "id=" + id + " appWidgetId=" + appWidgetId;
+ "id=" + id + " appWidgetId=" + appWidgetId;
Log.e(TAG, log);
Launcher.addDumpLog(TAG, log, false);
itemsToRemove.add(id);
} else {
if (providerValid) {
if (isProviderReady) {
appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,
provider.provider);
int[] minSpan =
Launcher.getMinSpanForWidget(context, provider);
appWidgetInfo.minSpanX = minSpan[0];
appWidgetInfo.minSpanY = minSpan[1];
int status = restoreStatus;
if (!wasProviderReady) {
// If provider was not previously ready, update the
// status and UI flag.
// Id would be valid only if the widget restore broadcast was received.
if (isIdValid) {
status = LauncherAppWidgetInfo.RESTORE_COMPLETED;
} else {
status &= ~LauncherAppWidgetInfo
.FLAG_PROVIDER_NOT_READY;
}
}
appWidgetInfo.restoreStatus = status;
} else {
Log.v(TAG, "Widget restore pending id=" + id
+ " appWidgetId=" + appWidgetId
+ " status =" + restoreStatus);
appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,
ComponentName.unflattenFromString(savedProvider));
component);
appWidgetInfo.restoreStatus = restoreStatus;
}
appWidgetInfo.id = id;
appWidgetInfo.screenId = c.getInt(screenIndex);
appWidgetInfo.cellX = c.getInt(cellXIndex);
@ -2195,15 +2207,15 @@ public class LauncherModel extends BroadcastReceiver
break;
}
if (providerValid) {
if (isProviderReady) {
String providerName = provider.provider.flattenToString();
if (!providerName.equals(savedProvider) || providerPending) {
if (!providerName.equals(savedProvider) ||
(appWidgetInfo.restoreStatus != restoreStatus)) {
ContentValues values = new ContentValues();
values.put(LauncherSettings.Favorites.APPWIDGET_PROVIDER,
providerName);
values.put(LauncherSettings.Favorites.RESTORED,
LauncherAppWidgetInfo.RESTORE_COMPLETED);
appWidgetInfo.restoreStatus);
String where = BaseColumns._ID + "= ?";
String[] args = {Long.toString(id)};
contentResolver.update(contentUri, values, where, args);

View File

@ -0,0 +1,78 @@
package com.android.launcher3;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;
public class PendingAppWidgetHostView extends LauncherAppWidgetHostView implements OnClickListener {
int mRestoreStatus;
private TextView mDefaultView;
private OnClickListener mClickListener;
public PendingAppWidgetHostView(Context context, int restoreStatus) {
super(context);
mRestoreStatus = restoreStatus;
}
@Override
public void updateAppWidgetSize(Bundle newOptions, int minWidth, int minHeight, int maxWidth,
int maxHeight) {
// No-op
}
@Override
protected View getDefaultView() {
if (mDefaultView == null) {
mDefaultView = (TextView) mInflater.inflate(R.layout.appwidget_not_ready, this, false);
mDefaultView.setOnClickListener(this);
applyState();
}
return mDefaultView;
}
@Override
public void setOnClickListener(OnClickListener l) {
mClickListener = l;
}
public void setStatus(int status) {
if (mRestoreStatus != status) {
mRestoreStatus = status;
applyState();
}
}
@Override
public boolean isReinflateRequired() {
// Re inflate is required if the the widget is restored.
return mRestoreStatus == LauncherAppWidgetInfo.RESTORE_COMPLETED;
}
private void applyState() {
if (mDefaultView != null) {
if (isReadyForClickSetup()) {
mDefaultView.setText(R.string.gadget_setup_text);
} else {
mDefaultView.setText(R.string.gadget_pending_text);
}
}
}
@Override
public void onClick(View v) {
// AppWidgetHostView blocks all click events on the root view. Instead handle click events
// on the content and pass it along.
if (mClickListener != null) {
mClickListener.onClick(this);
}
}
public boolean isReadyForClickSetup() {
return (mRestoreStatus & LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) == 0
&& (mRestoreStatus & LauncherAppWidgetInfo.FLAG_UI_NOT_READY) != 0;
}
}

View File

@ -30,8 +30,6 @@ 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;
@ -49,7 +47,6 @@ 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;
@ -75,6 +72,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* The workspace is a wide area with a wallpaper and a finite number of pages.
@ -1119,10 +1117,10 @@ public class Workspace extends SmoothPagedView
for (int j = 0; j < itemCount; j++) {
View v = swc.getChildAt(j);
if (v.getTag() instanceof LauncherAppWidgetInfo) {
if (v != null && v.getTag() instanceof LauncherAppWidgetInfo) {
LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) v.getTag();
LauncherAppWidgetHostView lahv = (LauncherAppWidgetHostView) info.hostView;
if (lahv != null && lahv.orientationChangedSincedInflation()) {
if (lahv != null && lahv.isReinflateRequired()) {
mLauncher.removeAppWidget(info);
// Remove the current widget which is inflated with the wrong orientation
cl.removeView(lahv);
@ -3258,7 +3256,6 @@ public class Workspace extends SmoothPagedView
LauncherAppState app = LauncherAppState.getInstance();
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
Resources res = launcher.getResources();
Display display = launcher.getWindowManager().getDefaultDisplay();
Point smallestSize = new Point();
Point largestSize = new Point();
@ -4591,29 +4588,43 @@ public class Workspace extends SmoothPagedView
}
public Folder getFolderForTag(final Object tag) {
final Folder[] value = new Folder[1];
mapOverItems(MAP_NO_RECURSE, new ItemOperator() {
return (Folder) getFirstMatch(new ItemOperator() {
@Override
public boolean evaluate(ItemInfo info, View v, View parent) {
if (v instanceof Folder) {
Folder f = (Folder) v;
if (f.getInfo() == tag && f.getInfo().opened) {
value[0] = f;
return true;
}
}
return false;
return (v instanceof Folder) && (((Folder) v).getInfo() == tag)
&& ((Folder) v).getInfo().opened;
}
});
return value[0];
}
public View getViewForTag(final Object tag) {
return getFirstMatch(new ItemOperator() {
@Override
public boolean evaluate(ItemInfo info, View v, View parent) {
return info == tag;
}
});
}
public LauncherAppWidgetHostView getWidgetForAppWidgetId(final int appWidgetId) {
return (LauncherAppWidgetHostView) getFirstMatch(new ItemOperator() {
@Override
public boolean evaluate(ItemInfo info, View v, View parent) {
return (info instanceof LauncherAppWidgetInfo) &&
((LauncherAppWidgetInfo) info).appWidgetId == appWidgetId;
}
});
}
private View getFirstMatch(final ItemOperator operator) {
final View[] value = new View[1];
mapOverItems(MAP_NO_RECURSE, new ItemOperator() {
@Override
public boolean evaluate(ItemInfo info, View v, View parent) {
if (v.getTag() == tag) {
if (operator.evaluate(info, v, parent)) {
value[0] = v;
return true;
}
@ -4895,7 +4906,7 @@ public class Workspace extends SmoothPagedView
}
private void restorePendingWidgets(final Set<String> installedPackaged) {
final ContentResolver contentResolver = getContext().getContentResolver();
final AtomicBoolean widgetsChanged = new AtomicBoolean(false);
// Iterate non recursively as widgets can't be inside a folder.
mapOverItems(MAP_NO_RECURSE, new ItemOperator() {
@ -4903,22 +4914,21 @@ public class Workspace extends SmoothPagedView
public boolean evaluate(ItemInfo info, View v, View parent) {
if (info instanceof LauncherAppWidgetInfo) {
LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) info;
if (widgetInfo.restoreStatus == LauncherAppWidgetInfo.RESTORE_PROVIDER_PENDING
if (widgetInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)
&& 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);
widgetsChanged.set(true);
}
}
// process all the widget
return false;
}
});
if (widgetsChanged.get()) {
// Reload layout and update widget status
// TODO instead of full reload, just update the specific widgets
getContext().getContentResolver()
.notifyChange(LauncherSettings.Favorites.CONTENT_URI, null);
}
}
private void moveToScreen(int page, boolean animate) {