Loading core/java/android/appwidget/AppWidgetHostView.java +8 −1 Original line number Diff line number Diff line Loading @@ -376,7 +376,13 @@ public class AppWidgetHostView extends FrameLayout { * AppWidget provider. Will animate into these new views as needed */ public void updateAppWidget(RemoteViews remoteViews) { applyRemoteViews(remoteViews); } /** * @hide */ protected void applyRemoteViews(RemoteViews remoteViews) { if (LOGD) Log.d(TAG, "updateAppWidget called mOld=" + mOld); boolean recycled = false; Loading Loading @@ -573,8 +579,9 @@ public class AppWidgetHostView extends FrameLayout { /** * Build a {@link Context} cloned into another package name, usually for the * purposes of reading remote resources. * @hide */ private Context getRemoteContext() { protected Context getRemoteContext() { try { // Return if cloned successfully, otherwise default return mContext.createApplicationContext( Loading core/java/android/widget/RemoteViewsAdapter.java +62 −143 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import java.util.HashSet; import java.util.LinkedList; import android.Manifest; import android.appwidget.AppWidgetHostView; import android.appwidget.AppWidgetManager; import android.content.Context; import android.content.Intent; Loading Loading @@ -78,7 +79,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback private RemoteViewsAdapterServiceConnection mServiceConnection; private WeakReference<RemoteAdapterConnectionCallback> mCallback; private OnClickHandler mRemoteViewsOnClickHandler; private FixedSizeRemoteViewsCache mCache; private final FixedSizeRemoteViewsCache mCache; private int mVisibleWindowLowerBound; private int mVisibleWindowUpperBound; Loading Loading @@ -287,9 +288,12 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback * A FrameLayout which contains a loading view, and manages the re/applying of RemoteViews when * they are loaded. */ private static class RemoteViewsFrameLayout extends FrameLayout { public RemoteViewsFrameLayout(Context context) { private static class RemoteViewsFrameLayout extends AppWidgetHostView { private final FixedSizeRemoteViewsCache mCache; public RemoteViewsFrameLayout(Context context, FixedSizeRemoteViewsCache cache) { super(context); mCache = cache; } /** Loading @@ -298,13 +302,24 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback * successfully. */ public void onRemoteViewsLoaded(RemoteViews view, OnClickHandler handler) { try { // Remove all the children of this layout first removeAllViews(); addView(view.apply(getContext(), this, handler)); } catch (Exception e) { Log.e(TAG, "Failed to apply RemoteViews."); setOnClickHandler(handler); applyRemoteViews(view); } @Override protected View getDefaultView() { return mCache.getMetaData().createDefaultLoadingView(this); } @Override protected Context getRemoteContext() { return null; } @Override protected View getErrorView() { // Use the default loading view as the error view. return getDefaultView(); } } Loading Loading @@ -444,63 +459,33 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback return (mappedType < viewTypeCount); } private RemoteViewsFrameLayout createLoadingView(int position, View convertView, ViewGroup parent, Object lock, LayoutInflater layoutInflater, OnClickHandler handler) { // Create and return a new FrameLayout, and setup the references for this position /** * Creates a default loading view. Uses the size of the first row as a guide for the * size of the loading view. */ private synchronized View createDefaultLoadingView(ViewGroup parent) { final Context context = parent.getContext(); RemoteViewsFrameLayout layout = new RemoteViewsFrameLayout(context); // Create a new loading view synchronized (lock) { boolean customLoadingViewAvailable = false; if (mUserLoadingView != null) { // Try to inflate user-specified loading view try { View loadingView = mUserLoadingView.apply(parent.getContext(), parent, handler); 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) { try { View firstView = mFirstView.apply(parent.getContext(), parent, handler); 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 = context.getResources().getDisplayMetrics().density; mFirstViewHeight = (int) Math.round(sDefaultLoadingViewHeight * density); mFirstView = null; mFirstViewHeight = Math.round(sDefaultLoadingViewHeight * density); Log.w(TAG, "Error inflating first RemoteViews" + e); } mFirstView = null; } // Compose the loading view text TextView loadingTextView = (TextView) layoutInflater.inflate( TextView loadingTextView = (TextView) LayoutInflater.from(context).inflate( com.android.internal.R.layout.remote_views_adapter_default_loading_view, layout, false); parent, false); loadingTextView.setHeight(mFirstViewHeight); loadingTextView.setTag(new Integer(0)); layout.addView(loadingTextView); } } return layout; return loadingTextView; } } Loading Loading @@ -1085,21 +1070,6 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback } } /** * Returns the item type id for the specified convert view. Returns -1 if the convert view * is invalid. */ private int getConvertViewTypeId(View convertView) { int typeId = -1; if (convertView != null) { Object tag = convertView.getTag(com.android.internal.R.id.rowTypeId); if (tag != null) { typeId = (Integer) tag; } } return typeId; } /** * This method allows an AdapterView using this Adapter to provide information about which * views are currently being displayed. This allows for certain optimizations and preloading Loading @@ -1114,7 +1084,8 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback // "Request" an index so that we can queue it for loading, initiate subsequent // preloading, etc. synchronized (mCache) { boolean isInCache = mCache.containsRemoteViewAt(position); RemoteViews rv = mCache.getRemoteViewsAt(position); boolean isInCache = (rv != null); boolean isConnected = mServiceConnection.isConnected(); boolean hasNewItems = false; Loading @@ -1131,75 +1102,23 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback hasNewItems = mCache.queuePositionsToBePreloadedFromRequestedPosition(position); } final RemoteViewsFrameLayout layout = (convertView instanceof RemoteViewsFrameLayout) ? (RemoteViewsFrameLayout) convertView : new RemoteViewsFrameLayout(parent.getContext(), mCache); if (isInCache) { View convertViewChild = null; int convertViewTypeId = 0; RemoteViewsFrameLayout layout = null; if (convertView instanceof RemoteViewsFrameLayout) { layout = (RemoteViewsFrameLayout) convertView; convertViewChild = layout.getChildAt(0); convertViewTypeId = getConvertViewTypeId(convertViewChild); } // Second, we try and retrieve the RemoteViews from the cache, returning a loading // view and queueing it to be loaded if it has not already been loaded. Context context = parent.getContext(); RemoteViews rv = mCache.getRemoteViewsAt(position); RemoteViewsIndexMetaData indexMetaData = mCache.getMetaDataAt(position); int typeId = indexMetaData.typeId; try { // Reuse the convert view where possible if (layout != null) { if (convertViewTypeId == typeId) { rv.reapply(context, convertViewChild, mRemoteViewsOnClickHandler); return layout; } layout.removeAllViews(); } else { layout = new RemoteViewsFrameLayout(context); } // Otherwise, create a new view to be returned View newView = rv.apply(context, parent, mRemoteViewsOnClickHandler); 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, mCache, mLayoutInflater, mRemoteViewsOnClickHandler); } return loadingView; } finally { layout.onRemoteViewsLoaded(rv, mRemoteViewsOnClickHandler); if (hasNewItems) loadNextIndexInBackground(); } } 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 RemoteViewsFrameLayout loadingView = null; final RemoteViewsMetaData metaData = mCache.getMetaData(); synchronized (metaData) { loadingView = metaData.createLoadingView(position, convertView, parent, mCache, mLayoutInflater, mRemoteViewsOnClickHandler); } mRequestedViews.add(position, loadingView); // If the views is not loaded, apply the loading view. If the loading view doesn't // exist, the layout will create a default view based on the firstView height. layout.onRemoteViewsLoaded(mCache.getMetaData().mUserLoadingView, mRemoteViewsOnClickHandler); mRequestedViews.add(position, layout); mCache.queueRequestedPositionToLoad(position); loadNextIndexInBackground(); return loadingView; } return layout; } } Loading Loading
core/java/android/appwidget/AppWidgetHostView.java +8 −1 Original line number Diff line number Diff line Loading @@ -376,7 +376,13 @@ public class AppWidgetHostView extends FrameLayout { * AppWidget provider. Will animate into these new views as needed */ public void updateAppWidget(RemoteViews remoteViews) { applyRemoteViews(remoteViews); } /** * @hide */ protected void applyRemoteViews(RemoteViews remoteViews) { if (LOGD) Log.d(TAG, "updateAppWidget called mOld=" + mOld); boolean recycled = false; Loading Loading @@ -573,8 +579,9 @@ public class AppWidgetHostView extends FrameLayout { /** * Build a {@link Context} cloned into another package name, usually for the * purposes of reading remote resources. * @hide */ private Context getRemoteContext() { protected Context getRemoteContext() { try { // Return if cloned successfully, otherwise default return mContext.createApplicationContext( Loading
core/java/android/widget/RemoteViewsAdapter.java +62 −143 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import java.util.HashSet; import java.util.LinkedList; import android.Manifest; import android.appwidget.AppWidgetHostView; import android.appwidget.AppWidgetManager; import android.content.Context; import android.content.Intent; Loading Loading @@ -78,7 +79,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback private RemoteViewsAdapterServiceConnection mServiceConnection; private WeakReference<RemoteAdapterConnectionCallback> mCallback; private OnClickHandler mRemoteViewsOnClickHandler; private FixedSizeRemoteViewsCache mCache; private final FixedSizeRemoteViewsCache mCache; private int mVisibleWindowLowerBound; private int mVisibleWindowUpperBound; Loading Loading @@ -287,9 +288,12 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback * A FrameLayout which contains a loading view, and manages the re/applying of RemoteViews when * they are loaded. */ private static class RemoteViewsFrameLayout extends FrameLayout { public RemoteViewsFrameLayout(Context context) { private static class RemoteViewsFrameLayout extends AppWidgetHostView { private final FixedSizeRemoteViewsCache mCache; public RemoteViewsFrameLayout(Context context, FixedSizeRemoteViewsCache cache) { super(context); mCache = cache; } /** Loading @@ -298,13 +302,24 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback * successfully. */ public void onRemoteViewsLoaded(RemoteViews view, OnClickHandler handler) { try { // Remove all the children of this layout first removeAllViews(); addView(view.apply(getContext(), this, handler)); } catch (Exception e) { Log.e(TAG, "Failed to apply RemoteViews."); setOnClickHandler(handler); applyRemoteViews(view); } @Override protected View getDefaultView() { return mCache.getMetaData().createDefaultLoadingView(this); } @Override protected Context getRemoteContext() { return null; } @Override protected View getErrorView() { // Use the default loading view as the error view. return getDefaultView(); } } Loading Loading @@ -444,63 +459,33 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback return (mappedType < viewTypeCount); } private RemoteViewsFrameLayout createLoadingView(int position, View convertView, ViewGroup parent, Object lock, LayoutInflater layoutInflater, OnClickHandler handler) { // Create and return a new FrameLayout, and setup the references for this position /** * Creates a default loading view. Uses the size of the first row as a guide for the * size of the loading view. */ private synchronized View createDefaultLoadingView(ViewGroup parent) { final Context context = parent.getContext(); RemoteViewsFrameLayout layout = new RemoteViewsFrameLayout(context); // Create a new loading view synchronized (lock) { boolean customLoadingViewAvailable = false; if (mUserLoadingView != null) { // Try to inflate user-specified loading view try { View loadingView = mUserLoadingView.apply(parent.getContext(), parent, handler); 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) { try { View firstView = mFirstView.apply(parent.getContext(), parent, handler); 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 = context.getResources().getDisplayMetrics().density; mFirstViewHeight = (int) Math.round(sDefaultLoadingViewHeight * density); mFirstView = null; mFirstViewHeight = Math.round(sDefaultLoadingViewHeight * density); Log.w(TAG, "Error inflating first RemoteViews" + e); } mFirstView = null; } // Compose the loading view text TextView loadingTextView = (TextView) layoutInflater.inflate( TextView loadingTextView = (TextView) LayoutInflater.from(context).inflate( com.android.internal.R.layout.remote_views_adapter_default_loading_view, layout, false); parent, false); loadingTextView.setHeight(mFirstViewHeight); loadingTextView.setTag(new Integer(0)); layout.addView(loadingTextView); } } return layout; return loadingTextView; } } Loading Loading @@ -1085,21 +1070,6 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback } } /** * Returns the item type id for the specified convert view. Returns -1 if the convert view * is invalid. */ private int getConvertViewTypeId(View convertView) { int typeId = -1; if (convertView != null) { Object tag = convertView.getTag(com.android.internal.R.id.rowTypeId); if (tag != null) { typeId = (Integer) tag; } } return typeId; } /** * This method allows an AdapterView using this Adapter to provide information about which * views are currently being displayed. This allows for certain optimizations and preloading Loading @@ -1114,7 +1084,8 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback // "Request" an index so that we can queue it for loading, initiate subsequent // preloading, etc. synchronized (mCache) { boolean isInCache = mCache.containsRemoteViewAt(position); RemoteViews rv = mCache.getRemoteViewsAt(position); boolean isInCache = (rv != null); boolean isConnected = mServiceConnection.isConnected(); boolean hasNewItems = false; Loading @@ -1131,75 +1102,23 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback hasNewItems = mCache.queuePositionsToBePreloadedFromRequestedPosition(position); } final RemoteViewsFrameLayout layout = (convertView instanceof RemoteViewsFrameLayout) ? (RemoteViewsFrameLayout) convertView : new RemoteViewsFrameLayout(parent.getContext(), mCache); if (isInCache) { View convertViewChild = null; int convertViewTypeId = 0; RemoteViewsFrameLayout layout = null; if (convertView instanceof RemoteViewsFrameLayout) { layout = (RemoteViewsFrameLayout) convertView; convertViewChild = layout.getChildAt(0); convertViewTypeId = getConvertViewTypeId(convertViewChild); } // Second, we try and retrieve the RemoteViews from the cache, returning a loading // view and queueing it to be loaded if it has not already been loaded. Context context = parent.getContext(); RemoteViews rv = mCache.getRemoteViewsAt(position); RemoteViewsIndexMetaData indexMetaData = mCache.getMetaDataAt(position); int typeId = indexMetaData.typeId; try { // Reuse the convert view where possible if (layout != null) { if (convertViewTypeId == typeId) { rv.reapply(context, convertViewChild, mRemoteViewsOnClickHandler); return layout; } layout.removeAllViews(); } else { layout = new RemoteViewsFrameLayout(context); } // Otherwise, create a new view to be returned View newView = rv.apply(context, parent, mRemoteViewsOnClickHandler); 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, mCache, mLayoutInflater, mRemoteViewsOnClickHandler); } return loadingView; } finally { layout.onRemoteViewsLoaded(rv, mRemoteViewsOnClickHandler); if (hasNewItems) loadNextIndexInBackground(); } } 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 RemoteViewsFrameLayout loadingView = null; final RemoteViewsMetaData metaData = mCache.getMetaData(); synchronized (metaData) { loadingView = metaData.createLoadingView(position, convertView, parent, mCache, mLayoutInflater, mRemoteViewsOnClickHandler); } mRequestedViews.add(position, loadingView); // If the views is not loaded, apply the loading view. If the loading view doesn't // exist, the layout will create a default view based on the firstView height. layout.onRemoteViewsLoaded(mCache.getMetaData().mUserLoadingView, mRemoteViewsOnClickHandler); mRequestedViews.add(position, layout); mCache.queueRequestedPositionToLoad(position); loadNextIndexInBackground(); return loadingView; } return layout; } } Loading