summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt1
-rw-r--r--core/java/android/appwidget/AppWidgetHost.java11
-rw-r--r--core/java/android/appwidget/AppWidgetProviderInfo.java22
-rw-r--r--core/java/android/widget/RemoteViews.java28
-rw-r--r--services/java/com/android/server/AppWidgetServiceImpl.java40
5 files changed, 77 insertions, 25 deletions
diff --git a/api/current.txt b/api/current.txt
index a123620..fa0bc72 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4476,6 +4476,7 @@ package android.appwidget {
public class AppWidgetProviderInfo implements android.os.Parcelable {
ctor public AppWidgetProviderInfo();
ctor public AppWidgetProviderInfo(android.os.Parcel);
+ method public android.appwidget.AppWidgetProviderInfo clone();
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
index 185fb5a..cb61a71 100644
--- a/core/java/android/appwidget/AppWidgetHost.java
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -21,6 +21,7 @@ import java.util.HashMap;
import android.app.ActivityThread;
import android.content.Context;
+import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -57,6 +58,9 @@ public class AppWidgetHost {
class Callbacks extends IAppWidgetHost.Stub {
public void updateAppWidget(int appWidgetId, RemoteViews views) {
+ if (isLocalBinder() && views != null) {
+ views = views.clone();
+ }
Message msg = mHandler.obtainMessage(HANDLE_UPDATE);
msg.arg1 = appWidgetId;
msg.obj = views;
@@ -64,6 +68,9 @@ public class AppWidgetHost {
}
public void providerChanged(int appWidgetId, AppWidgetProviderInfo info) {
+ if (isLocalBinder() && info != null) {
+ info = info.clone();
+ }
Message msg = mHandler.obtainMessage(HANDLE_PROVIDER_CHANGED);
msg.arg1 = appWidgetId;
msg.obj = info;
@@ -225,6 +232,10 @@ public class AppWidgetHost {
throw new SecurityException("Disallowed call for uid " + uid);
}
+ private boolean isLocalBinder() {
+ return Process.myPid() == Binder.getCallingPid();
+ }
+
/**
* Stop listening to changes for this AppWidget.
*/
diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java
index 5ef3d39..5074480 100644
--- a/core/java/android/appwidget/AppWidgetProviderInfo.java
+++ b/core/java/android/appwidget/AppWidgetProviderInfo.java
@@ -281,6 +281,28 @@ public class AppWidgetProviderInfo implements Parcelable {
out.writeInt(this.widgetFeatures);
}
+ @Override
+ public AppWidgetProviderInfo clone() {
+ AppWidgetProviderInfo that = new AppWidgetProviderInfo();
+ that.provider = this.provider == null ? null : this.provider.clone();
+ that.minWidth = this.minWidth;
+ that.minHeight = this.minHeight;
+ that.minResizeWidth = this.minResizeHeight;
+ that.minResizeHeight = this.minResizeHeight;
+ that.updatePeriodMillis = this.updatePeriodMillis;
+ that.initialLayout = that.initialLayout;
+ that.initialKeyguardLayout = this.initialKeyguardLayout;
+ that.configure = this.configure == null ? null : this.configure.clone();
+ that.label = this.label == null ? null : this.label.substring(0);
+ that.icon = this.icon;
+ that.previewImage = this.previewImage;
+ that.autoAdvanceViewId = this.autoAdvanceViewId;
+ that.resizeMode = this.resizeMode;
+ that.widgetCategory = this.widgetCategory;
+ that.widgetFeatures = this.widgetFeatures;
+ return that;
+ }
+
public int describeContents() {
return 0;
}
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 4b5dfb8..a822400 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -237,12 +237,11 @@ public class RemoteViews implements Parcelable, Filter {
* @hide
*/
public void mergeRemoteViews(RemoteViews newRv) {
+ if (newRv == null) return;
// We first copy the new RemoteViews, as the process of merging modifies the way the actions
// reference the bitmap cache. We don't want to modify the object as it may need to
// be merged and applied multiple times.
- Parcel p = Parcel.obtain();
- newRv.writeToParcel(p, 0);
- RemoteViews copy = new RemoteViews(p);
+ RemoteViews copy = newRv.clone();
HashMap<String, Action> map = new HashMap<String, Action>();
if (mActions == null) {
@@ -261,7 +260,7 @@ public class RemoteViews implements Parcelable, Filter {
for (int i = 0; i < count; i++) {
Action a = newActions.get(i);
String key = newActions.get(i).getUniqueKey();
- int mergeBehavior = map.get(key).mergeBehavior();
+ int mergeBehavior = newActions.get(i).mergeBehavior();
if (map.containsKey(key) && mergeBehavior == Action.MERGE_REPLACE) {
mActions.remove(map.get(key));
map.remove(key);
@@ -1579,23 +1578,12 @@ public class RemoteViews implements Parcelable, Filter {
recalculateMemoryUsage();
}
- @Override
- public RemoteViews clone() {
- RemoteViews that;
- if (!hasLandscapeAndPortraitLayouts()) {
- that = new RemoteViews(mPackage, mLayoutId);
- if (mActions != null) {
- that.mActions = (ArrayList<Action>)mActions.clone();
- }
- } else {
- RemoteViews land = mLandscape.clone();
- RemoteViews port = mPortrait.clone();
- that = new RemoteViews(land, port);
- }
- // update the memory usage stats of the cloned RemoteViews
- that.recalculateMemoryUsage();
- return that;
+ public RemoteViews clone() {
+ Parcel p = Parcel.obtain();
+ writeToParcel(p, 0);
+ p.setDataPosition(0);
+ return new RemoteViews(p);
}
public String getPackage() {
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java
index 8ec67c4..e77f8cf 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/java/com/android/server/AppWidgetServiceImpl.java
@@ -534,6 +534,7 @@ class AppWidgetServiceImpl {
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mAppWidgetIds) {
+ options = cloneIfLocalBinder(options);
ensureStateLoadedLocked();
AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
if (id == null) {
@@ -817,7 +818,7 @@ class AppWidgetServiceImpl {
ensureStateLoadedLocked();
AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
if (id != null && id.provider != null && !id.provider.zombie) {
- return id.provider.info;
+ return cloneIfLocalBinder(id.provider.info);
}
return null;
}
@@ -828,7 +829,7 @@ class AppWidgetServiceImpl {
ensureStateLoadedLocked();
AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
if (id != null) {
- return id.views;
+ return cloneIfLocalBinder(id.views);
}
return null;
}
@@ -842,7 +843,7 @@ class AppWidgetServiceImpl {
for (int i = 0; i < N; i++) {
Provider p = mInstalledProviders.get(i);
if (!p.zombie) {
- result.add(p.info);
+ result.add(cloneIfLocalBinder(p.info));
}
}
return result;
@@ -881,6 +882,7 @@ class AppWidgetServiceImpl {
public void updateAppWidgetOptions(int appWidgetId, Bundle options) {
synchronized (mAppWidgetIds) {
+ options = cloneIfLocalBinder(options);
ensureStateLoadedLocked();
AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
@@ -907,7 +909,7 @@ class AppWidgetServiceImpl {
ensureStateLoadedLocked();
AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
if (id != null && id.options != null) {
- return id.options;
+ return cloneIfLocalBinder(id.options);
} else {
return Bundle.EMPTY;
}
@@ -1062,6 +1064,34 @@ class AppWidgetServiceImpl {
}
}
+ private boolean isLocalBinder() {
+ return Process.myPid() == Binder.getCallingPid();
+ }
+
+ private RemoteViews cloneIfLocalBinder(RemoteViews rv) {
+ if (isLocalBinder() && rv != null) {
+ return rv.clone();
+ }
+ return rv;
+ }
+
+ private AppWidgetProviderInfo cloneIfLocalBinder(AppWidgetProviderInfo info) {
+ if (isLocalBinder() && info != null) {
+ return info.clone();
+ }
+ return info;
+ }
+
+ private Bundle cloneIfLocalBinder(Bundle bundle) {
+ // Note: this is only a shallow copy. For now this will be fine, but it could be problematic
+ // if we start adding objects to the options. Further, it would only be an issue if keyguard
+ // used such options.
+ if (isLocalBinder() && bundle != null) {
+ return (Bundle) bundle.clone();
+ }
+ return bundle;
+ }
+
public int[] startListening(IAppWidgetHost callbacks, String packageName, int hostId,
List<RemoteViews> updatedViews) {
int callingUid = enforceCallingUid(packageName);
@@ -1078,7 +1108,7 @@ class AppWidgetServiceImpl {
for (int i = 0; i < N; i++) {
AppWidgetId id = instances.get(i);
updatedIds[i] = id.appWidgetId;
- updatedViews.add(id.views);
+ updatedViews.add(cloneIfLocalBinder(id.views));
}
return updatedIds;
}