Catching TransactionTooLargeException when binding widget.
A widget can potentially bypass binder size limit with remote views when
using partual updates (as the merging happens on the system service). In
such a case, show the widget in error state.
Bug: 32365088
Change-Id: Id1c4425958a06463273731464e31f05908c35ec7
diff --git a/src/com/android/launcher3/LauncherAppWidgetHost.java b/src/com/android/launcher3/LauncherAppWidgetHost.java
index d3e5350..657b024 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHost.java
@@ -20,10 +20,8 @@
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
-import android.os.DeadObjectException;
-import android.os.TransactionTooLargeException;
+import android.util.SparseArray;
import android.view.LayoutInflater;
-import android.view.View;
import java.util.ArrayList;
@@ -36,6 +34,7 @@
public class LauncherAppWidgetHost extends AppWidgetHost {
private final ArrayList<Runnable> mProviderChangeListeners = new ArrayList<Runnable>();
+ private final SparseArray<LauncherAppWidgetHostView> mViews = new SparseArray<>();
private Launcher mLauncher;
@@ -45,9 +44,11 @@
}
@Override
- protected AppWidgetHostView onCreateView(Context context, int appWidgetId,
+ protected LauncherAppWidgetHostView onCreateView(Context context, int appWidgetId,
AppWidgetProviderInfo appWidget) {
- return new LauncherAppWidgetHostView(context);
+ LauncherAppWidgetHostView view = new LauncherAppWidgetHostView(context);
+ mViews.put(appWidgetId, view);
+ return view;
}
@Override
@@ -55,15 +56,13 @@
try {
super.startListening();
} catch (Exception e) {
- if (e.getCause() instanceof TransactionTooLargeException ||
- e.getCause() instanceof DeadObjectException) {
- // We're willing to let this slide. The exception is being caused by the list of
- // RemoteViews which is being passed back. The startListening relationship will
- // have been established by this point, and we will end up populating the
- // widgets upon bind anyway. See issue 14255011 for more context.
- } else {
+ if (!Utilities.isBinderSizeError(e)) {
throw new RuntimeException(e);
}
+ // We're willing to let this slide. The exception is being caused by the list of
+ // RemoteViews which is being passed back. The startListening relationship will
+ // have been established by this point, and we will end up populating the
+ // widgets upon bind anyway. See issue 14255011 for more context.
}
}
@@ -98,7 +97,24 @@
lahv.updateLastInflationOrientation();
return lahv;
} else {
- return super.createView(context, appWidgetId, appWidget);
+ try {
+ return super.createView(context, appWidgetId, appWidget);
+ } catch (Exception e) {
+ if (!Utilities.isBinderSizeError(e)) {
+ throw new RuntimeException(e);
+ }
+
+ // If the exception was thrown while fetching the remote views, let the view stay.
+ // This will ensure that if the widget posts a valid update later, the view
+ // will update.
+ LauncherAppWidgetHostView view = mViews.get(appWidgetId);
+ if (view == null) {
+ view = onCreateView(mLauncher, appWidgetId, appWidget);
+ }
+ view.setAppWidget(appWidgetId, appWidget);
+ view.switchToErrorView();
+ return view;
+ }
}
}
@@ -114,4 +130,16 @@
// launcher spans accordingly.
info.initSpans();
}
+
+ @Override
+ public void deleteAppWidgetId(int appWidgetId) {
+ super.deleteAppWidgetId(appWidgetId);
+ mViews.remove(appWidgetId);
+ }
+
+ @Override
+ protected void clearViews() {
+ super.clearViews();
+ mViews.clear();
+ }
}