FileDocCategorySizeDatePackage
AppWidgetHostView.javaAPI DocAndroid 1.5 API10890Wed May 06 22:41:54 BST 2009android.appwidget

AppWidgetHostView

public class AppWidgetHostView extends android.widget.FrameLayout
Provides the glue to show AppWidget views. This class offers automatic animation between updates, and will try recycling old views for each incoming {@link RemoteViews}.

Fields Summary
static final String
TAG
static final boolean
LOGD
static final boolean
CROSSFADE
static final int
VIEW_MODE_NOINIT
static final int
VIEW_MODE_CONTENT
static final int
VIEW_MODE_ERROR
static final int
VIEW_MODE_DEFAULT
static final int
FADE_DURATION
static final LayoutInflater.Filter
sInflaterFilter
android.content.Context
mContext
int
mAppWidgetId
AppWidgetProviderInfo
mInfo
android.view.View
mView
int
mViewMode
int
mLayoutId
long
mFadeStartTime
android.graphics.Bitmap
mOld
android.graphics.Paint
mOldPaint
Constructors Summary
public AppWidgetHostView(android.content.Context context)
Create a host view. Uses default fade animations.

    
                  
       
        this(context, android.R.anim.fade_in, android.R.anim.fade_out);
    
public AppWidgetHostView(android.content.Context context, int animationIn, int animationOut)
Create a host view. Uses specified animations when pushing {@link #updateAppWidget(RemoteViews)}.

param
animationIn Resource ID of in animation to use
param
animationOut Resource ID of out animation to use

        super(context);
        mContext = context;
    
Methods Summary
protected booleandrawChild(android.graphics.Canvas canvas, android.view.View child, long drawingTime)

        if (CROSSFADE) {
            int alpha;
            int l = child.getLeft();
            int t = child.getTop();
            if (mFadeStartTime > 0) {
                alpha = (int)(((drawingTime-mFadeStartTime)*255)/FADE_DURATION);
                if (alpha > 255) {
                    alpha = 255;
                }
                Log.d(TAG, "drawChild alpha=" + alpha + " l=" + l + " t=" + t
                        + " w=" + child.getWidth());
                if (alpha != 255 && mOld != null) {
                    mOldPaint.setAlpha(255-alpha);
                    //canvas.drawBitmap(mOld, l, t, mOldPaint);
                }
            } else {
                alpha = 255;
            }
            int restoreTo = canvas.saveLayerAlpha(l, t, child.getWidth(), child.getHeight(), alpha,
                    Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
            boolean rv = super.drawChild(canvas, child, drawingTime);
            canvas.restoreToCount(restoreTo);
            if (alpha < 255) {
                invalidate();
            } else {
                mFadeStartTime = -1;
                if (mOld != null) {
                    mOld.recycle();
                    mOld = null;
                }
            }
            return rv;
        } else {
            return super.drawChild(canvas, child, drawingTime);
        }
    
public intgetAppWidgetId()

        return mAppWidgetId;
    
public AppWidgetProviderInfogetAppWidgetInfo()

        return mInfo;
    
protected android.view.ViewgetDefaultView()
Inflate and return the default layout requested by AppWidget provider.

        View defaultView = null;
        Exception exception = null;
        
        try {
            if (mInfo != null) {
                Context theirContext = mContext.createPackageContext(
                        mInfo.provider.getPackageName(), 0 /* no flags */);
                LayoutInflater inflater = (LayoutInflater)
                        theirContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                inflater = inflater.cloneInContext(theirContext);
                inflater.setFilter(sInflaterFilter);
                defaultView = inflater.inflate(mInfo.initialLayout, this, false);
            } else {
                Log.w(TAG, "can't inflate defaultView because mInfo is missing");
            }
        } catch (PackageManager.NameNotFoundException e) {
            exception = e;
        } catch (RuntimeException e) {
            exception = e;
        }
        
        if (exception != null && LOGD) {
            Log.w(TAG, "Error inflating AppWidget " + mInfo, exception);
        }
        
        if (defaultView == null) {
            if (LOGD) Log.d(TAG, "getDefaultView couldn't find any view, so inflating error");
            defaultView = getErrorView();
        }
        
        return defaultView;
    
protected android.view.ViewgetErrorView()
Inflate and return a view that represents an error state.

        TextView tv = new TextView(mContext);
        tv.setText(com.android.internal.R.string.gadget_host_error_inflating);
        // TODO: get this color from somewhere.
        tv.setBackgroundColor(Color.argb(127, 0, 0, 0));
        return tv;
    
protected voidprepareView(android.view.View view)
Prepare the given view to be shown. This might include adjusting {@link FrameLayout.LayoutParams} before inserting.

        // Take requested dimensions from parent, but apply default gravity.
        ViewGroup.LayoutParams requested = view.getLayoutParams();
        if (requested == null) {
            requested = new FrameLayout.LayoutParams(LayoutParams.FILL_PARENT,
                    LayoutParams.FILL_PARENT);
        }
        
        FrameLayout.LayoutParams params =
            new FrameLayout.LayoutParams(requested.width, requested.height);
        params.gravity = Gravity.CENTER;
        view.setLayoutParams(params);
    
public voidsetAppWidget(int appWidgetId, AppWidgetProviderInfo info)
Set the AppWidget that will be displayed by this view.

        mAppWidgetId = appWidgetId;
        mInfo = info;
    
public voidupdateAppWidget(android.widget.RemoteViews remoteViews)
Process a set of {@link RemoteViews} coming in as an update from the AppWidget provider. Will animate into these new views as needed.

        if (LOGD) Log.d(TAG, "updateAppWidget called mOld=" + mOld);
        
        boolean recycled = false;
        View content = null;
        Exception exception = null;
        
        // Capture the old view into a bitmap so we can do the crossfade.
        if (CROSSFADE) {
            if (mFadeStartTime < 0) {
                if (mView != null) {
                    final int width = mView.getWidth();
                    final int height = mView.getHeight();
                    try {
                        mOld = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
                    } catch (OutOfMemoryError e) {
                        // we just won't do the fade
                        mOld = null;
                    }
                    if (mOld != null) {
                        //mView.drawIntoBitmap(mOld);
                    }
                }
            }
        }
        
        if (remoteViews == null) {
            if (mViewMode == VIEW_MODE_DEFAULT) {
                // We've already done this -- nothing to do.
                return;
            }
            content = getDefaultView();
            mLayoutId = -1;
            mViewMode = VIEW_MODE_DEFAULT;
        } else {
            int layoutId = remoteViews.getLayoutId();

            // If our stale view has been prepared to match active, and the new
            // layout matches, try recycling it
            if (content == null && layoutId == mLayoutId) {
                try {
                    remoteViews.reapply(mContext, mView);
                    content = mView;
                    recycled = true;
                    if (LOGD) Log.d(TAG, "was able to recycled existing layout");
                } catch (RuntimeException e) {
                    exception = e;
                }
            }
            
            // Try normal RemoteView inflation
            if (content == null) {
                try {
                    content = remoteViews.apply(mContext, this);
                    if (LOGD) Log.d(TAG, "had to inflate new layout");
                } catch (RuntimeException e) {
                    exception = e;
                }
            }

            mLayoutId = layoutId;
            mViewMode = VIEW_MODE_CONTENT;
        }
        
        if (content == null) {
            if (mViewMode == VIEW_MODE_ERROR) {
                // We've already done this -- nothing to do.
                return ;
            }
            Log.w(TAG, "updateAppWidget couldn't find any view, using error view", exception);
            content = getErrorView();
            mViewMode = VIEW_MODE_ERROR;
        }
        
        if (!recycled) {
            prepareView(content);
            addView(content);
        }

        if (mView != content) {
            removeView(mView);
            mView = content;
        }

        if (CROSSFADE) {
            if (mFadeStartTime < 0) {
                // if there is already an animation in progress, don't do anything --
                // the new view will pop in on top of the old one during the cross fade,
                // and that looks okay.
                mFadeStartTime = SystemClock.uptimeMillis();
                invalidate();
            }
        }