Merge "Catching RemoteViews#apply() layout inflation exceptions in RemoteViewsAdapter"
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index 4c47d37..867ebb4 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -53,6 +53,10 @@
// This ensures that we don't stay continually bound to the service and that it can be destroyed
// if we need the memory elsewhere in the system.
private static final int sUnbindServiceDelay = 5000;
+
+ // Default height for the default loading view, in case we cannot get inflate the first view
+ private static final int sDefaultLoadingViewHeight = 50;
+
// Type defs for controlling different messages across the main and worker message queues
private static final int sDefaultMessageType = 0;
private static final int sUnbindServiceMessageType = 1;
@@ -386,21 +390,39 @@
// Create a new loading view
synchronized (mCache) {
+ boolean customLoadingViewAvailable = false;
+
if (mUserLoadingView != null) {
- // A user-specified loading view
- View loadingView = mUserLoadingView.apply(parent.getContext(), parent);
- loadingView.setTagInternal(com.android.internal.R.id.rowTypeId, new Integer(0));
- layout.addView(loadingView);
- } else {
+ // Try to inflate user-specified loading view
+ try {
+ View loadingView = mUserLoadingView.apply(parent.getContext(), parent);
+ loadingView.setTagInternal(com.android.internal.R.id.rowTypeId,
+ new Integer(0));
+ layout.addView(loadingView);
+ customLoadingViewAvailable = true;
+ } catch (Exception e) {
+ Log.w(TAG, "Error inflating custom loading view, using default loading" +
+ "view instead", e);
+ }
+ }
+ if (!customLoadingViewAvailable) {
// A default loading view
// Use the size of the first row as a guide for the size of the loading view
if (mFirstViewHeight < 0) {
- View firstView = mFirstView.apply(parent.getContext(), parent);
- firstView.measure(
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
- mFirstViewHeight = firstView.getMeasuredHeight();
- mFirstView = null;
+ try {
+ View firstView = mFirstView.apply(parent.getContext(), parent);
+ firstView.measure(
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+ mFirstViewHeight = firstView.getMeasuredHeight();
+ mFirstView = null;
+ } catch (Exception e) {
+ float density = mContext.getResources().getDisplayMetrics().density;
+ mFirstViewHeight = (int)
+ Math.round(sDefaultLoadingViewHeight * density);
+ mFirstView = null;
+ Log.w(TAG, "Error inflating first RemoteViews" + e);
+ }
}
// Compose the loading view text
@@ -937,24 +959,40 @@
indexMetaData.isRequested = true;
int typeId = indexMetaData.typeId;
- // Reuse the convert view where possible
- if (layout != null) {
- if (convertViewTypeId == typeId) {
- rv.reapply(context, convertViewChild);
- return layout;
+ try {
+ // Reuse the convert view where possible
+ if (layout != null) {
+ if (convertViewTypeId == typeId) {
+ rv.reapply(context, convertViewChild);
+ return layout;
+ }
+ layout.removeAllViews();
+ } else {
+ layout = new RemoteViewsFrameLayout(context);
}
- layout.removeAllViews();
- } else {
- layout = new RemoteViewsFrameLayout(context);
+
+ // Otherwise, create a new view to be returned
+ View newView = rv.apply(context, parent);
+ newView.setTagInternal(com.android.internal.R.id.rowTypeId,
+ new Integer(typeId));
+ layout.addView(newView);
+ return layout;
+
+ } catch (Exception e){
+ // We have to make sure that we successfully inflated the RemoteViews, if not
+ // we return the loading view instead.
+ Log.w(TAG, "Error inflating RemoteViews at position: " + position + ", using" +
+ "loading view instead" + e);
+
+ RemoteViewsFrameLayout loadingView = null;
+ final RemoteViewsMetaData metaData = mCache.getMetaData();
+ synchronized (metaData) {
+ loadingView = metaData.createLoadingView(position, convertView, parent);
+ }
+ return loadingView;
+ } finally {
+ if (hasNewItems) loadNextIndexInBackground();
}
-
- // Otherwise, create a new view to be returned
- View newView = rv.apply(context, parent);
- newView.setTagInternal(com.android.internal.R.id.rowTypeId, new Integer(typeId));
- layout.addView(newView);
- if (hasNewItems) loadNextIndexInBackground();
-
- return layout;
} else {
// If the cache does not have the RemoteViews at this position, then create a
// loading view and queue the actual position to be loaded in the background