2 * Copyright (C) 2007 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package android.widget;
19 import android.app.PendingIntent;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.IntentSender;
23 import android.content.pm.PackageManager.NameNotFoundException;
24 import android.graphics.Bitmap;
25 import android.graphics.PorterDuff;
26 import android.graphics.Rect;
27 import android.graphics.drawable.Drawable;
28 import android.net.Uri;
29 import android.os.Bundle;
30 import android.os.Parcel;
31 import android.os.Parcelable;
32 import android.text.TextUtils;
33 import android.util.Log;
34 import android.view.LayoutInflater;
35 import android.view.RemotableViewMethod;
36 import android.view.View;
37 import android.view.ViewGroup;
38 import android.view.LayoutInflater.Filter;
39 import android.view.View.OnClickListener;
41 import java.lang.annotation.ElementType;
42 import java.lang.annotation.Retention;
43 import java.lang.annotation.RetentionPolicy;
44 import java.lang.annotation.Target;
45 import java.lang.reflect.Method;
46 import java.util.ArrayList;
50 * A class that describes a view hierarchy that can be displayed in
51 * another process. The hierarchy is inflated from a layout resource
52 * file, and this class provides some basic operations for modifying
53 * the content of the inflated hierarchy.
55 public class RemoteViews implements Parcelable, Filter {
57 private static final String LOG_TAG = "RemoteViews";
60 * The package name of the package containing the layout
61 * resource. (Added to the parcel)
63 private String mPackage;
66 * The resource ID of the layout file. (Added to the parcel)
68 private int mLayoutId;
71 * An array of actions to perform on the view tree once it has been
74 private ArrayList<Action> mActions;
78 * This annotation indicates that a subclass of View is alllowed to be used
79 * with the {@link RemoteViews} mechanism.
81 @Target({ ElementType.TYPE })
82 @Retention(RetentionPolicy.RUNTIME)
83 public @interface RemoteView {
87 * Exception to send when something goes wrong executing an action
90 public static class ActionException extends RuntimeException {
91 public ActionException(Exception ex) {
94 public ActionException(String message) {
100 * Base class for all actions that can be performed on an
103 * SUBCLASSES MUST BE IMMUTABLE SO CLONE WORKS!!!!!
105 private abstract static class Action implements Parcelable {
106 public abstract void apply(View root) throws ActionException;
108 public int describeContents() {
114 * Equivalent to calling
115 * {@link android.view.View#setOnClickListener(android.view.View.OnClickListener)}
116 * to launch the provided {@link PendingIntent}.
118 private class SetOnClickPendingIntent extends Action {
119 public SetOnClickPendingIntent(int id, PendingIntent pendingIntent) {
121 this.pendingIntent = pendingIntent;
124 public SetOnClickPendingIntent(Parcel parcel) {
125 viewId = parcel.readInt();
126 pendingIntent = PendingIntent.readPendingIntentOrNullFromParcel(parcel);
129 public void writeToParcel(Parcel dest, int flags) {
131 dest.writeInt(viewId);
132 pendingIntent.writeToParcel(dest, 0 /* no flags */);
136 public void apply(View root) {
137 final View target = root.findViewById(viewId);
138 if (target != null && pendingIntent != null) {
139 OnClickListener listener = new OnClickListener() {
140 public void onClick(View v) {
141 // Find target view location in screen coordinates and
142 // fill into PendingIntent before sending.
143 final float appScale = v.getContext().getResources()
144 .getCompatibilityInfo().applicationScale;
145 final int[] pos = new int[2];
146 v.getLocationOnScreen(pos);
148 final Rect rect = new Rect();
149 rect.left = (int) (pos[0] * appScale + 0.5f);
150 rect.top = (int) (pos[1] * appScale + 0.5f);
151 rect.right = (int) ((pos[0] + v.getWidth()) * appScale + 0.5f);
152 rect.bottom = (int) ((pos[1] + v.getHeight()) * appScale + 0.5f);
154 final Intent intent = new Intent();
155 intent.setSourceBounds(rect);
157 // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
158 v.getContext().startIntentSender(
159 pendingIntent.getIntentSender(), intent,
160 Intent.FLAG_ACTIVITY_NEW_TASK,
161 Intent.FLAG_ACTIVITY_NEW_TASK, 0);
162 } catch (IntentSender.SendIntentException e) {
163 android.util.Log.e(LOG_TAG, "Cannot send pending intent: ", e);
167 target.setOnClickListener(listener);
172 PendingIntent pendingIntent;
174 public final static int TAG = 1;
178 * Equivalent to calling a combination of {@link Drawable#setAlpha(int)},
179 * {@link Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)},
180 * and/or {@link Drawable#setLevel(int)} on the {@link Drawable} of a given view.
182 * These operations will be performed on the {@link Drawable} returned by the
183 * target {@link View#getBackground()} by default. If targetBackground is false,
184 * we assume the target is an {@link ImageView} and try applying the operations
185 * to {@link ImageView#getDrawable()}.
187 * You can omit specific calls by marking their values with null or -1.
189 private class SetDrawableParameters extends Action {
190 public SetDrawableParameters(int id, boolean targetBackground, int alpha,
191 int colorFilter, PorterDuff.Mode mode, int level) {
193 this.targetBackground = targetBackground;
195 this.colorFilter = colorFilter;
196 this.filterMode = mode;
200 public SetDrawableParameters(Parcel parcel) {
201 viewId = parcel.readInt();
202 targetBackground = parcel.readInt() != 0;
203 alpha = parcel.readInt();
204 colorFilter = parcel.readInt();
205 boolean hasMode = parcel.readInt() != 0;
207 filterMode = PorterDuff.Mode.valueOf(parcel.readString());
211 level = parcel.readInt();
214 public void writeToParcel(Parcel dest, int flags) {
216 dest.writeInt(viewId);
217 dest.writeInt(targetBackground ? 1 : 0);
218 dest.writeInt(alpha);
219 dest.writeInt(colorFilter);
220 if (filterMode != null) {
222 dest.writeString(filterMode.toString());
226 dest.writeInt(level);
230 public void apply(View root) {
231 final View target = root.findViewById(viewId);
232 if (target == null) {
236 // Pick the correct drawable to modify for this view
237 Drawable targetDrawable = null;
238 if (targetBackground) {
239 targetDrawable = target.getBackground();
240 } else if (target instanceof ImageView) {
241 ImageView imageView = (ImageView) target;
242 targetDrawable = imageView.getDrawable();
245 if (targetDrawable != null) {
246 // Perform modifications only if values are set correctly
248 targetDrawable.setAlpha(alpha);
250 if (colorFilter != -1 && filterMode != null) {
251 targetDrawable.setColorFilter(colorFilter, filterMode);
254 targetDrawable.setLevel(level);
260 boolean targetBackground;
263 PorterDuff.Mode filterMode;
266 public final static int TAG = 3;
270 * Base class for the reflection actions.
272 private class ReflectionAction extends Action {
273 static final int TAG = 2;
275 static final int BOOLEAN = 1;
276 static final int BYTE = 2;
277 static final int SHORT = 3;
278 static final int INT = 4;
279 static final int LONG = 5;
280 static final int FLOAT = 6;
281 static final int DOUBLE = 7;
282 static final int CHAR = 8;
283 static final int STRING = 9;
284 static final int CHAR_SEQUENCE = 10;
285 static final int URI = 11;
286 static final int BITMAP = 12;
287 static final int BUNDLE = 13;
294 ReflectionAction(int viewId, String methodName, int type, Object value) {
295 this.viewId = viewId;
296 this.methodName = methodName;
301 ReflectionAction(Parcel in) {
302 this.viewId = in.readInt();
303 this.methodName = in.readString();
304 this.type = in.readInt();
305 //noinspection ConstantIfStatement
307 Log.d("RemoteViews", "read viewId=0x" + Integer.toHexString(this.viewId)
308 + " methodName=" + this.methodName + " type=" + this.type);
312 this.value = in.readInt() != 0;
315 this.value = in.readByte();
318 this.value = (short)in.readInt();
321 this.value = in.readInt();
324 this.value = in.readLong();
327 this.value = in.readFloat();
330 this.value = in.readDouble();
333 this.value = (char)in.readInt();
336 this.value = in.readString();
339 this.value = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
342 this.value = Uri.CREATOR.createFromParcel(in);
345 this.value = Bitmap.CREATOR.createFromParcel(in);
348 this.value = in.readBundle();
355 public void writeToParcel(Parcel out, int flags) {
357 out.writeInt(this.viewId);
358 out.writeString(this.methodName);
359 out.writeInt(this.type);
360 //noinspection ConstantIfStatement
362 Log.d("RemoteViews", "write viewId=0x" + Integer.toHexString(this.viewId)
363 + " methodName=" + this.methodName + " type=" + this.type);
367 out.writeInt((Boolean) this.value ? 1 : 0);
370 out.writeByte((Byte) this.value);
373 out.writeInt((Short) this.value);
376 out.writeInt((Integer) this.value);
379 out.writeLong((Long) this.value);
382 out.writeFloat((Float) this.value);
385 out.writeDouble((Double) this.value);
388 out.writeInt((int)((Character)this.value).charValue());
391 out.writeString((String)this.value);
394 TextUtils.writeToParcel((CharSequence)this.value, out, flags);
397 ((Uri)this.value).writeToParcel(out, flags);
400 ((Bitmap)this.value).writeToParcel(out, flags);
403 out.writeBundle((Bundle) this.value);
410 private Class getParameterType() {
413 return boolean.class;
431 return CharSequence.class;
444 public void apply(View root) {
445 final View view = root.findViewById(viewId);
447 throw new ActionException("can't find view: 0x" + Integer.toHexString(viewId));
450 Class param = getParameterType();
452 throw new ActionException("bad type: " + this.type);
455 Class klass = view.getClass();
458 method = klass.getMethod(this.methodName, getParameterType());
460 catch (NoSuchMethodException ex) {
461 throw new ActionException("view: " + klass.getName() + " doesn't have method: "
462 + this.methodName + "(" + param.getName() + ")");
465 if (!method.isAnnotationPresent(RemotableViewMethod.class)) {
466 throw new ActionException("view: " + klass.getName()
467 + " can't use method with RemoteViews: "
468 + this.methodName + "(" + param.getName() + ")");
472 //noinspection ConstantIfStatement
474 Log.d("RemoteViews", "view: " + klass.getName() + " calling method: "
475 + this.methodName + "(" + param.getName() + ") with "
476 + (this.value == null ? "null" : this.value.getClass().getName()));
478 method.invoke(view, this.value);
480 catch (Exception ex) {
481 throw new ActionException(ex);
487 * Equivalent to calling {@link ViewGroup#addView(View)} after inflating the
488 * given {@link RemoteViews}, or calling {@link ViewGroup#removeAllViews()}
489 * when null. This allows users to build "nested" {@link RemoteViews}.
491 private class ViewGroupAction extends Action {
492 public ViewGroupAction(int viewId, RemoteViews nestedViews) {
493 this.viewId = viewId;
494 this.nestedViews = nestedViews;
497 public ViewGroupAction(Parcel parcel) {
498 viewId = parcel.readInt();
499 nestedViews = parcel.readParcelable(null);
502 public void writeToParcel(Parcel dest, int flags) {
504 dest.writeInt(viewId);
505 dest.writeParcelable(nestedViews, 0 /* no flags */);
509 public void apply(View root) {
510 final Context context = root.getContext();
511 final ViewGroup target = (ViewGroup) root.findViewById(viewId);
512 if (nestedViews != null) {
513 // Inflate nested views and add as children
514 target.addView(nestedViews.apply(context, target));
515 } else if (target != null) {
516 // Clear all children when nested views omitted
517 target.removeAllViews();
522 RemoteViews nestedViews;
524 public final static int TAG = 4;
528 * Create a new RemoteViews object that will display the views contained
529 * in the specified layout file.
531 * @param packageName Name of the package that contains the layout resource
532 * @param layoutId The id of the layout resource
534 public RemoteViews(String packageName, int layoutId) {
535 mPackage = packageName;
536 mLayoutId = layoutId;
540 * Reads a RemoteViews object from a parcel.
544 public RemoteViews(Parcel parcel) {
545 mPackage = parcel.readString();
546 mLayoutId = parcel.readInt();
547 int count = parcel.readInt();
549 mActions = new ArrayList<Action>(count);
550 for (int i=0; i<count; i++) {
551 int tag = parcel.readInt();
553 case SetOnClickPendingIntent.TAG:
554 mActions.add(new SetOnClickPendingIntent(parcel));
556 case SetDrawableParameters.TAG:
557 mActions.add(new SetDrawableParameters(parcel));
559 case ReflectionAction.TAG:
560 mActions.add(new ReflectionAction(parcel));
562 case ViewGroupAction.TAG:
563 mActions.add(new ViewGroupAction(parcel));
566 throw new ActionException("Tag " + tag + " not found");
572 public RemoteViews clone() {
573 final RemoteViews that = new RemoteViews(mPackage, mLayoutId);
574 if (mActions != null) {
575 that.mActions = (ArrayList<Action>)mActions.clone();
580 public String getPackage() {
584 public int getLayoutId() {
589 * Add an action to be executed on the remote side when apply is called.
591 * @param a The action to add
593 private void addAction(Action a) {
594 if (mActions == null) {
595 mActions = new ArrayList<Action>();
601 * Equivalent to calling {@link ViewGroup#addView(View)} after inflating the
602 * given {@link RemoteViews}. This allows users to build "nested"
603 * {@link RemoteViews}. In cases where consumers of {@link RemoteViews} may
604 * recycle layouts, use {@link #removeAllViews(int)} to clear any existing
607 * @param viewId The id of the parent {@link ViewGroup} to add child into.
608 * @param nestedView {@link RemoteViews} that describes the child.
610 public void addView(int viewId, RemoteViews nestedView) {
611 addAction(new ViewGroupAction(viewId, nestedView));
615 * Equivalent to calling {@link ViewGroup#removeAllViews()}.
617 * @param viewId The id of the parent {@link ViewGroup} to remove all
620 public void removeAllViews(int viewId) {
621 addAction(new ViewGroupAction(viewId, null));
625 * Equivalent to calling View.setVisibility
627 * @param viewId The id of the view whose visibility should change
628 * @param visibility The new visibility for the view
630 public void setViewVisibility(int viewId, int visibility) {
631 setInt(viewId, "setVisibility", visibility);
635 * Equivalent to calling TextView.setText
637 * @param viewId The id of the view whose text should change
638 * @param text The new text for the view
640 public void setTextViewText(int viewId, CharSequence text) {
641 setCharSequence(viewId, "setText", text);
645 * Equivalent to calling ImageView.setImageResource
647 * @param viewId The id of the view whose drawable should change
648 * @param srcId The new resource id for the drawable
650 public void setImageViewResource(int viewId, int srcId) {
651 setInt(viewId, "setImageResource", srcId);
655 * Equivalent to calling ImageView.setImageURI
657 * @param viewId The id of the view whose drawable should change
658 * @param uri The Uri for the image
660 public void setImageViewUri(int viewId, Uri uri) {
661 setUri(viewId, "setImageURI", uri);
665 * Equivalent to calling ImageView.setImageBitmap
667 * @param viewId The id of the view whose drawable should change
668 * @param bitmap The new Bitmap for the drawable
670 public void setImageViewBitmap(int viewId, Bitmap bitmap) {
671 setBitmap(viewId, "setImageBitmap", bitmap);
675 * Equivalent to calling {@link Chronometer#setBase Chronometer.setBase},
676 * {@link Chronometer#setFormat Chronometer.setFormat},
677 * and {@link Chronometer#start Chronometer.start()} or
678 * {@link Chronometer#stop Chronometer.stop()}.
680 * @param viewId The id of the view whose text should change
681 * @param base The time at which the timer would have read 0:00. This
682 * time should be based off of
683 * {@link android.os.SystemClock#elapsedRealtime SystemClock.elapsedRealtime()}.
684 * @param format The Chronometer format string, or null to
685 * simply display the timer value.
686 * @param started True if you want the clock to be started, false if not.
688 public void setChronometer(int viewId, long base, String format, boolean started) {
689 setLong(viewId, "setBase", base);
690 setString(viewId, "setFormat", format);
691 setBoolean(viewId, "setStarted", started);
695 * Equivalent to calling {@link ProgressBar#setMax ProgressBar.setMax},
696 * {@link ProgressBar#setProgress ProgressBar.setProgress}, and
697 * {@link ProgressBar#setIndeterminate ProgressBar.setIndeterminate}
699 * If indeterminate is true, then the values for max and progress are ignored.
701 * @param viewId The id of the view whose text should change
702 * @param max The 100% value for the progress bar
703 * @param progress The current value of the progress bar.
704 * @param indeterminate True if the progress bar is indeterminate,
707 public void setProgressBar(int viewId, int max, int progress,
708 boolean indeterminate) {
709 setBoolean(viewId, "setIndeterminate", indeterminate);
710 if (!indeterminate) {
711 setInt(viewId, "setMax", max);
712 setInt(viewId, "setProgress", progress);
717 * Equivalent to calling
718 * {@link android.view.View#setOnClickListener(android.view.View.OnClickListener)}
719 * to launch the provided {@link PendingIntent}.
721 * @param viewId The id of the view that will trigger the {@link PendingIntent} when clicked
722 * @param pendingIntent The {@link PendingIntent} to send when user clicks
724 public void setOnClickPendingIntent(int viewId, PendingIntent pendingIntent) {
725 addAction(new SetOnClickPendingIntent(viewId, pendingIntent));
730 * Equivalent to calling a combination of {@link Drawable#setAlpha(int)},
731 * {@link Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)},
732 * and/or {@link Drawable#setLevel(int)} on the {@link Drawable} of a given
735 * You can omit specific calls by marking their values with null or -1.
737 * @param viewId The id of the view that contains the target
739 * @param targetBackground If true, apply these parameters to the
740 * {@link Drawable} returned by
741 * {@link android.view.View#getBackground()}. Otherwise, assume
742 * the target view is an {@link ImageView} and apply them to
743 * {@link ImageView#getDrawable()}.
744 * @param alpha Specify an alpha value for the drawable, or -1 to leave
746 * @param colorFilter Specify a color for a
747 * {@link android.graphics.ColorFilter} for this drawable, or -1
748 * to leave unchanged.
749 * @param mode Specify a PorterDuff mode for this drawable, or null to leave
751 * @param level Specify the level for the drawable, or -1 to leave
754 public void setDrawableParameters(int viewId, boolean targetBackground, int alpha,
755 int colorFilter, PorterDuff.Mode mode, int level) {
756 addAction(new SetDrawableParameters(viewId, targetBackground, alpha,
757 colorFilter, mode, level));
761 * Equivalent to calling {@link android.widget.TextView#setTextColor(int)}.
763 * @param viewId The id of the view whose text should change
764 * @param color Sets the text color for all the states (normal, selected,
765 * focused) to be this color.
767 public void setTextColor(int viewId, int color) {
768 setInt(viewId, "setTextColor", color);
772 * Call a method taking one boolean on a view in the layout for this RemoteViews.
774 * @param viewId The id of the view whose text should change
775 * @param methodName The name of the method to call.
776 * @param value The value to pass to the method.
778 public void setBoolean(int viewId, String methodName, boolean value) {
779 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.BOOLEAN, value));
783 * Call a method taking one byte on a view in the layout for this RemoteViews.
785 * @param viewId The id of the view whose text should change
786 * @param methodName The name of the method to call.
787 * @param value The value to pass to the method.
789 public void setByte(int viewId, String methodName, byte value) {
790 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.BYTE, value));
794 * Call a method taking one short on a view in the layout for this RemoteViews.
796 * @param viewId The id of the view whose text should change
797 * @param methodName The name of the method to call.
798 * @param value The value to pass to the method.
800 public void setShort(int viewId, String methodName, short value) {
801 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.SHORT, value));
805 * Call a method taking one int on a view in the layout for this RemoteViews.
807 * @param viewId The id of the view whose text should change
808 * @param methodName The name of the method to call.
809 * @param value The value to pass to the method.
811 public void setInt(int viewId, String methodName, int value) {
812 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.INT, value));
816 * Call a method taking one long on a view in the layout for this RemoteViews.
818 * @param viewId The id of the view whose text should change
819 * @param methodName The name of the method to call.
820 * @param value The value to pass to the method.
822 public void setLong(int viewId, String methodName, long value) {
823 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.LONG, value));
827 * Call a method taking one float on a view in the layout for this RemoteViews.
829 * @param viewId The id of the view whose text should change
830 * @param methodName The name of the method to call.
831 * @param value The value to pass to the method.
833 public void setFloat(int viewId, String methodName, float value) {
834 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.FLOAT, value));
838 * Call a method taking one double on a view in the layout for this RemoteViews.
840 * @param viewId The id of the view whose text should change
841 * @param methodName The name of the method to call.
842 * @param value The value to pass to the method.
844 public void setDouble(int viewId, String methodName, double value) {
845 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.DOUBLE, value));
849 * Call a method taking one char on a view in the layout for this RemoteViews.
851 * @param viewId The id of the view whose text should change
852 * @param methodName The name of the method to call.
853 * @param value The value to pass to the method.
855 public void setChar(int viewId, String methodName, char value) {
856 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.CHAR, value));
860 * Call a method taking one String on a view in the layout for this RemoteViews.
862 * @param viewId The id of the view whose text should change
863 * @param methodName The name of the method to call.
864 * @param value The value to pass to the method.
866 public void setString(int viewId, String methodName, String value) {
867 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.STRING, value));
871 * Call a method taking one CharSequence on a view in the layout for this RemoteViews.
873 * @param viewId The id of the view whose text should change
874 * @param methodName The name of the method to call.
875 * @param value The value to pass to the method.
877 public void setCharSequence(int viewId, String methodName, CharSequence value) {
878 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.CHAR_SEQUENCE, value));
882 * Call a method taking one Uri on a view in the layout for this RemoteViews.
884 * @param viewId The id of the view whose text should change
885 * @param methodName The name of the method to call.
886 * @param value The value to pass to the method.
888 public void setUri(int viewId, String methodName, Uri value) {
889 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.URI, value));
893 * Call a method taking one Bitmap on a view in the layout for this RemoteViews.
895 * <p class="note">The bitmap will be flattened into the parcel if this object is
896 * sent across processes, so it may end up using a lot of memory, and may be fairly slow.</p>
898 * @param viewId The id of the view whose text should change
899 * @param methodName The name of the method to call.
900 * @param value The value to pass to the method.
902 public void setBitmap(int viewId, String methodName, Bitmap value) {
903 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.BITMAP, value));
907 * Call a method taking one Bundle on a view in the layout for this RemoteViews.
909 * @param viewId The id of the view whose text should change
910 * @param methodName The name of the method to call.
911 * @param value The value to pass to the method.
913 public void setBundle(int viewId, String methodName, Bundle value) {
914 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.BUNDLE, value));
918 * Inflates the view hierarchy represented by this object and applies
919 * all of the actions.
921 * <p><strong>Caller beware: this may throw</strong>
923 * @param context Default context to use
924 * @param parent Parent that the resulting view hierarchy will be attached to. This method
925 * does <strong>not</strong> attach the hierarchy. The caller should do so when appropriate.
926 * @return The inflated view hierarchy
928 public View apply(Context context, ViewGroup parent) {
931 Context c = prepareContext(context);
933 LayoutInflater inflater = (LayoutInflater)
934 c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
936 inflater = inflater.cloneInContext(c);
937 inflater.setFilter(this);
939 result = inflater.inflate(mLayoutId, parent, false);
941 performApply(result);
947 * Applies all of the actions to the provided view.
949 * <p><strong>Caller beware: this may throw</strong>
951 * @param v The view to apply the actions to. This should be the result of
952 * the {@link #apply(Context,ViewGroup)} call.
954 public void reapply(Context context, View v) {
955 prepareContext(context);
959 private void performApply(View v) {
960 if (mActions != null) {
961 final int count = mActions.size();
962 for (int i = 0; i < count; i++) {
963 Action a = mActions.get(i);
969 private Context prepareContext(Context context) {
971 String packageName = mPackage;
973 if (packageName != null) {
975 c = context.createPackageContext(packageName, Context.CONTEXT_RESTRICTED);
976 } catch (NameNotFoundException e) {
977 Log.e(LOG_TAG, "Package name " + packageName + " not found");
988 * Used to restrict the views which can be inflated
990 * @see android.view.LayoutInflater.Filter#onLoadClass(java.lang.Class)
992 public boolean onLoadClass(Class clazz) {
993 return clazz.isAnnotationPresent(RemoteView.class);
996 public int describeContents() {
1000 public void writeToParcel(Parcel dest, int flags) {
1001 dest.writeString(mPackage);
1002 dest.writeInt(mLayoutId);
1004 if (mActions != null) {
1005 count = mActions.size();
1009 dest.writeInt(count);
1010 for (int i=0; i<count; i++) {
1011 Action a = mActions.get(i);
1012 a.writeToParcel(dest, 0);
1017 * Parcelable.Creator that instantiates RemoteViews objects
1019 public static final Parcelable.Creator<RemoteViews> CREATOR = new Parcelable.Creator<RemoteViews>() {
1020 public RemoteViews createFromParcel(Parcel parcel) {
1021 return new RemoteViews(parcel);
1024 public RemoteViews[] newArray(int size) {
1025 return new RemoteViews[size];