blob: 9cf27181d3ae1f67664ced66b83e4fef10b71365 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.widget;
18
Adam Cohenca6fd842010-09-03 18:10:35 -070019import java.lang.annotation.ElementType;
20import java.lang.annotation.Retention;
21import java.lang.annotation.RetentionPolicy;
22import java.lang.annotation.Target;
23import java.lang.reflect.Method;
24import java.util.ArrayList;
25
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026import android.app.PendingIntent;
Adam Cohen1480fdd2010-08-25 17:24:53 -070027import android.appwidget.AppWidgetHostView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.content.Context;
Dianne Hackbornfa82f222009-09-17 15:14:12 -070029import android.content.Intent;
30import android.content.IntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.content.pm.PackageManager.NameNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.graphics.Bitmap;
33import android.graphics.PorterDuff;
Joe Onorato75970652009-12-02 23:04:55 -080034import android.graphics.Rect;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035import android.graphics.drawable.Drawable;
36import android.net.Uri;
Bjorn Bringertd755b062010-01-06 17:15:37 +000037import android.os.Bundle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.os.Parcel;
39import android.os.Parcelable;
40import android.text.TextUtils;
41import android.util.Log;
42import android.view.LayoutInflater;
43import android.view.RemotableViewMethod;
44import android.view.View;
45import android.view.ViewGroup;
46import android.view.LayoutInflater.Filter;
47import android.view.View.OnClickListener;
Adam Cohena32edd42010-10-26 10:35:01 -070048import android.widget.AdapterView.OnItemClickListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050
51/**
52 * A class that describes a view hierarchy that can be displayed in
53 * another process. The hierarchy is inflated from a layout resource
54 * file, and this class provides some basic operations for modifying
55 * the content of the inflated hierarchy.
56 */
57public class RemoteViews implements Parcelable, Filter {
58
59 private static final String LOG_TAG = "RemoteViews";
60
61 /**
Winson Chung81f39eb2011-01-11 18:05:01 -080062 * The intent extra that contains the appWidgetId.
63 * @hide
64 */
65 static final String EXTRA_REMOTEADAPTER_APPWIDGET_ID = "remoteAdapterAppWidgetId";
66
67 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068 * The package name of the package containing the layout
69 * resource. (Added to the parcel)
70 */
Gilles Debunne30301932010-06-16 18:32:00 -070071 private final String mPackage;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072
73 /**
74 * The resource ID of the layout file. (Added to the parcel)
75 */
Gilles Debunne30301932010-06-16 18:32:00 -070076 private final int mLayoutId;
Romain Guya5475592009-07-01 17:20:08 -070077
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078 /**
79 * An array of actions to perform on the view tree once it has been
80 * inflated
81 */
82 private ArrayList<Action> mActions;
83
Winson Chung3ec9a452010-09-23 16:40:28 -070084 /**
85 * A class to keep track of memory usage by this RemoteViews
86 */
87 private MemoryUsageCounter mMemoryUsageCounter;
88
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089
90 /**
Adam Cohenca6fd842010-09-03 18:10:35 -070091 * This flag indicates whether this RemoteViews object is being created from a
92 * RemoteViewsService for use as a child of a widget collection. This flag is used
93 * to determine whether or not certain features are available, in particular,
94 * setting on click extras and setting on click pending intents. The former is enabled,
95 * and the latter disabled when this flag is true.
96 */
97 private boolean mIsWidgetCollectionChild = false;
98
99 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100 * This annotation indicates that a subclass of View is alllowed to be used
Romain Guya5475592009-07-01 17:20:08 -0700101 * with the {@link RemoteViews} mechanism.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102 */
103 @Target({ ElementType.TYPE })
104 @Retention(RetentionPolicy.RUNTIME)
105 public @interface RemoteView {
106 }
107
108 /**
109 * Exception to send when something goes wrong executing an action
110 *
111 */
112 public static class ActionException extends RuntimeException {
113 public ActionException(Exception ex) {
114 super(ex);
115 }
116 public ActionException(String message) {
117 super(message);
118 }
119 }
Adam Cohena32edd42010-10-26 10:35:01 -0700120
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121 /**
122 * Base class for all actions that can be performed on an
123 * inflated view.
124 *
Joe Onorato18e69df2010-05-17 22:26:12 -0700125 * SUBCLASSES MUST BE IMMUTABLE SO CLONE WORKS!!!!!
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 */
127 private abstract static class Action implements Parcelable {
Winson Chung037300b2011-03-29 15:40:16 -0700128 public abstract void apply(View root, ViewGroup rootParent) throws ActionException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129
130 public int describeContents() {
131 return 0;
132 }
Winson Chung3ec9a452010-09-23 16:40:28 -0700133
134 /**
135 * Overridden by each class to report on it's own memory usage
136 */
137 public void updateMemoryUsageEstimate(MemoryUsageCounter counter) {
138 // We currently only calculate Bitmap memory usage, so by default, don't do anything
139 // here
140 return;
141 }
Winson Chungae615982010-11-01 12:14:49 -0700142
143 protected boolean startIntentSafely(Context context, PendingIntent pendingIntent,
144 Intent fillInIntent) {
145 try {
146 // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
147 context.startIntentSender(
148 pendingIntent.getIntentSender(), fillInIntent,
149 Intent.FLAG_ACTIVITY_NEW_TASK,
150 Intent.FLAG_ACTIVITY_NEW_TASK, 0);
151 } catch (IntentSender.SendIntentException e) {
152 android.util.Log.e(LOG_TAG, "Cannot send pending intent: ", e);
153 return false;
154 } catch (Exception e) {
155 android.util.Log.e(LOG_TAG, "Cannot send pending intent due to " +
156 "unknown exception: ", e);
157 return false;
158 }
159 return true;
160 }
Romain Guya5475592009-07-01 17:20:08 -0700161 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162
Adam Cohen1480fdd2010-08-25 17:24:53 -0700163 private class SetEmptyView extends Action {
164 int viewId;
165 int emptyViewId;
166
167 public final static int TAG = 6;
168
169 SetEmptyView(int viewId, int emptyViewId) {
170 this.viewId = viewId;
171 this.emptyViewId = emptyViewId;
172 }
173
174 SetEmptyView(Parcel in) {
175 this.viewId = in.readInt();
176 this.emptyViewId = in.readInt();
177 }
178
179 public void writeToParcel(Parcel out, int flags) {
180 out.writeInt(TAG);
181 out.writeInt(this.viewId);
182 out.writeInt(this.emptyViewId);
183 }
184
185 @Override
Winson Chung037300b2011-03-29 15:40:16 -0700186 public void apply(View root, ViewGroup rootParent) {
Adam Cohen1480fdd2010-08-25 17:24:53 -0700187 final View view = root.findViewById(viewId);
188 if (!(view instanceof AdapterView<?>)) return;
189
190 AdapterView<?> adapterView = (AdapterView<?>) view;
191
192 final View emptyView = root.findViewById(emptyViewId);
193 if (emptyView == null) return;
194
195 adapterView.setEmptyView(emptyView);
196 }
197 }
198
Adam Cohen35ae9ca2010-09-20 15:20:41 -0700199 private class SetOnClickFillInIntent extends Action {
200 public SetOnClickFillInIntent(int id, Intent fillInIntent) {
201 this.viewId = id;
202 this.fillInIntent = fillInIntent;
203 }
204
205 public SetOnClickFillInIntent(Parcel parcel) {
206 viewId = parcel.readInt();
207 fillInIntent = Intent.CREATOR.createFromParcel(parcel);
208 }
209
210 public void writeToParcel(Parcel dest, int flags) {
211 dest.writeInt(TAG);
212 dest.writeInt(viewId);
213 fillInIntent.writeToParcel(dest, 0 /* no flags */);
214 }
215
216 @Override
Winson Chung037300b2011-03-29 15:40:16 -0700217 public void apply(View root, ViewGroup rootParent) {
Adam Cohen35ae9ca2010-09-20 15:20:41 -0700218 final View target = root.findViewById(viewId);
Joe Onorato2b69ce42010-10-31 11:35:41 -0700219 if (target == null) return;
Adam Cohen35ae9ca2010-09-20 15:20:41 -0700220
221 if (!mIsWidgetCollectionChild) {
222 Log.e("RemoteViews", "The method setOnClickFillInIntent is available " +
223 "only from RemoteViewsFactory (ie. on collection items).");
224 return;
225 }
Adam Cohena32edd42010-10-26 10:35:01 -0700226 if (target == root) {
227 target.setTagInternal(com.android.internal.R.id.fillInIntent, fillInIntent);
228 } else if (target != null && fillInIntent != null) {
Adam Cohen35ae9ca2010-09-20 15:20:41 -0700229 OnClickListener listener = new OnClickListener() {
230 public void onClick(View v) {
231 // Insure that this view is a child of an AdapterView
232 View parent = (View) v.getParent();
233 while (!(parent instanceof AdapterView<?>)
234 && !(parent instanceof AppWidgetHostView)) {
235 parent = (View) parent.getParent();
236 }
237
238 if (parent instanceof AppWidgetHostView) {
239 // Somehow they've managed to get this far without having
240 // and AdapterView as a parent.
241 Log.e("RemoteViews", "Collection item doesn't have AdapterView parent");
242 return;
243 }
244
245 // Insure that a template pending intent has been set on an ancestor
246 if (!(parent.getTag() instanceof PendingIntent)) {
247 Log.e("RemoteViews", "Attempting setOnClickFillInIntent without" +
Adam Cohena32edd42010-10-26 10:35:01 -0700248 " calling setPendingIntentTemplate on parent.");
Adam Cohen35ae9ca2010-09-20 15:20:41 -0700249 return;
250 }
251
252 PendingIntent pendingIntent = (PendingIntent) parent.getTag();
253
254 final float appScale = v.getContext().getResources()
Adam Cohena32edd42010-10-26 10:35:01 -0700255 .getCompatibilityInfo().applicationScale;
Adam Cohen35ae9ca2010-09-20 15:20:41 -0700256 final int[] pos = new int[2];
257 v.getLocationOnScreen(pos);
258
259 final Rect rect = new Rect();
260 rect.left = (int) (pos[0] * appScale + 0.5f);
261 rect.top = (int) (pos[1] * appScale + 0.5f);
262 rect.right = (int) ((pos[0] + v.getWidth()) * appScale + 0.5f);
263 rect.bottom = (int) ((pos[1] + v.getHeight()) * appScale + 0.5f);
264
265 fillInIntent.setSourceBounds(rect);
Winson Chungae615982010-11-01 12:14:49 -0700266 startIntentSafely(v.getContext(), pendingIntent, fillInIntent);
Adam Cohen35ae9ca2010-09-20 15:20:41 -0700267 }
268
269 };
270 target.setOnClickListener(listener);
271 }
272 }
273
274 int viewId;
275 Intent fillInIntent;
276
277 public final static int TAG = 9;
278 }
279
Adam Cohenca6fd842010-09-03 18:10:35 -0700280 private class SetPendingIntentTemplate extends Action {
281 public SetPendingIntentTemplate(int id, PendingIntent pendingIntentTemplate) {
282 this.viewId = id;
283 this.pendingIntentTemplate = pendingIntentTemplate;
284 }
285
286 public SetPendingIntentTemplate(Parcel parcel) {
287 viewId = parcel.readInt();
288 pendingIntentTemplate = PendingIntent.readPendingIntentOrNullFromParcel(parcel);
289 }
290
291 public void writeToParcel(Parcel dest, int flags) {
292 dest.writeInt(TAG);
293 dest.writeInt(viewId);
294 pendingIntentTemplate.writeToParcel(dest, 0 /* no flags */);
295 }
296
297 @Override
Winson Chung037300b2011-03-29 15:40:16 -0700298 public void apply(View root, ViewGroup rootParent) {
Adam Cohenca6fd842010-09-03 18:10:35 -0700299 final View target = root.findViewById(viewId);
Joe Onorato2b69ce42010-10-31 11:35:41 -0700300 if (target == null) return;
Adam Cohenca6fd842010-09-03 18:10:35 -0700301
302 // If the view isn't an AdapterView, setting a PendingIntent template doesn't make sense
303 if (target instanceof AdapterView<?>) {
Adam Cohena32edd42010-10-26 10:35:01 -0700304 AdapterView<?> av = (AdapterView<?>) target;
Adam Cohenca6fd842010-09-03 18:10:35 -0700305 // The PendingIntent template is stored in the view's tag.
Adam Cohena32edd42010-10-26 10:35:01 -0700306 OnItemClickListener listener = new OnItemClickListener() {
307 public void onItemClick(AdapterView<?> parent, View view,
308 int position, long id) {
309 // The view should be a frame layout
310 if (view instanceof ViewGroup) {
311 ViewGroup vg = (ViewGroup) view;
312
313 // AdapterViews contain their children in a frame
314 // so we need to go one layer deeper here.
315 if (parent instanceof AdapterViewAnimator) {
316 vg = (ViewGroup) vg.getChildAt(0);
317 }
318 if (vg == null) return;
319
320 Intent fillInIntent = null;
321 int childCount = vg.getChildCount();
322 for (int i = 0; i < childCount; i++) {
323 Object tag = vg.getChildAt(i).getTag(com.android.internal.R.id.fillInIntent);
324 if (tag instanceof Intent) {
325 fillInIntent = (Intent) tag;
326 break;
327 }
328 }
329 if (fillInIntent == null) return;
330
331 final float appScale = view.getContext().getResources()
332 .getCompatibilityInfo().applicationScale;
333 final int[] pos = new int[2];
334 view.getLocationOnScreen(pos);
335
336 final Rect rect = new Rect();
337 rect.left = (int) (pos[0] * appScale + 0.5f);
338 rect.top = (int) (pos[1] * appScale + 0.5f);
339 rect.right = (int) ((pos[0] + view.getWidth()) * appScale + 0.5f);
340 rect.bottom = (int) ((pos[1] + view.getHeight()) * appScale + 0.5f);
341
342 final Intent intent = new Intent();
343 intent.setSourceBounds(rect);
344 startIntentSafely(view.getContext(), pendingIntentTemplate, fillInIntent);
345 }
346 }
347 };
348 av.setOnItemClickListener(listener);
349 av.setTag(pendingIntentTemplate);
Adam Cohenca6fd842010-09-03 18:10:35 -0700350 } else {
351 Log.e("RemoteViews", "Cannot setPendingIntentTemplate on a view which is not" +
Adam Cohen35ae9ca2010-09-20 15:20:41 -0700352 "an AdapterView (id: " + viewId + ")");
Adam Cohenca6fd842010-09-03 18:10:35 -0700353 return;
354 }
355 }
356
357 int viewId;
358 PendingIntent pendingIntentTemplate;
359
360 public final static int TAG = 8;
361 }
362
Winson Chung037300b2011-03-29 15:40:16 -0700363 private class SetRemoteViewsAdapterIntent extends Action {
364 public SetRemoteViewsAdapterIntent(int id, Intent intent) {
365 this.viewId = id;
366 this.intent = intent;
367 }
368
369 public SetRemoteViewsAdapterIntent(Parcel parcel) {
370 viewId = parcel.readInt();
371 intent = Intent.CREATOR.createFromParcel(parcel);
372 }
373
374 public void writeToParcel(Parcel dest, int flags) {
375 dest.writeInt(TAG);
376 dest.writeInt(viewId);
377 intent.writeToParcel(dest, flags);
378 }
379
380 @Override
381 public void apply(View root, ViewGroup rootParent) {
382 final View target = root.findViewById(viewId);
383 if (target == null) return;
384
385 // Ensure that we are applying to an AppWidget root
386 if (!(rootParent instanceof AppWidgetHostView)) {
387 Log.e("RemoteViews", "SetRemoteViewsAdapterIntent action can only be used for " +
388 "AppWidgets (root id: " + viewId + ")");
389 return;
390 }
391 // Ensure that we are calling setRemoteAdapter on an AdapterView that supports it
392 if (!(target instanceof AbsListView) && !(target instanceof AdapterViewAnimator)) {
393 Log.e("RemoteViews", "Cannot setRemoteViewsAdapter on a view which is not " +
394 "an AbsListView or AdapterViewAnimator (id: " + viewId + ")");
395 return;
396 }
397
398 // Embed the AppWidget Id for use in RemoteViewsAdapter when connecting to the intent
399 // RemoteViewsService
400 AppWidgetHostView host = (AppWidgetHostView) rootParent;
401 intent.putExtra(EXTRA_REMOTEADAPTER_APPWIDGET_ID, host.getAppWidgetId());
402 if (target instanceof AbsListView) {
403 AbsListView v = (AbsListView) target;
404 v.setRemoteViewsAdapter(intent);
405 } else if (target instanceof AdapterViewAnimator) {
406 AdapterViewAnimator v = (AdapterViewAnimator) target;
407 v.setRemoteViewsAdapter(intent);
408 }
409 }
410
411 int viewId;
412 Intent intent;
413
414 public final static int TAG = 10;
415 }
416
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 /**
418 * Equivalent to calling
419 * {@link android.view.View#setOnClickListener(android.view.View.OnClickListener)}
420 * to launch the provided {@link PendingIntent}.
421 */
422 private class SetOnClickPendingIntent extends Action {
423 public SetOnClickPendingIntent(int id, PendingIntent pendingIntent) {
424 this.viewId = id;
425 this.pendingIntent = pendingIntent;
426 }
Adam Cohenca6fd842010-09-03 18:10:35 -0700427
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428 public SetOnClickPendingIntent(Parcel parcel) {
429 viewId = parcel.readInt();
430 pendingIntent = PendingIntent.readPendingIntentOrNullFromParcel(parcel);
431 }
Adam Cohenca6fd842010-09-03 18:10:35 -0700432
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800433 public void writeToParcel(Parcel dest, int flags) {
434 dest.writeInt(TAG);
435 dest.writeInt(viewId);
436 pendingIntent.writeToParcel(dest, 0 /* no flags */);
437 }
Adam Cohenca6fd842010-09-03 18:10:35 -0700438
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800439 @Override
Winson Chung037300b2011-03-29 15:40:16 -0700440 public void apply(View root, ViewGroup rootParent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800441 final View target = root.findViewById(viewId);
Joe Onorato2b69ce42010-10-31 11:35:41 -0700442 if (target == null) return;
Adam Cohenca6fd842010-09-03 18:10:35 -0700443
444 // If the view is an AdapterView, setting a PendingIntent on click doesn't make much
445 // sense, do they mean to set a PendingIntent template for the AdapterView's children?
446 if (mIsWidgetCollectionChild) {
Adam Cohen35ae9ca2010-09-20 15:20:41 -0700447 Log.e("RemoteViews", "Cannot setOnClickPendingIntent for collection item " +
448 "(id: " + viewId + ")");
Adam Cohenca6fd842010-09-03 18:10:35 -0700449 // TODO: return; We'll let this slide until apps are up to date.
450 }
451
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800452 if (target != null && pendingIntent != null) {
453 OnClickListener listener = new OnClickListener() {
454 public void onClick(View v) {
Jeff Sharkeya503f6f2009-12-08 21:50:14 -0800455 // Find target view location in screen coordinates and
456 // fill into PendingIntent before sending.
457 final float appScale = v.getContext().getResources()
458 .getCompatibilityInfo().applicationScale;
459 final int[] pos = new int[2];
Joe Onorato75970652009-12-02 23:04:55 -0800460 v.getLocationOnScreen(pos);
Jeff Sharkeya503f6f2009-12-08 21:50:14 -0800461
462 final Rect rect = new Rect();
463 rect.left = (int) (pos[0] * appScale + 0.5f);
464 rect.top = (int) (pos[1] * appScale + 0.5f);
465 rect.right = (int) ((pos[0] + v.getWidth()) * appScale + 0.5f);
466 rect.bottom = (int) ((pos[1] + v.getHeight()) * appScale + 0.5f);
467
468 final Intent intent = new Intent();
469 intent.setSourceBounds(rect);
Winson Chungae615982010-11-01 12:14:49 -0700470 startIntentSafely(v.getContext(), pendingIntent, intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800471 }
472 };
473 target.setOnClickListener(listener);
474 }
475 }
476
477 int viewId;
478 PendingIntent pendingIntent;
479
480 public final static int TAG = 1;
481 }
482
483 /**
484 * Equivalent to calling a combination of {@link Drawable#setAlpha(int)},
485 * {@link Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)},
486 * and/or {@link Drawable#setLevel(int)} on the {@link Drawable} of a given view.
487 * <p>
488 * These operations will be performed on the {@link Drawable} returned by the
489 * target {@link View#getBackground()} by default. If targetBackground is false,
490 * we assume the target is an {@link ImageView} and try applying the operations
491 * to {@link ImageView#getDrawable()}.
492 * <p>
493 * You can omit specific calls by marking their values with null or -1.
494 */
495 private class SetDrawableParameters extends Action {
496 public SetDrawableParameters(int id, boolean targetBackground, int alpha,
497 int colorFilter, PorterDuff.Mode mode, int level) {
498 this.viewId = id;
499 this.targetBackground = targetBackground;
500 this.alpha = alpha;
501 this.colorFilter = colorFilter;
502 this.filterMode = mode;
503 this.level = level;
504 }
505
506 public SetDrawableParameters(Parcel parcel) {
507 viewId = parcel.readInt();
508 targetBackground = parcel.readInt() != 0;
509 alpha = parcel.readInt();
510 colorFilter = parcel.readInt();
511 boolean hasMode = parcel.readInt() != 0;
512 if (hasMode) {
513 filterMode = PorterDuff.Mode.valueOf(parcel.readString());
514 } else {
515 filterMode = null;
516 }
517 level = parcel.readInt();
518 }
519
520 public void writeToParcel(Parcel dest, int flags) {
521 dest.writeInt(TAG);
522 dest.writeInt(viewId);
523 dest.writeInt(targetBackground ? 1 : 0);
524 dest.writeInt(alpha);
525 dest.writeInt(colorFilter);
526 if (filterMode != null) {
527 dest.writeInt(1);
528 dest.writeString(filterMode.toString());
529 } else {
530 dest.writeInt(0);
531 }
532 dest.writeInt(level);
533 }
534
535 @Override
Winson Chung037300b2011-03-29 15:40:16 -0700536 public void apply(View root, ViewGroup rootParent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 final View target = root.findViewById(viewId);
Joe Onorato2b69ce42010-10-31 11:35:41 -0700538 if (target == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800539
540 // Pick the correct drawable to modify for this view
541 Drawable targetDrawable = null;
542 if (targetBackground) {
543 targetDrawable = target.getBackground();
544 } else if (target instanceof ImageView) {
545 ImageView imageView = (ImageView) target;
546 targetDrawable = imageView.getDrawable();
547 }
548
Romain Guya5475592009-07-01 17:20:08 -0700549 if (targetDrawable != null) {
550 // Perform modifications only if values are set correctly
551 if (alpha != -1) {
552 targetDrawable.setAlpha(alpha);
553 }
554 if (colorFilter != -1 && filterMode != null) {
555 targetDrawable.setColorFilter(colorFilter, filterMode);
556 }
557 if (level != -1) {
558 targetDrawable.setLevel(level);
559 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560 }
561 }
Winson Chung3ec9a452010-09-23 16:40:28 -0700562
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800563 int viewId;
564 boolean targetBackground;
565 int alpha;
566 int colorFilter;
567 PorterDuff.Mode filterMode;
568 int level;
569
570 public final static int TAG = 3;
571 }
572
Adam Cohen2dd21972010-08-15 18:20:04 -0700573 private class ReflectionActionWithoutParams extends Action {
574 int viewId;
575 String methodName;
576
577 public final static int TAG = 5;
578
579 ReflectionActionWithoutParams(int viewId, String methodName) {
580 this.viewId = viewId;
581 this.methodName = methodName;
582 }
583
584 ReflectionActionWithoutParams(Parcel in) {
585 this.viewId = in.readInt();
586 this.methodName = in.readString();
587 }
588
589 public void writeToParcel(Parcel out, int flags) {
590 out.writeInt(TAG);
591 out.writeInt(this.viewId);
592 out.writeString(this.methodName);
593 }
594
595 @Override
Winson Chung037300b2011-03-29 15:40:16 -0700596 public void apply(View root, ViewGroup rootParent) {
Adam Cohen2dd21972010-08-15 18:20:04 -0700597 final View view = root.findViewById(viewId);
Joe Onorato2b69ce42010-10-31 11:35:41 -0700598 if (view == null) return;
Adam Cohen2dd21972010-08-15 18:20:04 -0700599
600 Class klass = view.getClass();
601 Method method;
602 try {
603 method = klass.getMethod(this.methodName);
604 } catch (NoSuchMethodException ex) {
605 throw new ActionException("view: " + klass.getName() + " doesn't have method: "
606 + this.methodName + "()");
607 }
608
609 if (!method.isAnnotationPresent(RemotableViewMethod.class)) {
610 throw new ActionException("view: " + klass.getName()
611 + " can't use method with RemoteViews: "
612 + this.methodName + "()");
613 }
614
615 try {
616 //noinspection ConstantIfStatement
617 if (false) {
618 Log.d("RemoteViews", "view: " + klass.getName() + " calling method: "
619 + this.methodName + "()");
620 }
621 method.invoke(view);
622 } catch (Exception ex) {
623 throw new ActionException(ex);
624 }
625 }
626 }
627
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800628 /**
629 * Base class for the reflection actions.
630 */
631 private class ReflectionAction extends Action {
632 static final int TAG = 2;
633
634 static final int BOOLEAN = 1;
635 static final int BYTE = 2;
636 static final int SHORT = 3;
637 static final int INT = 4;
638 static final int LONG = 5;
639 static final int FLOAT = 6;
640 static final int DOUBLE = 7;
641 static final int CHAR = 8;
642 static final int STRING = 9;
643 static final int CHAR_SEQUENCE = 10;
644 static final int URI = 11;
645 static final int BITMAP = 12;
Bjorn Bringertd755b062010-01-06 17:15:37 +0000646 static final int BUNDLE = 13;
Winson Chung499cb9f2010-07-16 11:18:17 -0700647 static final int INTENT = 14;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648
649 int viewId;
650 String methodName;
651 int type;
652 Object value;
653
654 ReflectionAction(int viewId, String methodName, int type, Object value) {
655 this.viewId = viewId;
656 this.methodName = methodName;
657 this.type = type;
658 this.value = value;
659 }
660
661 ReflectionAction(Parcel in) {
662 this.viewId = in.readInt();
663 this.methodName = in.readString();
664 this.type = in.readInt();
Romain Guya5475592009-07-01 17:20:08 -0700665 //noinspection ConstantIfStatement
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800666 if (false) {
667 Log.d("RemoteViews", "read viewId=0x" + Integer.toHexString(this.viewId)
668 + " methodName=" + this.methodName + " type=" + this.type);
669 }
670 switch (this.type) {
671 case BOOLEAN:
672 this.value = in.readInt() != 0;
673 break;
674 case BYTE:
675 this.value = in.readByte();
676 break;
677 case SHORT:
678 this.value = (short)in.readInt();
679 break;
680 case INT:
681 this.value = in.readInt();
682 break;
683 case LONG:
684 this.value = in.readLong();
685 break;
686 case FLOAT:
687 this.value = in.readFloat();
688 break;
689 case DOUBLE:
690 this.value = in.readDouble();
691 break;
692 case CHAR:
693 this.value = (char)in.readInt();
694 break;
695 case STRING:
696 this.value = in.readString();
697 break;
698 case CHAR_SEQUENCE:
699 this.value = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
700 break;
701 case URI:
702 this.value = Uri.CREATOR.createFromParcel(in);
703 break;
704 case BITMAP:
705 this.value = Bitmap.CREATOR.createFromParcel(in);
706 break;
Bjorn Bringertd755b062010-01-06 17:15:37 +0000707 case BUNDLE:
708 this.value = in.readBundle();
709 break;
Winson Chung499cb9f2010-07-16 11:18:17 -0700710 case INTENT:
711 this.value = Intent.CREATOR.createFromParcel(in);
712 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800713 default:
714 break;
715 }
716 }
717
718 public void writeToParcel(Parcel out, int flags) {
719 out.writeInt(TAG);
720 out.writeInt(this.viewId);
721 out.writeString(this.methodName);
722 out.writeInt(this.type);
Romain Guya5475592009-07-01 17:20:08 -0700723 //noinspection ConstantIfStatement
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800724 if (false) {
725 Log.d("RemoteViews", "write viewId=0x" + Integer.toHexString(this.viewId)
726 + " methodName=" + this.methodName + " type=" + this.type);
727 }
728 switch (this.type) {
729 case BOOLEAN:
Romain Guya5475592009-07-01 17:20:08 -0700730 out.writeInt((Boolean) this.value ? 1 : 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800731 break;
732 case BYTE:
Romain Guya5475592009-07-01 17:20:08 -0700733 out.writeByte((Byte) this.value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800734 break;
735 case SHORT:
Romain Guya5475592009-07-01 17:20:08 -0700736 out.writeInt((Short) this.value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800737 break;
738 case INT:
Romain Guya5475592009-07-01 17:20:08 -0700739 out.writeInt((Integer) this.value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800740 break;
741 case LONG:
Romain Guya5475592009-07-01 17:20:08 -0700742 out.writeLong((Long) this.value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800743 break;
744 case FLOAT:
Romain Guya5475592009-07-01 17:20:08 -0700745 out.writeFloat((Float) this.value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800746 break;
747 case DOUBLE:
Romain Guya5475592009-07-01 17:20:08 -0700748 out.writeDouble((Double) this.value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800749 break;
750 case CHAR:
751 out.writeInt((int)((Character)this.value).charValue());
752 break;
753 case STRING:
754 out.writeString((String)this.value);
755 break;
756 case CHAR_SEQUENCE:
757 TextUtils.writeToParcel((CharSequence)this.value, out, flags);
758 break;
759 case URI:
760 ((Uri)this.value).writeToParcel(out, flags);
761 break;
762 case BITMAP:
763 ((Bitmap)this.value).writeToParcel(out, flags);
764 break;
Bjorn Bringertd755b062010-01-06 17:15:37 +0000765 case BUNDLE:
766 out.writeBundle((Bundle) this.value);
767 break;
Winson Chung499cb9f2010-07-16 11:18:17 -0700768 case INTENT:
769 ((Intent)this.value).writeToParcel(out, flags);
770 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800771 default:
772 break;
773 }
774 }
775
776 private Class getParameterType() {
777 switch (this.type) {
778 case BOOLEAN:
779 return boolean.class;
780 case BYTE:
781 return byte.class;
782 case SHORT:
783 return short.class;
784 case INT:
785 return int.class;
786 case LONG:
787 return long.class;
788 case FLOAT:
789 return float.class;
790 case DOUBLE:
791 return double.class;
792 case CHAR:
793 return char.class;
794 case STRING:
795 return String.class;
796 case CHAR_SEQUENCE:
797 return CharSequence.class;
798 case URI:
799 return Uri.class;
800 case BITMAP:
801 return Bitmap.class;
Bjorn Bringertd755b062010-01-06 17:15:37 +0000802 case BUNDLE:
803 return Bundle.class;
Winson Chung499cb9f2010-07-16 11:18:17 -0700804 case INTENT:
805 return Intent.class;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800806 default:
807 return null;
808 }
809 }
810
811 @Override
Winson Chung037300b2011-03-29 15:40:16 -0700812 public void apply(View root, ViewGroup rootParent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800813 final View view = root.findViewById(viewId);
Joe Onorato2b69ce42010-10-31 11:35:41 -0700814 if (view == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815
816 Class param = getParameterType();
817 if (param == null) {
818 throw new ActionException("bad type: " + this.type);
819 }
820
821 Class klass = view.getClass();
Romain Guya5475592009-07-01 17:20:08 -0700822 Method method;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800823 try {
824 method = klass.getMethod(this.methodName, getParameterType());
825 }
826 catch (NoSuchMethodException ex) {
827 throw new ActionException("view: " + klass.getName() + " doesn't have method: "
828 + this.methodName + "(" + param.getName() + ")");
829 }
830
831 if (!method.isAnnotationPresent(RemotableViewMethod.class)) {
832 throw new ActionException("view: " + klass.getName()
833 + " can't use method with RemoteViews: "
834 + this.methodName + "(" + param.getName() + ")");
835 }
836
837 try {
Romain Guya5475592009-07-01 17:20:08 -0700838 //noinspection ConstantIfStatement
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800839 if (false) {
840 Log.d("RemoteViews", "view: " + klass.getName() + " calling method: "
841 + this.methodName + "(" + param.getName() + ") with "
842 + (this.value == null ? "null" : this.value.getClass().getName()));
843 }
844 method.invoke(view, this.value);
845 }
846 catch (Exception ex) {
847 throw new ActionException(ex);
848 }
849 }
Winson Chung3ec9a452010-09-23 16:40:28 -0700850
851 @Override
852 public void updateMemoryUsageEstimate(MemoryUsageCounter counter) {
853 // We currently only calculate Bitmap memory usage
854 switch (this.type) {
855 case BITMAP:
856 if (this.value != null) {
857 final Bitmap b = (Bitmap) this.value;
858 final Bitmap.Config c = b.getConfig();
Joe Onoratof01345e2011-01-17 17:20:09 -0800859 // If we don't know, be pessimistic and assume 4
Winson Chung3ec9a452010-09-23 16:40:28 -0700860 int bpp = 4;
Joe Onoratof01345e2011-01-17 17:20:09 -0800861 if (c != null) {
862 switch (c) {
863 case ALPHA_8:
864 bpp = 1;
865 break;
866 case RGB_565:
867 case ARGB_4444:
868 bpp = 2;
869 break;
870 case ARGB_8888:
871 bpp = 4;
872 break;
873 }
Winson Chung3ec9a452010-09-23 16:40:28 -0700874 }
875 counter.bitmapIncrement(b.getWidth() * b.getHeight() * bpp);
876 }
877 break;
878 default:
879 break;
880 }
881 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800882 }
883
Jeff Sharkey1162fd72009-11-04 17:58:08 -0800884 /**
885 * Equivalent to calling {@link ViewGroup#addView(View)} after inflating the
886 * given {@link RemoteViews}, or calling {@link ViewGroup#removeAllViews()}
887 * when null. This allows users to build "nested" {@link RemoteViews}.
888 */
889 private class ViewGroupAction extends Action {
890 public ViewGroupAction(int viewId, RemoteViews nestedViews) {
891 this.viewId = viewId;
892 this.nestedViews = nestedViews;
893 }
894
895 public ViewGroupAction(Parcel parcel) {
896 viewId = parcel.readInt();
897 nestedViews = parcel.readParcelable(null);
898 }
899
900 public void writeToParcel(Parcel dest, int flags) {
901 dest.writeInt(TAG);
902 dest.writeInt(viewId);
903 dest.writeParcelable(nestedViews, 0 /* no flags */);
904 }
905
906 @Override
Winson Chung037300b2011-03-29 15:40:16 -0700907 public void apply(View root, ViewGroup rootParent) {
Jeff Sharkey1162fd72009-11-04 17:58:08 -0800908 final Context context = root.getContext();
909 final ViewGroup target = (ViewGroup) root.findViewById(viewId);
Joe Onorato2b69ce42010-10-31 11:35:41 -0700910 if (target == null) return;
Jeff Sharkey1162fd72009-11-04 17:58:08 -0800911 if (nestedViews != null) {
912 // Inflate nested views and add as children
913 target.addView(nestedViews.apply(context, target));
Joe Onorato2b69ce42010-10-31 11:35:41 -0700914 } else {
Jeff Sharkey1162fd72009-11-04 17:58:08 -0800915 // Clear all children when nested views omitted
916 target.removeAllViews();
917 }
918 }
919
Winson Chung3ec9a452010-09-23 16:40:28 -0700920 @Override
921 public void updateMemoryUsageEstimate(MemoryUsageCounter counter) {
922 if (nestedViews != null) {
923 counter.bitmapIncrement(nestedViews.estimateBitmapMemoryUsage());
924 }
925 }
926
Jeff Sharkey1162fd72009-11-04 17:58:08 -0800927 int viewId;
928 RemoteViews nestedViews;
929
930 public final static int TAG = 4;
931 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800932
933 /**
Winson Chung3ec9a452010-09-23 16:40:28 -0700934 * Simple class used to keep track of memory usage in a RemoteViews.
935 *
936 */
937 private class MemoryUsageCounter {
938 public void clear() {
939 mBitmapHeapMemoryUsage = 0;
940 }
941
942 public void bitmapIncrement(int numBytes) {
943 mBitmapHeapMemoryUsage += numBytes;
944 }
945
946 public int getBitmapHeapMemoryUsage() {
947 return mBitmapHeapMemoryUsage;
948 }
949
950 int mBitmapHeapMemoryUsage;
951 }
952
953 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800954 * Create a new RemoteViews object that will display the views contained
955 * in the specified layout file.
956 *
957 * @param packageName Name of the package that contains the layout resource
958 * @param layoutId The id of the layout resource
959 */
960 public RemoteViews(String packageName, int layoutId) {
961 mPackage = packageName;
962 mLayoutId = layoutId;
Winson Chung3ec9a452010-09-23 16:40:28 -0700963
964 // setup the memory usage statistics
965 mMemoryUsageCounter = new MemoryUsageCounter();
966 recalculateMemoryUsage();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800967 }
968
969 /**
970 * Reads a RemoteViews object from a parcel.
971 *
972 * @param parcel
973 */
974 public RemoteViews(Parcel parcel) {
975 mPackage = parcel.readString();
976 mLayoutId = parcel.readInt();
Adam Cohenca6fd842010-09-03 18:10:35 -0700977 mIsWidgetCollectionChild = parcel.readInt() == 1 ? true : false;
978
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800979 int count = parcel.readInt();
980 if (count > 0) {
981 mActions = new ArrayList<Action>(count);
982 for (int i=0; i<count; i++) {
983 int tag = parcel.readInt();
984 switch (tag) {
985 case SetOnClickPendingIntent.TAG:
986 mActions.add(new SetOnClickPendingIntent(parcel));
987 break;
988 case SetDrawableParameters.TAG:
989 mActions.add(new SetDrawableParameters(parcel));
990 break;
991 case ReflectionAction.TAG:
992 mActions.add(new ReflectionAction(parcel));
993 break;
Jeff Sharkey1162fd72009-11-04 17:58:08 -0800994 case ViewGroupAction.TAG:
995 mActions.add(new ViewGroupAction(parcel));
996 break;
Adam Cohen2dd21972010-08-15 18:20:04 -0700997 case ReflectionActionWithoutParams.TAG:
998 mActions.add(new ReflectionActionWithoutParams(parcel));
999 break;
Adam Cohen1480fdd2010-08-25 17:24:53 -07001000 case SetEmptyView.TAG:
1001 mActions.add(new SetEmptyView(parcel));
1002 break;
Adam Cohenca6fd842010-09-03 18:10:35 -07001003 case SetPendingIntentTemplate.TAG:
1004 mActions.add(new SetPendingIntentTemplate(parcel));
1005 break;
Adam Cohen35ae9ca2010-09-20 15:20:41 -07001006 case SetOnClickFillInIntent.TAG:
1007 mActions.add(new SetOnClickFillInIntent(parcel));
1008 break;
Winson Chung037300b2011-03-29 15:40:16 -07001009 case SetRemoteViewsAdapterIntent.TAG:
1010 mActions.add(new SetRemoteViewsAdapterIntent(parcel));
1011 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001012 default:
1013 throw new ActionException("Tag " + tag + " not found");
1014 }
1015 }
1016 }
Winson Chung3ec9a452010-09-23 16:40:28 -07001017
1018 // setup the memory usage statistics
1019 mMemoryUsageCounter = new MemoryUsageCounter();
1020 recalculateMemoryUsage();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001021 }
1022
Gilles Debunne30301932010-06-16 18:32:00 -07001023 @Override
Joe Onorato18e69df2010-05-17 22:26:12 -07001024 public RemoteViews clone() {
1025 final RemoteViews that = new RemoteViews(mPackage, mLayoutId);
1026 if (mActions != null) {
1027 that.mActions = (ArrayList<Action>)mActions.clone();
1028 }
Winson Chung3ec9a452010-09-23 16:40:28 -07001029
1030 // update the memory usage stats of the cloned RemoteViews
1031 that.recalculateMemoryUsage();
Joe Onorato18e69df2010-05-17 22:26:12 -07001032 return that;
1033 }
1034
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001035 public String getPackage() {
1036 return mPackage;
1037 }
1038
1039 public int getLayoutId() {
1040 return mLayoutId;
1041 }
1042
Winson Chung3ec9a452010-09-23 16:40:28 -07001043 /*
Adam Cohenca6fd842010-09-03 18:10:35 -07001044 * This flag indicates whether this RemoteViews object is being created from a
1045 * RemoteViewsService for use as a child of a widget collection. This flag is used
1046 * to determine whether or not certain features are available, in particular,
1047 * setting on click extras and setting on click pending intents. The former is enabled,
1048 * and the latter disabled when this flag is true.
1049 */
1050 void setIsWidgetCollectionChild(boolean isWidgetCollectionChild) {
1051 mIsWidgetCollectionChild = isWidgetCollectionChild;
1052 }
1053
1054 /**
Winson Chung3ec9a452010-09-23 16:40:28 -07001055 * Updates the memory usage statistics.
1056 */
1057 private void recalculateMemoryUsage() {
1058 mMemoryUsageCounter.clear();
1059
1060 // Accumulate the memory usage for each action
1061 if (mActions != null) {
1062 final int count = mActions.size();
1063 for (int i= 0; i < count; ++i) {
1064 mActions.get(i).updateMemoryUsageEstimate(mMemoryUsageCounter);
1065 }
1066 }
1067 }
1068
1069 /**
1070 * Returns an estimate of the bitmap heap memory usage for this RemoteViews.
1071 */
1072 int estimateBitmapMemoryUsage() {
1073 return mMemoryUsageCounter.getBitmapHeapMemoryUsage();
1074 }
1075
1076 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001077 * Add an action to be executed on the remote side when apply is called.
1078 *
1079 * @param a The action to add
1080 */
1081 private void addAction(Action a) {
1082 if (mActions == null) {
1083 mActions = new ArrayList<Action>();
1084 }
1085 mActions.add(a);
Winson Chung3ec9a452010-09-23 16:40:28 -07001086
1087 // update the memory usage stats
1088 a.updateMemoryUsageEstimate(mMemoryUsageCounter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001089 }
Jeff Sharkey1162fd72009-11-04 17:58:08 -08001090
1091 /**
1092 * Equivalent to calling {@link ViewGroup#addView(View)} after inflating the
1093 * given {@link RemoteViews}. This allows users to build "nested"
1094 * {@link RemoteViews}. In cases where consumers of {@link RemoteViews} may
1095 * recycle layouts, use {@link #removeAllViews(int)} to clear any existing
1096 * children.
1097 *
1098 * @param viewId The id of the parent {@link ViewGroup} to add child into.
1099 * @param nestedView {@link RemoteViews} that describes the child.
1100 */
1101 public void addView(int viewId, RemoteViews nestedView) {
1102 addAction(new ViewGroupAction(viewId, nestedView));
1103 }
1104
1105 /**
1106 * Equivalent to calling {@link ViewGroup#removeAllViews()}.
1107 *
1108 * @param viewId The id of the parent {@link ViewGroup} to remove all
1109 * children from.
1110 */
1111 public void removeAllViews(int viewId) {
1112 addAction(new ViewGroupAction(viewId, null));
1113 }
1114
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001115 /**
Adam Cohen0b96a572011-02-10 15:56:16 -08001116 * Equivalent to calling {@link AdapterViewAnimator#showNext()}
Adam Cohen2dd21972010-08-15 18:20:04 -07001117 *
Adam Cohen0b96a572011-02-10 15:56:16 -08001118 * @param viewId The id of the view on which to call {@link AdapterViewAnimator#showNext()}
Adam Cohen2dd21972010-08-15 18:20:04 -07001119 */
1120 public void showNext(int viewId) {
1121 addAction(new ReflectionActionWithoutParams(viewId, "showNext"));
1122 }
1123
1124 /**
Adam Cohen0b96a572011-02-10 15:56:16 -08001125 * Equivalent to calling {@link AdapterViewAnimator#showPrevious()}
Adam Cohen2dd21972010-08-15 18:20:04 -07001126 *
Adam Cohen0b96a572011-02-10 15:56:16 -08001127 * @param viewId The id of the view on which to call {@link AdapterViewAnimator#showPrevious()}
Adam Cohen2dd21972010-08-15 18:20:04 -07001128 */
1129 public void showPrevious(int viewId) {
1130 addAction(new ReflectionActionWithoutParams(viewId, "showPrevious"));
1131 }
1132
1133 /**
Adam Cohen0b96a572011-02-10 15:56:16 -08001134 * Equivalent to calling {@link AdapterViewAnimator#setDisplayedChild(int)}
1135 *
1136 * @param viewId The id of the view on which to call
1137 * {@link AdapterViewAnimator#setDisplayedChild(int)}
1138 */
1139 public void setDisplayedChild(int viewId, int childIndex) {
1140 setInt(viewId, "setDisplayedChild", childIndex);
1141 }
1142
1143 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001144 * Equivalent to calling View.setVisibility
1145 *
1146 * @param viewId The id of the view whose visibility should change
1147 * @param visibility The new visibility for the view
1148 */
1149 public void setViewVisibility(int viewId, int visibility) {
1150 setInt(viewId, "setVisibility", visibility);
1151 }
Adam Cohenca6fd842010-09-03 18:10:35 -07001152
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001153 /**
1154 * Equivalent to calling TextView.setText
1155 *
1156 * @param viewId The id of the view whose text should change
1157 * @param text The new text for the view
1158 */
1159 public void setTextViewText(int viewId, CharSequence text) {
1160 setCharSequence(viewId, "setText", text);
1161 }
1162
1163 /**
1164 * Equivalent to calling ImageView.setImageResource
1165 *
1166 * @param viewId The id of the view whose drawable should change
1167 * @param srcId The new resource id for the drawable
1168 */
1169 public void setImageViewResource(int viewId, int srcId) {
1170 setInt(viewId, "setImageResource", srcId);
1171 }
1172
1173 /**
1174 * Equivalent to calling ImageView.setImageURI
1175 *
1176 * @param viewId The id of the view whose drawable should change
1177 * @param uri The Uri for the image
1178 */
1179 public void setImageViewUri(int viewId, Uri uri) {
1180 setUri(viewId, "setImageURI", uri);
1181 }
1182
1183 /**
1184 * Equivalent to calling ImageView.setImageBitmap
1185 *
1186 * @param viewId The id of the view whose drawable should change
1187 * @param bitmap The new Bitmap for the drawable
1188 */
1189 public void setImageViewBitmap(int viewId, Bitmap bitmap) {
1190 setBitmap(viewId, "setImageBitmap", bitmap);
1191 }
1192
1193 /**
Adam Cohen1480fdd2010-08-25 17:24:53 -07001194 * Equivalent to calling AdapterView.setEmptyView
1195 *
1196 * @param viewId The id of the view on which to set the empty view
1197 * @param emptyViewId The view id of the empty view
1198 */
1199 public void setEmptyView(int viewId, int emptyViewId) {
1200 addAction(new SetEmptyView(viewId, emptyViewId));
1201 }
1202
1203 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001204 * Equivalent to calling {@link Chronometer#setBase Chronometer.setBase},
1205 * {@link Chronometer#setFormat Chronometer.setFormat},
1206 * and {@link Chronometer#start Chronometer.start()} or
1207 * {@link Chronometer#stop Chronometer.stop()}.
1208 *
1209 * @param viewId The id of the view whose text should change
1210 * @param base The time at which the timer would have read 0:00. This
1211 * time should be based off of
1212 * {@link android.os.SystemClock#elapsedRealtime SystemClock.elapsedRealtime()}.
1213 * @param format The Chronometer format string, or null to
1214 * simply display the timer value.
1215 * @param started True if you want the clock to be started, false if not.
1216 */
1217 public void setChronometer(int viewId, long base, String format, boolean started) {
1218 setLong(viewId, "setBase", base);
1219 setString(viewId, "setFormat", format);
1220 setBoolean(viewId, "setStarted", started);
1221 }
1222
1223 /**
1224 * Equivalent to calling {@link ProgressBar#setMax ProgressBar.setMax},
1225 * {@link ProgressBar#setProgress ProgressBar.setProgress}, and
1226 * {@link ProgressBar#setIndeterminate ProgressBar.setIndeterminate}
1227 *
1228 * If indeterminate is true, then the values for max and progress are ignored.
1229 *
1230 * @param viewId The id of the view whose text should change
1231 * @param max The 100% value for the progress bar
1232 * @param progress The current value of the progress bar.
1233 * @param indeterminate True if the progress bar is indeterminate,
1234 * false if not.
1235 */
1236 public void setProgressBar(int viewId, int max, int progress,
1237 boolean indeterminate) {
1238 setBoolean(viewId, "setIndeterminate", indeterminate);
1239 if (!indeterminate) {
1240 setInt(viewId, "setMax", max);
1241 setInt(viewId, "setProgress", progress);
1242 }
1243 }
1244
1245 /**
1246 * Equivalent to calling
1247 * {@link android.view.View#setOnClickListener(android.view.View.OnClickListener)}
1248 * to launch the provided {@link PendingIntent}.
1249 *
Adam Cohen35ae9ca2010-09-20 15:20:41 -07001250 * When setting the on-click action of items within collections (eg. {@link ListView},
1251 * {@link StackView} etc.), this method will not work. Instead, use {@link
1252 * RemoteViews#setPendingIntentTemplate(int, PendingIntent) in conjunction with
1253 * RemoteViews#setOnClickFillInIntent(int, Intent).
1254 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001255 * @param viewId The id of the view that will trigger the {@link PendingIntent} when clicked
1256 * @param pendingIntent The {@link PendingIntent} to send when user clicks
1257 */
1258 public void setOnClickPendingIntent(int viewId, PendingIntent pendingIntent) {
1259 addAction(new SetOnClickPendingIntent(viewId, pendingIntent));
1260 }
1261
1262 /**
Adam Cohen35ae9ca2010-09-20 15:20:41 -07001263 * When using collections (eg. {@link ListView}, {@link StackView} etc.) in widgets, it is very
1264 * costly to set PendingIntents on the individual items, and is hence not permitted. Instead
1265 * this method should be used to set a single PendingIntent template on the collection, and
1266 * individual items can differentiate their on-click behavior using
1267 * {@link RemoteViews#setOnClickFillInIntent(int, Intent)}.
Adam Cohenca6fd842010-09-03 18:10:35 -07001268 *
1269 * @param viewId The id of the collection who's children will use this PendingIntent template
1270 * when clicked
1271 * @param pendingIntentTemplate The {@link PendingIntent} to be combined with extras specified
1272 * by a child of viewId and executed when that child is clicked
1273 */
1274 public void setPendingIntentTemplate(int viewId, PendingIntent pendingIntentTemplate) {
1275 addAction(new SetPendingIntentTemplate(viewId, pendingIntentTemplate));
1276 }
1277
1278 /**
Adam Cohen35ae9ca2010-09-20 15:20:41 -07001279 * When using collections (eg. {@link ListView}, {@link StackView} etc.) in widgets, it is very
1280 * costly to set PendingIntents on the individual items, and is hence not permitted. Instead
1281 * a single PendingIntent template can be set on the collection, see {@link
1282 * RemoteViews#setPendingIntentTemplate(int, PendingIntent)}, and the individual on-click
1283 * action of a given item can be distinguished by setting a fillInIntent on that item. The
1284 * fillInIntent is then combined with the PendingIntent template in order to determine the final
1285 * intent which will be executed when the item is clicked. This works as follows: any fields
1286 * which are left blank in the PendingIntent template, but are provided by the fillInIntent
1287 * will be overwritten, and the resulting PendingIntent will be used.
1288 *
1289 *
1290 * of the PendingIntent template will then be filled in with the associated fields that are
1291 * set in fillInIntent. See {@link Intent#fillIn(Intent, int)} for more details.
1292 *
1293 * @param viewId The id of the view on which to set the fillInIntent
1294 * @param fillInIntent The intent which will be combined with the parent's PendingIntent
1295 * in order to determine the on-click behavior of the view specified by viewId
1296 */
1297 public void setOnClickFillInIntent(int viewId, Intent fillInIntent) {
1298 addAction(new SetOnClickFillInIntent(viewId, fillInIntent));
1299 }
1300
1301 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001302 * @hide
1303 * Equivalent to calling a combination of {@link Drawable#setAlpha(int)},
1304 * {@link Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)},
1305 * and/or {@link Drawable#setLevel(int)} on the {@link Drawable} of a given
1306 * view.
1307 * <p>
1308 * You can omit specific calls by marking their values with null or -1.
1309 *
1310 * @param viewId The id of the view that contains the target
1311 * {@link Drawable}
1312 * @param targetBackground If true, apply these parameters to the
1313 * {@link Drawable} returned by
1314 * {@link android.view.View#getBackground()}. Otherwise, assume
1315 * the target view is an {@link ImageView} and apply them to
1316 * {@link ImageView#getDrawable()}.
1317 * @param alpha Specify an alpha value for the drawable, or -1 to leave
1318 * unchanged.
1319 * @param colorFilter Specify a color for a
1320 * {@link android.graphics.ColorFilter} for this drawable, or -1
1321 * to leave unchanged.
1322 * @param mode Specify a PorterDuff mode for this drawable, or null to leave
1323 * unchanged.
1324 * @param level Specify the level for the drawable, or -1 to leave
1325 * unchanged.
1326 */
1327 public void setDrawableParameters(int viewId, boolean targetBackground, int alpha,
1328 int colorFilter, PorterDuff.Mode mode, int level) {
1329 addAction(new SetDrawableParameters(viewId, targetBackground, alpha,
1330 colorFilter, mode, level));
1331 }
1332
1333 /**
1334 * Equivalent to calling {@link android.widget.TextView#setTextColor(int)}.
1335 *
1336 * @param viewId The id of the view whose text should change
1337 * @param color Sets the text color for all the states (normal, selected,
1338 * focused) to be this color.
1339 */
1340 public void setTextColor(int viewId, int color) {
1341 setInt(viewId, "setTextColor", color);
1342 }
1343
Joe Onorato592d0652009-03-24 22:25:52 -07001344 /**
Winson Chung499cb9f2010-07-16 11:18:17 -07001345 * Equivalent to calling {@link android.widget.AbsListView#setRemoteViewsAdapter(Intent)}.
1346 *
Winson Chung037300b2011-03-29 15:40:16 -07001347 * @param appWidgetId The id of the app widget which contains the specified view. (This
1348 * parameter is ignored in this deprecated method)
1349 * @param viewId The id of the view whose text should change
1350 * @param intent The intent of the service which will be
1351 * providing data to the RemoteViewsAdapter
1352 * @deprecated This method has been deprecated. See
1353 * {@link android.widget.RemoteViews#setRemoteAdapter(int, Intent)}
1354 */
1355 @Deprecated
1356 public void setRemoteAdapter(int appWidgetId, int viewId, Intent intent) {
1357 setRemoteAdapter(viewId, intent);
1358 }
1359
1360 /**
1361 * Equivalent to calling {@link android.widget.AbsListView#setRemoteViewsAdapter(Intent)}.
1362 * Can only be used for App Widgets.
1363 *
Winson Chung81f39eb2011-01-11 18:05:01 -08001364 * @param viewId The id of the view whose text should change
1365 * @param intent The intent of the service which will be
1366 * providing data to the RemoteViewsAdapter
1367 */
Winson Chung037300b2011-03-29 15:40:16 -07001368 public void setRemoteAdapter(int viewId, Intent intent) {
1369 addAction(new SetRemoteViewsAdapterIntent(viewId, intent));
Winson Chung499cb9f2010-07-16 11:18:17 -07001370 }
1371
1372 /**
1373 * Equivalent to calling {@link android.widget.AbsListView#smoothScrollToPosition(int, int)}.
1374 *
1375 * @param viewId The id of the view whose text should change
1376 * @param position Scroll to this adapter position
1377 */
1378 public void setScrollPosition(int viewId, int position) {
1379 setInt(viewId, "smoothScrollToPosition", position);
1380 }
1381
1382 /**
1383 * Equivalent to calling {@link android.widget.AbsListView#smoothScrollToPosition(int, int)}.
1384 *
1385 * @param viewId The id of the view whose text should change
Winson Chung95362592010-07-19 16:05:50 -07001386 * @param offset Scroll by this adapter position offset
Winson Chung499cb9f2010-07-16 11:18:17 -07001387 */
1388 public void setRelativeScrollPosition(int viewId, int offset) {
1389 setInt(viewId, "smoothScrollByOffset", offset);
1390 }
1391
1392 /**
Joe Onorato592d0652009-03-24 22:25:52 -07001393 * Call a method taking one boolean on a view in the layout for this RemoteViews.
1394 *
1395 * @param viewId The id of the view whose text should change
1396 * @param methodName The name of the method to call.
1397 * @param value The value to pass to the method.
1398 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001399 public void setBoolean(int viewId, String methodName, boolean value) {
1400 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.BOOLEAN, value));
1401 }
1402
Joe Onorato592d0652009-03-24 22:25:52 -07001403 /**
1404 * Call a method taking one byte on a view in the layout for this RemoteViews.
1405 *
1406 * @param viewId The id of the view whose text should change
1407 * @param methodName The name of the method to call.
1408 * @param value The value to pass to the method.
1409 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001410 public void setByte(int viewId, String methodName, byte value) {
1411 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.BYTE, value));
1412 }
1413
Joe Onorato592d0652009-03-24 22:25:52 -07001414 /**
1415 * Call a method taking one short on a view in the layout for this RemoteViews.
1416 *
1417 * @param viewId The id of the view whose text should change
1418 * @param methodName The name of the method to call.
1419 * @param value The value to pass to the method.
1420 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001421 public void setShort(int viewId, String methodName, short value) {
1422 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.SHORT, value));
1423 }
1424
Joe Onorato592d0652009-03-24 22:25:52 -07001425 /**
1426 * Call a method taking one int on a view in the layout for this RemoteViews.
1427 *
1428 * @param viewId The id of the view whose text should change
1429 * @param methodName The name of the method to call.
1430 * @param value The value to pass to the method.
1431 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001432 public void setInt(int viewId, String methodName, int value) {
1433 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.INT, value));
1434 }
1435
Joe Onorato592d0652009-03-24 22:25:52 -07001436 /**
1437 * Call a method taking one long on a view in the layout for this RemoteViews.
1438 *
1439 * @param viewId The id of the view whose text should change
1440 * @param methodName The name of the method to call.
1441 * @param value The value to pass to the method.
1442 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001443 public void setLong(int viewId, String methodName, long value) {
1444 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.LONG, value));
1445 }
1446
Joe Onorato592d0652009-03-24 22:25:52 -07001447 /**
1448 * Call a method taking one float on a view in the layout for this RemoteViews.
1449 *
1450 * @param viewId The id of the view whose text should change
1451 * @param methodName The name of the method to call.
1452 * @param value The value to pass to the method.
1453 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001454 public void setFloat(int viewId, String methodName, float value) {
1455 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.FLOAT, value));
1456 }
1457
Joe Onorato592d0652009-03-24 22:25:52 -07001458 /**
1459 * Call a method taking one double on a view in the layout for this RemoteViews.
1460 *
1461 * @param viewId The id of the view whose text should change
1462 * @param methodName The name of the method to call.
1463 * @param value The value to pass to the method.
1464 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001465 public void setDouble(int viewId, String methodName, double value) {
1466 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.DOUBLE, value));
1467 }
1468
Joe Onorato592d0652009-03-24 22:25:52 -07001469 /**
1470 * Call a method taking one char on a view in the layout for this RemoteViews.
1471 *
1472 * @param viewId The id of the view whose text should change
1473 * @param methodName The name of the method to call.
1474 * @param value The value to pass to the method.
1475 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001476 public void setChar(int viewId, String methodName, char value) {
1477 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.CHAR, value));
1478 }
1479
Joe Onorato592d0652009-03-24 22:25:52 -07001480 /**
1481 * Call a method taking one String on a view in the layout for this RemoteViews.
1482 *
1483 * @param viewId The id of the view whose text should change
1484 * @param methodName The name of the method to call.
1485 * @param value The value to pass to the method.
1486 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001487 public void setString(int viewId, String methodName, String value) {
1488 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.STRING, value));
1489 }
1490
Joe Onorato592d0652009-03-24 22:25:52 -07001491 /**
1492 * Call a method taking one CharSequence on a view in the layout for this RemoteViews.
1493 *
1494 * @param viewId The id of the view whose text should change
1495 * @param methodName The name of the method to call.
1496 * @param value The value to pass to the method.
1497 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001498 public void setCharSequence(int viewId, String methodName, CharSequence value) {
1499 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.CHAR_SEQUENCE, value));
1500 }
1501
Joe Onorato592d0652009-03-24 22:25:52 -07001502 /**
1503 * Call a method taking one Uri on a view in the layout for this RemoteViews.
1504 *
1505 * @param viewId The id of the view whose text should change
1506 * @param methodName The name of the method to call.
1507 * @param value The value to pass to the method.
1508 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001509 public void setUri(int viewId, String methodName, Uri value) {
1510 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.URI, value));
1511 }
1512
Joe Onorato592d0652009-03-24 22:25:52 -07001513 /**
1514 * Call a method taking one Bitmap on a view in the layout for this RemoteViews.
1515 * @more
1516 * <p class="note">The bitmap will be flattened into the parcel if this object is
1517 * sent across processes, so it may end up using a lot of memory, and may be fairly slow.</p>
1518 *
1519 * @param viewId The id of the view whose text should change
1520 * @param methodName The name of the method to call.
1521 * @param value The value to pass to the method.
1522 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001523 public void setBitmap(int viewId, String methodName, Bitmap value) {
1524 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.BITMAP, value));
1525 }
1526
1527 /**
Bjorn Bringertd755b062010-01-06 17:15:37 +00001528 * Call a method taking one Bundle on a view in the layout for this RemoteViews.
1529 *
1530 * @param viewId The id of the view whose text should change
1531 * @param methodName The name of the method to call.
1532 * @param value The value to pass to the method.
1533 */
1534 public void setBundle(int viewId, String methodName, Bundle value) {
1535 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.BUNDLE, value));
1536 }
1537
1538 /**
Winson Chung499cb9f2010-07-16 11:18:17 -07001539 *
1540 * @param viewId
1541 * @param methodName
1542 * @param value
1543 */
1544 public void setIntent(int viewId, String methodName, Intent value) {
1545 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.INTENT, value));
1546 }
1547
1548 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001549 * Inflates the view hierarchy represented by this object and applies
1550 * all of the actions.
1551 *
1552 * <p><strong>Caller beware: this may throw</strong>
1553 *
1554 * @param context Default context to use
1555 * @param parent Parent that the resulting view hierarchy will be attached to. This method
1556 * does <strong>not</strong> attach the hierarchy. The caller should do so when appropriate.
1557 * @return The inflated view hierarchy
1558 */
1559 public View apply(Context context, ViewGroup parent) {
Romain Guya5475592009-07-01 17:20:08 -07001560 View result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001561
1562 Context c = prepareContext(context);
1563
Romain Guya5475592009-07-01 17:20:08 -07001564 LayoutInflater inflater = (LayoutInflater)
1565 c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001566
1567 inflater = inflater.cloneInContext(c);
1568 inflater.setFilter(this);
1569
1570 result = inflater.inflate(mLayoutId, parent, false);
1571
Winson Chung037300b2011-03-29 15:40:16 -07001572 performApply(result, parent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001573
1574 return result;
1575 }
1576
1577 /**
1578 * Applies all of the actions to the provided view.
1579 *
1580 * <p><strong>Caller beware: this may throw</strong>
1581 *
1582 * @param v The view to apply the actions to. This should be the result of
1583 * the {@link #apply(Context,ViewGroup)} call.
1584 */
1585 public void reapply(Context context, View v) {
1586 prepareContext(context);
Winson Chung037300b2011-03-29 15:40:16 -07001587 performApply(v, (ViewGroup) v.getParent());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001588 }
1589
Winson Chung037300b2011-03-29 15:40:16 -07001590 private void performApply(View v, ViewGroup parent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001591 if (mActions != null) {
1592 final int count = mActions.size();
1593 for (int i = 0; i < count; i++) {
1594 Action a = mActions.get(i);
Winson Chung037300b2011-03-29 15:40:16 -07001595 a.apply(v, parent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001596 }
1597 }
1598 }
1599
1600 private Context prepareContext(Context context) {
Romain Guya5475592009-07-01 17:20:08 -07001601 Context c;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001602 String packageName = mPackage;
1603
1604 if (packageName != null) {
1605 try {
Romain Guy870e09f2009-07-06 16:35:25 -07001606 c = context.createPackageContext(packageName, Context.CONTEXT_RESTRICTED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001607 } catch (NameNotFoundException e) {
1608 Log.e(LOG_TAG, "Package name " + packageName + " not found");
1609 c = context;
1610 }
1611 } else {
1612 c = context;
1613 }
1614
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001615 return c;
1616 }
1617
1618 /* (non-Javadoc)
1619 * Used to restrict the views which can be inflated
1620 *
1621 * @see android.view.LayoutInflater.Filter#onLoadClass(java.lang.Class)
1622 */
Gilles Debunnee6ac8b92010-06-17 10:55:04 -07001623 public boolean onLoadClass(Class clazz) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001624 return clazz.isAnnotationPresent(RemoteView.class);
1625 }
1626
1627 public int describeContents() {
1628 return 0;
1629 }
1630
1631 public void writeToParcel(Parcel dest, int flags) {
1632 dest.writeString(mPackage);
1633 dest.writeInt(mLayoutId);
Adam Cohenca6fd842010-09-03 18:10:35 -07001634 dest.writeInt(mIsWidgetCollectionChild ? 1 : 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001635 int count;
1636 if (mActions != null) {
1637 count = mActions.size();
1638 } else {
1639 count = 0;
1640 }
1641 dest.writeInt(count);
1642 for (int i=0; i<count; i++) {
1643 Action a = mActions.get(i);
1644 a.writeToParcel(dest, 0);
1645 }
1646 }
1647
1648 /**
1649 * Parcelable.Creator that instantiates RemoteViews objects
1650 */
1651 public static final Parcelable.Creator<RemoteViews> CREATOR = new Parcelable.Creator<RemoteViews>() {
1652 public RemoteViews createFromParcel(Parcel parcel) {
1653 return new RemoteViews(parcel);
1654 }
1655
1656 public RemoteViews[] newArray(int size) {
1657 return new RemoteViews[size];
1658 }
1659 };
1660}