summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.xml56
-rw-r--r--core/java/android/appwidget/AppWidgetManager.java61
-rw-r--r--core/java/android/widget/AdapterViewFlipper.java35
-rw-r--r--core/java/android/widget/RemoteViews.java78
-rw-r--r--core/java/com/android/internal/appwidget/IAppWidgetService.aidl1
-rw-r--r--services/java/com/android/server/AppWidgetService.java25
6 files changed, 253 insertions, 3 deletions
diff --git a/api/current.xml b/api/current.xml
index 297a7bc..3b262e9 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -36167,6 +36167,36 @@
<parameter name="viewId" type="int">
</parameter>
</method>
+<method name="partiallyUpdateAppWidget"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="appWidgetIds" type="int[]">
+</parameter>
+<parameter name="views" type="android.widget.RemoteViews">
+</parameter>
+</method>
+<method name="partiallyUpdateAppWidget"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="appWidgetId" type="int">
+</parameter>
+<parameter name="views" type="android.widget.RemoteViews">
+</parameter>
+</method>
<method name="updateAppWidget"
return="void"
abstract="false"
@@ -228211,6 +228241,32 @@
<parameter name="visibility" type="int">
</parameter>
</method>
+<method name="showNext"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="viewId" type="int">
+</parameter>
+</method>
+<method name="showPrevious"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="viewId" type="int">
+</parameter>
+</method>
<method name="writeToParcel"
return="void"
abstract="false"
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 5ee721f..b83642b 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -233,6 +233,10 @@ public class AppWidgetManager {
/**
* Set the RemoteViews to use for the specified appWidgetIds.
*
+ * Note that the RemoteViews parameter will be cached by the AppWidgetService, and hence should
+ * contain a complete representation of the widget. For performing partial widget updates, see
+ * {@link #partiallyUpdateAppWidget(int[], RemoteViews)}.
+ *
* <p>
* It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
* and outside of the handler.
@@ -253,6 +257,10 @@ public class AppWidgetManager {
/**
* Set the RemoteViews to use for the specified appWidgetId.
*
+ * Note that the RemoteViews parameter will be cached by the AppWidgetService, and hence should
+ * contain a complete representation of the widget. For performing partial widget updates, see
+ * {@link #partiallyUpdateAppWidget(int, RemoteViews)}.
+ *
* <p>
* It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
* and outside of the handler.
@@ -266,6 +274,59 @@ public class AppWidgetManager {
}
/**
+ * Perform an incremental update or command on the widget(s) specified by appWidgetIds.
+ *
+ * This update differs from {@link #updateAppWidget(int[], RemoteViews)} in that the
+ * RemoteViews object which is passed is understood to be an incomplete representation of the
+ * widget, and hence is not cached by the AppWidgetService. Note that because these updates are
+ * not cached, any state that they modify that is not restored by restoreInstanceState will not
+ * persist in the case that the widgets are restored using the cached version in
+ * AppWidgetService.
+ *
+ * Use with {@link RemoteViews#showNext(int)}, {@link RemoteViews#showPrevious(int)},
+ * {@link RemoteViews#setScrollPosition(int, int)} and similar commands.
+ *
+ * <p>
+ * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
+ * and outside of the handler.
+ * This method will only work when called from the uid that owns the AppWidget provider.
+ *
+ * @param appWidgetIds The AppWidget instances for which to set the RemoteViews.
+ * @param views The RemoteViews object containing the incremental update / command.
+ */
+ public void partiallyUpdateAppWidget(int[] appWidgetIds, RemoteViews views) {
+ try {
+ sService.partiallyUpdateAppWidgetIds(appWidgetIds, views);
+ } catch (RemoteException e) {
+ throw new RuntimeException("system server dead?", e);
+ }
+ }
+
+ /**
+ * Perform an incremental update or command on the widget specified by appWidgetId.
+ *
+ * This update differs from {@link #updateAppWidget(int, RemoteViews)} in that the RemoteViews
+ * object which is passed is understood to be an incomplete representation of the widget, and
+ * hence is not cached by the AppWidgetService. Note that because these updates are not cached,
+ * any state that they modify that is not restored by restoreInstanceState will not persist in
+ * the case that the widgets are restored using the cached version in AppWidgetService.
+ *
+ * Use with {@link RemoteViews#showNext(int)}, {@link RemoteViews#showPrevious(int)},
+ * {@link RemoteViews#setScrollPosition(int, int)} and similar commands.
+ *
+ * <p>
+ * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
+ * and outside of the handler.
+ * This method will only work when called from the uid that owns the AppWidget provider.
+ *
+ * @param appWidgetId The AppWidget instance for which to set the RemoteViews.
+ * @param views The RemoteViews object containing the incremental update / command.
+ */
+ public void partiallyUpdateAppWidget(int appWidgetId, RemoteViews views) {
+ partiallyUpdateAppWidget(new int[] { appWidgetId }, views);
+ }
+
+ /**
* Set the RemoteViews to use for all AppWidget instances for the supplied AppWidget provider.
*
* <p>
diff --git a/core/java/android/widget/AdapterViewFlipper.java b/core/java/android/widget/AdapterViewFlipper.java
index 901c761..205c0ba 100644
--- a/core/java/android/widget/AdapterViewFlipper.java
+++ b/core/java/android/widget/AdapterViewFlipper.java
@@ -25,6 +25,7 @@ import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.RemotableViewMethod;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.widget.RemoteViews.RemoteView;
@@ -137,6 +138,38 @@ public class AdapterViewFlipper extends AdapterViewAnimator {
}
/**
+ * {@inheritDoc}
+ */
+ @Override
+ @RemotableViewMethod
+ public void showNext() {
+ // if the flipper is currently flipping automatically, and showNext() is called
+ // we should we should make sure to reset the timer
+ if (mRunning) {
+ mHandler.removeMessages(FLIP_MSG);
+ Message msg = mHandler.obtainMessage(FLIP_MSG);
+ mHandler.sendMessageDelayed(msg, mFlipInterval);
+ }
+ super.showNext();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ @RemotableViewMethod
+ public void showPrevious() {
+ // if the flipper is currently flipping automatically, and showPrevious() is called
+ // we should we should make sure to reset the timer
+ if (mRunning) {
+ mHandler.removeMessages(FLIP_MSG);
+ Message msg = mHandler.obtainMessage(FLIP_MSG);
+ mHandler.sendMessageDelayed(msg, mFlipInterval);
+ }
+ super.showPrevious();
+ }
+
+ /**
* How long to wait before flipping to the next view
*
* @param milliseconds
@@ -229,8 +262,6 @@ public class AdapterViewFlipper extends AdapterViewAnimator {
if (msg.what == FLIP_MSG) {
if (mRunning) {
showNext();
- msg = obtainMessage(FLIP_MSG);
- sendMessageDelayed(msg, mFlipInterval);
}
}
}
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 50745dc0..f23a723 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -266,6 +266,63 @@ public class RemoteViews implements Parcelable, Filter {
public final static int TAG = 3;
}
+ private class ReflectionActionWithoutParams extends Action {
+ int viewId;
+ String methodName;
+
+ public final static int TAG = 5;
+
+ ReflectionActionWithoutParams(int viewId, String methodName) {
+ this.viewId = viewId;
+ this.methodName = methodName;
+ }
+
+ ReflectionActionWithoutParams(Parcel in) {
+ this.viewId = in.readInt();
+ this.methodName = in.readString();
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(TAG);
+ out.writeInt(this.viewId);
+ out.writeString(this.methodName);
+ }
+
+ @Override
+ public void apply(View root) {
+ final View view = root.findViewById(viewId);
+ if (view == null) {
+ throw new ActionException("can't find view: 0x" + Integer.toHexString(viewId));
+ }
+
+ Class klass = view.getClass();
+ Method method;
+ try {
+ method = klass.getMethod(this.methodName);
+ } catch (NoSuchMethodException ex) {
+ throw new ActionException("view: " + klass.getName() + " doesn't have method: "
+ + this.methodName + "()");
+ }
+
+ if (!method.isAnnotationPresent(RemotableViewMethod.class)) {
+ throw new ActionException("view: " + klass.getName()
+ + " can't use method with RemoteViews: "
+ + this.methodName + "()");
+ }
+
+ try {
+ //noinspection ConstantIfStatement
+ if (false) {
+ Log.d("RemoteViews", "view: " + klass.getName() + " calling method: "
+ + this.methodName + "()");
+ }
+ method.invoke(view);
+ } catch (Exception ex) {
+ throw new ActionException(ex);
+ }
+ }
+ }
+
/**
* Base class for the reflection actions.
*/
@@ -571,6 +628,9 @@ public class RemoteViews implements Parcelable, Filter {
case ViewGroupAction.TAG:
mActions.add(new ViewGroupAction(parcel));
break;
+ case ReflectionActionWithoutParams.TAG:
+ mActions.add(new ReflectionActionWithoutParams(parcel));
+ break;
default:
throw new ActionException("Tag " + tag + " not found");
}
@@ -632,6 +692,24 @@ public class RemoteViews implements Parcelable, Filter {
}
/**
+ * Equivalent to calling {@link AdapterViewFlipper#showNext()}
+ *
+ * @param viewId The id of the view on which to call {@link AdapterViewFlipper#showNext()}
+ */
+ public void showNext(int viewId) {
+ addAction(new ReflectionActionWithoutParams(viewId, "showNext"));
+ }
+
+ /**
+ * Equivalent to calling {@link AdapterViewFlipper#showPrevious()}
+ *
+ * @param viewId The id of the view on which to call {@link AdapterViewFlipper#showPrevious()}
+ */
+ public void showPrevious(int viewId) {
+ addAction(new ReflectionActionWithoutParams(viewId, "showPrevious"));
+ }
+
+ /**
* Equivalent to calling View.setVisibility
*
* @param viewId The id of the view whose visibility should change
diff --git a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
index af75d5b..8da51b1 100644
--- a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
+++ b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
@@ -40,6 +40,7 @@ interface IAppWidgetService {
// for AppWidgetManager
//
void updateAppWidgetIds(in int[] appWidgetIds, in RemoteViews views);
+ void partiallyUpdateAppWidgetIds(in int[] appWidgetIds, in RemoteViews views);
void updateAppWidgetProvider(in ComponentName provider, in RemoteViews views);
void notifyAppWidgetViewDataChanged(in int[] appWidgetIds, in RemoteViews views, int viewId);
List<AppWidgetProviderInfo> getInstalledProviders();
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 3059732..b8b8880 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -425,6 +425,23 @@ class AppWidgetService extends IAppWidgetService.Stub
}
}
+ public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views) {
+ if (appWidgetIds == null) {
+ return;
+ }
+ if (appWidgetIds.length == 0) {
+ return;
+ }
+ final int N = appWidgetIds.length;
+
+ synchronized (mAppWidgetIds) {
+ for (int i=0; i<N; i++) {
+ AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]);
+ updateAppWidgetInstanceLocked(id, views, true);
+ }
+ }
+ }
+
public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, RemoteViews views, int viewId) {
if (appWidgetIds == null) {
return;
@@ -459,11 +476,17 @@ class AppWidgetService extends IAppWidgetService.Stub
}
void updateAppWidgetInstanceLocked(AppWidgetId id, RemoteViews views) {
+ updateAppWidgetInstanceLocked(id, views, false);
+ }
+
+ void updateAppWidgetInstanceLocked(AppWidgetId id, RemoteViews views, boolean isPartialUpdate) {
// allow for stale appWidgetIds and other badness
// lookup also checks that the calling process can access the appWidgetId
// drop unbound appWidgetIds (shouldn't be possible under normal circumstances)
if (id != null && id.provider != null && !id.provider.zombie && !id.host.zombie) {
- id.views = views;
+
+ // We do not want to save this RemoteViews
+ if (!isPartialUpdate) id.views = views;
// is anyone listening?
if (id.host.callbacks != null) {