summaryrefslogtreecommitdiffstats
path: root/core/java/android/gadget/GadgetHostView.java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/gadget/GadgetHostView.java')
-rw-r--r--core/java/android/gadget/GadgetHostView.java206
1 files changed, 149 insertions, 57 deletions
diff --git a/core/java/android/gadget/GadgetHostView.java b/core/java/android/gadget/GadgetHostView.java
index d92c123..a985bd4 100644
--- a/core/java/android/gadget/GadgetHostView.java
+++ b/core/java/android/gadget/GadgetHostView.java
@@ -18,7 +18,6 @@ package android.gadget;
import android.content.Context;
import android.content.pm.PackageManager;
-import android.gadget.GadgetInfo;
import android.graphics.Color;
import android.util.Config;
import android.util.Log;
@@ -26,12 +25,18 @@ import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.animation.Animation;
import android.widget.FrameLayout;
import android.widget.RemoteViews;
import android.widget.TextView;
import android.widget.ViewAnimator;
-public class GadgetHostView extends ViewAnimator {
+/**
+ * Provides the glue to show gadget views. This class offers automatic animation
+ * between updates, and will try recycling old views for each incoming
+ * {@link RemoteViews}.
+ */
+public class GadgetHostView extends ViewAnimator implements Animation.AnimationListener {
static final String TAG = "GadgetHostView";
static final boolean LOGD = Config.LOGD || true;
@@ -42,57 +47,93 @@ public class GadgetHostView extends ViewAnimator {
return clazz.isAnnotationPresent(RemoteViews.RemoteView.class);
}
};
-
+
+ Context mLocalContext;
+
int mGadgetId;
- GadgetInfo mInfo;
- View mActiveView;
- View mStaleView;
+ GadgetProviderInfo mInfo;
- protected int mDefaultGravity = Gravity.CENTER;
-
+ View mActiveView = null;
+ View mStaleView = null;
+
+ int mActiveLayoutId = -1;
+ int mStaleLayoutId = -1;
+
+ /**
+ * Last set of {@link RemoteViews} applied to {@link #mActiveView}
+ */
+ RemoteViews mActiveActions = null;
+
+ /**
+ * Flag indicating that {@link #mActiveActions} has been applied to
+ * {@link #mStaleView}, meaning it's readyto recycle.
+ */
+ boolean mStalePrepared = false;
+
+ /**
+ * Create a host view. Uses default fade animations.
+ */
public GadgetHostView(Context context) {
- super(context);
+ this(context, android.R.anim.fade_in, android.R.anim.fade_out);
}
- public void setGadget(int gadgetId, GadgetInfo info) {
- if (LOGD) Log.d(TAG, "setGadget is incoming with info=" + info);
+ /**
+ * Create a host view. Uses specified animations when pushing
+ * {@link #updateGadget(RemoteViews)}.
+ *
+ * @param animationIn Resource ID of in animation to use
+ * @param animationOut Resource ID of out animation to use
+ */
+ public GadgetHostView(Context context, int animationIn, int animationOut) {
+ super(context);
+ mLocalContext = context;
+
+ // Prepare our default transition animations
+ setAnimateFirstView(true);
+ setInAnimation(context, animationIn);
+ setOutAnimation(context, animationOut);
+
+ // Watch for animation events to prepare recycling
+ Animation inAnimation = getInAnimation();
+ if (inAnimation != null) {
+ inAnimation.setAnimationListener(this);
+ }
+ }
+
+ /**
+ * Set the gadget that will be displayed by this view.
+ */
+ public void setGadget(int gadgetId, GadgetProviderInfo info) {
if (mInfo != null) {
// TODO: remove the old view, or whatever
}
mGadgetId = gadgetId;
mInfo = info;
-
- View defaultView = getDefaultView();
- flipUpdate(defaultView);
}
- /**
- * Trigger actual animation between current and new content in the
- * {@link ViewAnimator}.
- */
- protected void flipUpdate(View newContent) {
- if (LOGD) Log.d(TAG, "pushing an update to surface");
-
- // Take requested dimensions from parent, but apply default gravity.
- ViewGroup.LayoutParams requested = newContent.getLayoutParams();
- if (requested == null) {
- requested = new FrameLayout.LayoutParams(LayoutParams.FILL_PARENT,
- LayoutParams.FILL_PARENT);
+ public int getGadgetId() {
+ return mGadgetId;
+ }
+
+ public GadgetProviderInfo getGadgetInfo() {
+ return mInfo;
+ }
+
+ public void onAnimationEnd(Animation animation) {
+ // When our transition animation finishes, we should try bringing our
+ // newly-stale view up to the current view.
+ if (mActiveActions != null &&
+ mStaleLayoutId == mActiveActions.getLayoutId()) {
+ if (LOGD) Log.d(TAG, "after animation, layoutId matched so we're recycling old view");
+ mActiveActions.reapply(mLocalContext, mStaleView);
+ mStalePrepared = true;
}
-
- FrameLayout.LayoutParams params =
- new FrameLayout.LayoutParams(requested.width, requested.height);
- params.gravity = mDefaultGravity;
- newContent.setLayoutParams(params);
-
- // Add new content and animate to it
- addView(newContent);
- showNext();
-
- // Dispose old stale view
- removeView(mStaleView);
- mStaleView = mActiveView;
- mActiveView = newContent;
+ }
+
+ public void onAnimationRepeat(Animation animation) {
+ }
+
+ public void onAnimationStart(Animation animation) {
}
/**
@@ -100,26 +141,42 @@ public class GadgetHostView extends ViewAnimator {
* gadget provider. Will animate into these new views as needed.
*/
public void updateGadget(RemoteViews remoteViews) {
- if (LOGD) Log.d(TAG, "updateGadget() with remoteViews = " + remoteViews);
+ if (LOGD) Log.d(TAG, "updateGadget called");
+ boolean recycled = false;
View newContent = null;
Exception exception = null;
- try {
- if (remoteViews == null) {
- // there is no remoteViews (yet), so use the initial layout
- newContent = getDefaultView();
- } else {
- // use the RemoteViews
- // TODO: try applying RemoteViews to existing staleView if available
- newContent = remoteViews.apply(mContext, this);
+ if (remoteViews == null) {
+ newContent = getDefaultView();
+ }
+
+ // If our stale view has been prepared to match active, and the new
+ // layout matches, try recycling it
+ if (newContent == null && mStalePrepared &&
+ remoteViews.getLayoutId() == mStaleLayoutId) {
+ try {
+ remoteViews.reapply(mLocalContext, mStaleView);
+ newContent = mStaleView;
+ recycled = true;
+ if (LOGD) Log.d(TAG, "was able to recycled existing layout");
+ } catch (RuntimeException e) {
+ exception = e;
+ }
+ }
+
+ // Try normal RemoteView inflation
+ if (newContent == null) {
+ try {
+ newContent = remoteViews.apply(mLocalContext, this);
+ if (LOGD) Log.d(TAG, "had to inflate new layout");
+ } catch (RuntimeException e) {
+ exception = e;
}
- } catch (RuntimeException e) {
- exception = e;
}
if (exception != null && LOGD) {
- Log.w(TAG, "Error inflating gadget " + mInfo, exception);
+ Log.w(TAG, "Error inflating gadget " + getGadgetInfo(), exception);
}
if (newContent == null) {
@@ -128,8 +185,44 @@ public class GadgetHostView extends ViewAnimator {
if (LOGD) Log.d(TAG, "updateGadget couldn't find any view, so inflating error");
newContent = getErrorView();
}
-
- flipUpdate(newContent);
+
+ if (!recycled) {
+ prepareView(newContent);
+ addView(newContent);
+ }
+
+ showNext();
+
+ if (!recycled) {
+ removeView(mStaleView);
+ }
+
+ mStalePrepared = false;
+ mActiveActions = remoteViews;
+
+ mStaleView = mActiveView;
+ mActiveView = newContent;
+
+ mStaleLayoutId = mActiveLayoutId;
+ mActiveLayoutId = (remoteViews == null) ? -1 : remoteViews.getLayoutId();
+ }
+
+ /**
+ * Prepare the given view to be shown. This might include adjusting
+ * {@link FrameLayout.LayoutParams} before inserting.
+ */
+ protected void prepareView(View view) {
+ // 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);
}
/**
@@ -141,7 +234,7 @@ public class GadgetHostView extends ViewAnimator {
try {
if (mInfo != null) {
- Context theirContext = mContext.createPackageContext(
+ Context theirContext = mLocalContext.createPackageContext(
mInfo.provider.getPackageName(), 0 /* no flags */);
LayoutInflater inflater = (LayoutInflater)
theirContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@@ -173,11 +266,10 @@ public class GadgetHostView extends ViewAnimator {
* Inflate and return a view that represents an error state.
*/
protected View getErrorView() {
- TextView tv = new TextView(mContext);
+ TextView tv = new TextView(mLocalContext);
// TODO: move this error string and background color into resources
tv.setText("Error inflating gadget");
tv.setBackgroundColor(Color.argb(127, 0, 0, 0));
return tv;
}
}
-