blob: 529a09a467b10b4254091adcae39e4e207e2261f [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
Winson Chungdc6f79b2012-04-17 17:27:31 -070019import android.app.ActivityOptions;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import android.app.PendingIntent;
Adam Cohen1480fdd2010-08-25 17:24:53 -070021import android.appwidget.AppWidgetHostView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.content.Context;
Dianne Hackbornfa82f222009-09-17 15:14:12 -070023import android.content.Intent;
24import android.content.IntentSender;
Adam Cohenffc46a52012-04-30 19:54:39 -070025import android.content.pm.ApplicationInfo;
26import android.content.pm.PackageManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027import android.content.pm.PackageManager.NameNotFoundException;
Adam Cohen5d200642012-04-24 10:43:31 -070028import android.content.res.Configuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.graphics.Bitmap;
30import android.graphics.PorterDuff;
Joe Onorato75970652009-12-02 23:04:55 -080031import android.graphics.Rect;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.graphics.drawable.Drawable;
33import android.net.Uri;
Adam Cohenffc46a52012-04-30 19:54:39 -070034import android.os.Build;
Bjorn Bringertd755b062010-01-06 17:15:37 +000035import android.os.Bundle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.os.Parcel;
37import android.os.Parcelable;
38import android.text.TextUtils;
39import android.util.Log;
Daniel Sandler7264f712012-05-21 14:48:23 -040040import android.util.TypedValue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.view.LayoutInflater;
Winson Chungdc6f79b2012-04-17 17:27:31 -070042import android.view.LayoutInflater.Filter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.view.RemotableViewMethod;
44import android.view.View;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.view.View.OnClickListener;
Winson Chungdc6f79b2012-04-17 17:27:31 -070046import android.view.ViewGroup;
Adam Cohena32edd42010-10-26 10:35:01 -070047import android.widget.AdapterView.OnItemClickListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048
Winson Chungdc6f79b2012-04-17 17:27:31 -070049import java.lang.annotation.ElementType;
50import java.lang.annotation.Retention;
51import java.lang.annotation.RetentionPolicy;
52import java.lang.annotation.Target;
53import java.lang.reflect.Method;
54import java.util.ArrayList;
55
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056
57/**
58 * A class that describes a view hierarchy that can be displayed in
59 * another process. The hierarchy is inflated from a layout resource
60 * file, and this class provides some basic operations for modifying
61 * the content of the inflated hierarchy.
62 */
63public class RemoteViews implements Parcelable, Filter {
64
65 private static final String LOG_TAG = "RemoteViews";
66
67 /**
Winson Chung81f39eb2011-01-11 18:05:01 -080068 * The intent extra that contains the appWidgetId.
69 * @hide
70 */
71 static final String EXTRA_REMOTEADAPTER_APPWIDGET_ID = "remoteAdapterAppWidgetId";
72
73 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074 * The package name of the package containing the layout
75 * resource. (Added to the parcel)
76 */
Gilles Debunne30301932010-06-16 18:32:00 -070077 private final String mPackage;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078
79 /**
80 * The resource ID of the layout file. (Added to the parcel)
81 */
Gilles Debunne30301932010-06-16 18:32:00 -070082 private final int mLayoutId;
Romain Guya5475592009-07-01 17:20:08 -070083
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084 /**
85 * An array of actions to perform on the view tree once it has been
86 * inflated
87 */
88 private ArrayList<Action> mActions;
89
Winson Chung3ec9a452010-09-23 16:40:28 -070090 /**
91 * A class to keep track of memory usage by this RemoteViews
92 */
93 private MemoryUsageCounter mMemoryUsageCounter;
94
Adam Cohen5d200642012-04-24 10:43:31 -070095 /**
96 * Maps bitmaps to unique indicies to avoid Bitmap duplication.
97 */
98 private BitmapCache mBitmapCache;
99
100 /**
101 * Indicates whether or not this RemoteViews object is contained as a child of any other
102 * RemoteViews.
103 */
104 private boolean mIsRoot = true;
105
106 /**
107 * Constants to whether or not this RemoteViews is composed of a landscape and portrait
108 * RemoteViews.
109 */
110 private static final int MODE_NORMAL = 0;
111 private static final int MODE_HAS_LANDSCAPE_AND_PORTRAIT = 1;
112
113 /**
114 * Used in conjunction with the special constructor
115 * {@link #RemoteViews(RemoteViews, RemoteViews)} to keep track of the landscape and portrait
116 * RemoteViews.
117 */
118 private RemoteViews mLandscape = null;
119 private RemoteViews mPortrait = null;
120
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121 /**
Adam Cohenca6fd842010-09-03 18:10:35 -0700122 * This flag indicates whether this RemoteViews object is being created from a
123 * RemoteViewsService for use as a child of a widget collection. This flag is used
124 * to determine whether or not certain features are available, in particular,
125 * setting on click extras and setting on click pending intents. The former is enabled,
126 * and the latter disabled when this flag is true.
127 */
128 private boolean mIsWidgetCollectionChild = false;
129
130 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131 * This annotation indicates that a subclass of View is alllowed to be used
Romain Guya5475592009-07-01 17:20:08 -0700132 * with the {@link RemoteViews} mechanism.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 */
134 @Target({ ElementType.TYPE })
135 @Retention(RetentionPolicy.RUNTIME)
136 public @interface RemoteView {
137 }
138
139 /**
140 * Exception to send when something goes wrong executing an action
141 *
142 */
143 public static class ActionException extends RuntimeException {
144 public ActionException(Exception ex) {
145 super(ex);
146 }
147 public ActionException(String message) {
148 super(message);
149 }
150 }
Adam Cohena32edd42010-10-26 10:35:01 -0700151
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 /**
153 * Base class for all actions that can be performed on an
154 * inflated view.
155 *
Joe Onorato18e69df2010-05-17 22:26:12 -0700156 * SUBCLASSES MUST BE IMMUTABLE SO CLONE WORKS!!!!!
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157 */
158 private abstract static class Action implements Parcelable {
Winson Chung037300b2011-03-29 15:40:16 -0700159 public abstract void apply(View root, ViewGroup rootParent) throws ActionException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160
161 public int describeContents() {
162 return 0;
163 }
Winson Chung3ec9a452010-09-23 16:40:28 -0700164
165 /**
166 * Overridden by each class to report on it's own memory usage
167 */
168 public void updateMemoryUsageEstimate(MemoryUsageCounter counter) {
169 // We currently only calculate Bitmap memory usage, so by default, don't do anything
170 // here
171 return;
172 }
Winson Chungae615982010-11-01 12:14:49 -0700173
Winson Chungdc6f79b2012-04-17 17:27:31 -0700174 protected boolean startIntentSafely(View view, PendingIntent pendingIntent,
Winson Chungae615982010-11-01 12:14:49 -0700175 Intent fillInIntent) {
176 try {
177 // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
Winson Chungdc6f79b2012-04-17 17:27:31 -0700178 Context context = view.getContext();
179 ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(view,
180 0, 0,
181 view.getMeasuredWidth(), view.getMeasuredHeight());
Winson Chungae615982010-11-01 12:14:49 -0700182 context.startIntentSender(
183 pendingIntent.getIntentSender(), fillInIntent,
184 Intent.FLAG_ACTIVITY_NEW_TASK,
Winson Chungdc6f79b2012-04-17 17:27:31 -0700185 Intent.FLAG_ACTIVITY_NEW_TASK, 0, opts.toBundle());
Winson Chungae615982010-11-01 12:14:49 -0700186 } catch (IntentSender.SendIntentException e) {
187 android.util.Log.e(LOG_TAG, "Cannot send pending intent: ", e);
188 return false;
189 } catch (Exception e) {
190 android.util.Log.e(LOG_TAG, "Cannot send pending intent due to " +
191 "unknown exception: ", e);
192 return false;
193 }
194 return true;
195 }
Adam Cohen5d200642012-04-24 10:43:31 -0700196
197 public void setBitmapCache(BitmapCache bitmapCache) {
198 // Do nothing
199 }
Romain Guya5475592009-07-01 17:20:08 -0700200 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201
Adam Cohen1480fdd2010-08-25 17:24:53 -0700202 private class SetEmptyView extends Action {
203 int viewId;
204 int emptyViewId;
205
206 public final static int TAG = 6;
207
208 SetEmptyView(int viewId, int emptyViewId) {
209 this.viewId = viewId;
210 this.emptyViewId = emptyViewId;
211 }
212
213 SetEmptyView(Parcel in) {
214 this.viewId = in.readInt();
215 this.emptyViewId = in.readInt();
216 }
217
218 public void writeToParcel(Parcel out, int flags) {
219 out.writeInt(TAG);
220 out.writeInt(this.viewId);
221 out.writeInt(this.emptyViewId);
222 }
223
224 @Override
Winson Chung037300b2011-03-29 15:40:16 -0700225 public void apply(View root, ViewGroup rootParent) {
Adam Cohen1480fdd2010-08-25 17:24:53 -0700226 final View view = root.findViewById(viewId);
227 if (!(view instanceof AdapterView<?>)) return;
228
229 AdapterView<?> adapterView = (AdapterView<?>) view;
230
231 final View emptyView = root.findViewById(emptyViewId);
232 if (emptyView == null) return;
233
234 adapterView.setEmptyView(emptyView);
235 }
236 }
237
Adam Cohen35ae9ca2010-09-20 15:20:41 -0700238 private class SetOnClickFillInIntent extends Action {
239 public SetOnClickFillInIntent(int id, Intent fillInIntent) {
240 this.viewId = id;
241 this.fillInIntent = fillInIntent;
242 }
243
244 public SetOnClickFillInIntent(Parcel parcel) {
245 viewId = parcel.readInt();
246 fillInIntent = Intent.CREATOR.createFromParcel(parcel);
247 }
248
249 public void writeToParcel(Parcel dest, int flags) {
250 dest.writeInt(TAG);
251 dest.writeInt(viewId);
252 fillInIntent.writeToParcel(dest, 0 /* no flags */);
253 }
254
255 @Override
Winson Chung037300b2011-03-29 15:40:16 -0700256 public void apply(View root, ViewGroup rootParent) {
Adam Cohen35ae9ca2010-09-20 15:20:41 -0700257 final View target = root.findViewById(viewId);
Joe Onorato2b69ce42010-10-31 11:35:41 -0700258 if (target == null) return;
Adam Cohen35ae9ca2010-09-20 15:20:41 -0700259
260 if (!mIsWidgetCollectionChild) {
261 Log.e("RemoteViews", "The method setOnClickFillInIntent is available " +
262 "only from RemoteViewsFactory (ie. on collection items).");
263 return;
264 }
Adam Cohena32edd42010-10-26 10:35:01 -0700265 if (target == root) {
266 target.setTagInternal(com.android.internal.R.id.fillInIntent, fillInIntent);
267 } else if (target != null && fillInIntent != null) {
Adam Cohen35ae9ca2010-09-20 15:20:41 -0700268 OnClickListener listener = new OnClickListener() {
269 public void onClick(View v) {
270 // Insure that this view is a child of an AdapterView
271 View parent = (View) v.getParent();
272 while (!(parent instanceof AdapterView<?>)
273 && !(parent instanceof AppWidgetHostView)) {
274 parent = (View) parent.getParent();
275 }
276
277 if (parent instanceof AppWidgetHostView) {
278 // Somehow they've managed to get this far without having
279 // and AdapterView as a parent.
280 Log.e("RemoteViews", "Collection item doesn't have AdapterView parent");
281 return;
282 }
283
284 // Insure that a template pending intent has been set on an ancestor
285 if (!(parent.getTag() instanceof PendingIntent)) {
286 Log.e("RemoteViews", "Attempting setOnClickFillInIntent without" +
Adam Cohena32edd42010-10-26 10:35:01 -0700287 " calling setPendingIntentTemplate on parent.");
Adam Cohen35ae9ca2010-09-20 15:20:41 -0700288 return;
289 }
290
291 PendingIntent pendingIntent = (PendingIntent) parent.getTag();
292
293 final float appScale = v.getContext().getResources()
Adam Cohena32edd42010-10-26 10:35:01 -0700294 .getCompatibilityInfo().applicationScale;
Adam Cohen35ae9ca2010-09-20 15:20:41 -0700295 final int[] pos = new int[2];
296 v.getLocationOnScreen(pos);
297
298 final Rect rect = new Rect();
299 rect.left = (int) (pos[0] * appScale + 0.5f);
300 rect.top = (int) (pos[1] * appScale + 0.5f);
301 rect.right = (int) ((pos[0] + v.getWidth()) * appScale + 0.5f);
302 rect.bottom = (int) ((pos[1] + v.getHeight()) * appScale + 0.5f);
303
304 fillInIntent.setSourceBounds(rect);
Winson Chungdc6f79b2012-04-17 17:27:31 -0700305 startIntentSafely(v, pendingIntent, fillInIntent);
Adam Cohen35ae9ca2010-09-20 15:20:41 -0700306 }
307
308 };
309 target.setOnClickListener(listener);
310 }
311 }
312
313 int viewId;
314 Intent fillInIntent;
315
316 public final static int TAG = 9;
317 }
318
Adam Cohenca6fd842010-09-03 18:10:35 -0700319 private class SetPendingIntentTemplate extends Action {
320 public SetPendingIntentTemplate(int id, PendingIntent pendingIntentTemplate) {
321 this.viewId = id;
322 this.pendingIntentTemplate = pendingIntentTemplate;
323 }
324
325 public SetPendingIntentTemplate(Parcel parcel) {
326 viewId = parcel.readInt();
327 pendingIntentTemplate = PendingIntent.readPendingIntentOrNullFromParcel(parcel);
328 }
329
330 public void writeToParcel(Parcel dest, int flags) {
331 dest.writeInt(TAG);
332 dest.writeInt(viewId);
333 pendingIntentTemplate.writeToParcel(dest, 0 /* no flags */);
334 }
335
336 @Override
Winson Chung037300b2011-03-29 15:40:16 -0700337 public void apply(View root, ViewGroup rootParent) {
Adam Cohenca6fd842010-09-03 18:10:35 -0700338 final View target = root.findViewById(viewId);
Joe Onorato2b69ce42010-10-31 11:35:41 -0700339 if (target == null) return;
Adam Cohenca6fd842010-09-03 18:10:35 -0700340
341 // If the view isn't an AdapterView, setting a PendingIntent template doesn't make sense
342 if (target instanceof AdapterView<?>) {
Adam Cohena32edd42010-10-26 10:35:01 -0700343 AdapterView<?> av = (AdapterView<?>) target;
Adam Cohenca6fd842010-09-03 18:10:35 -0700344 // The PendingIntent template is stored in the view's tag.
Adam Cohena32edd42010-10-26 10:35:01 -0700345 OnItemClickListener listener = new OnItemClickListener() {
346 public void onItemClick(AdapterView<?> parent, View view,
347 int position, long id) {
348 // The view should be a frame layout
349 if (view instanceof ViewGroup) {
350 ViewGroup vg = (ViewGroup) view;
351
352 // AdapterViews contain their children in a frame
353 // so we need to go one layer deeper here.
354 if (parent instanceof AdapterViewAnimator) {
355 vg = (ViewGroup) vg.getChildAt(0);
356 }
357 if (vg == null) return;
358
359 Intent fillInIntent = null;
360 int childCount = vg.getChildCount();
361 for (int i = 0; i < childCount; i++) {
362 Object tag = vg.getChildAt(i).getTag(com.android.internal.R.id.fillInIntent);
363 if (tag instanceof Intent) {
364 fillInIntent = (Intent) tag;
365 break;
366 }
367 }
368 if (fillInIntent == null) return;
369
370 final float appScale = view.getContext().getResources()
371 .getCompatibilityInfo().applicationScale;
372 final int[] pos = new int[2];
373 view.getLocationOnScreen(pos);
374
375 final Rect rect = new Rect();
376 rect.left = (int) (pos[0] * appScale + 0.5f);
377 rect.top = (int) (pos[1] * appScale + 0.5f);
378 rect.right = (int) ((pos[0] + view.getWidth()) * appScale + 0.5f);
379 rect.bottom = (int) ((pos[1] + view.getHeight()) * appScale + 0.5f);
380
381 final Intent intent = new Intent();
382 intent.setSourceBounds(rect);
Winson Chungdc6f79b2012-04-17 17:27:31 -0700383 startIntentSafely(view, pendingIntentTemplate, fillInIntent);
Adam Cohena32edd42010-10-26 10:35:01 -0700384 }
385 }
386 };
387 av.setOnItemClickListener(listener);
388 av.setTag(pendingIntentTemplate);
Adam Cohenca6fd842010-09-03 18:10:35 -0700389 } else {
390 Log.e("RemoteViews", "Cannot setPendingIntentTemplate on a view which is not" +
Adam Cohen35ae9ca2010-09-20 15:20:41 -0700391 "an AdapterView (id: " + viewId + ")");
Adam Cohenca6fd842010-09-03 18:10:35 -0700392 return;
393 }
394 }
395
396 int viewId;
397 PendingIntent pendingIntentTemplate;
398
399 public final static int TAG = 8;
400 }
401
Winson Chung037300b2011-03-29 15:40:16 -0700402 private class SetRemoteViewsAdapterIntent extends Action {
403 public SetRemoteViewsAdapterIntent(int id, Intent intent) {
404 this.viewId = id;
405 this.intent = intent;
406 }
407
408 public SetRemoteViewsAdapterIntent(Parcel parcel) {
409 viewId = parcel.readInt();
410 intent = Intent.CREATOR.createFromParcel(parcel);
411 }
412
413 public void writeToParcel(Parcel dest, int flags) {
414 dest.writeInt(TAG);
415 dest.writeInt(viewId);
416 intent.writeToParcel(dest, flags);
417 }
418
419 @Override
420 public void apply(View root, ViewGroup rootParent) {
421 final View target = root.findViewById(viewId);
422 if (target == null) return;
423
424 // Ensure that we are applying to an AppWidget root
425 if (!(rootParent instanceof AppWidgetHostView)) {
426 Log.e("RemoteViews", "SetRemoteViewsAdapterIntent action can only be used for " +
427 "AppWidgets (root id: " + viewId + ")");
428 return;
429 }
430 // Ensure that we are calling setRemoteAdapter on an AdapterView that supports it
431 if (!(target instanceof AbsListView) && !(target instanceof AdapterViewAnimator)) {
432 Log.e("RemoteViews", "Cannot setRemoteViewsAdapter on a view which is not " +
433 "an AbsListView or AdapterViewAnimator (id: " + viewId + ")");
434 return;
435 }
436
437 // Embed the AppWidget Id for use in RemoteViewsAdapter when connecting to the intent
438 // RemoteViewsService
439 AppWidgetHostView host = (AppWidgetHostView) rootParent;
440 intent.putExtra(EXTRA_REMOTEADAPTER_APPWIDGET_ID, host.getAppWidgetId());
441 if (target instanceof AbsListView) {
442 AbsListView v = (AbsListView) target;
443 v.setRemoteViewsAdapter(intent);
444 } else if (target instanceof AdapterViewAnimator) {
445 AdapterViewAnimator v = (AdapterViewAnimator) target;
446 v.setRemoteViewsAdapter(intent);
447 }
448 }
449
450 int viewId;
451 Intent intent;
452
453 public final static int TAG = 10;
454 }
455
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800456 /**
457 * Equivalent to calling
458 * {@link android.view.View#setOnClickListener(android.view.View.OnClickListener)}
459 * to launch the provided {@link PendingIntent}.
460 */
461 private class SetOnClickPendingIntent extends Action {
462 public SetOnClickPendingIntent(int id, PendingIntent pendingIntent) {
463 this.viewId = id;
464 this.pendingIntent = pendingIntent;
465 }
Adam Cohenca6fd842010-09-03 18:10:35 -0700466
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800467 public SetOnClickPendingIntent(Parcel parcel) {
468 viewId = parcel.readInt();
Adam Cohenc6151f22012-02-02 21:02:31 -0800469
470 // We check a flag to determine if the parcel contains a PendingIntent.
471 if (parcel.readInt() != 0) {
472 pendingIntent = PendingIntent.readPendingIntentOrNullFromParcel(parcel);
473 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800474 }
Adam Cohenca6fd842010-09-03 18:10:35 -0700475
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 public void writeToParcel(Parcel dest, int flags) {
477 dest.writeInt(TAG);
478 dest.writeInt(viewId);
Adam Cohenc6151f22012-02-02 21:02:31 -0800479
480 // We use a flag to indicate whether the parcel contains a valid object.
481 dest.writeInt(pendingIntent != null ? 1 : 0);
482 if (pendingIntent != null) {
483 pendingIntent.writeToParcel(dest, 0 /* no flags */);
484 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800485 }
Adam Cohenca6fd842010-09-03 18:10:35 -0700486
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800487 @Override
Winson Chung037300b2011-03-29 15:40:16 -0700488 public void apply(View root, ViewGroup rootParent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489 final View target = root.findViewById(viewId);
Joe Onorato2b69ce42010-10-31 11:35:41 -0700490 if (target == null) return;
Adam Cohenca6fd842010-09-03 18:10:35 -0700491
492 // If the view is an AdapterView, setting a PendingIntent on click doesn't make much
493 // sense, do they mean to set a PendingIntent template for the AdapterView's children?
494 if (mIsWidgetCollectionChild) {
Adam Cohen35ae9ca2010-09-20 15:20:41 -0700495 Log.e("RemoteViews", "Cannot setOnClickPendingIntent for collection item " +
Adam Cohenc6151f22012-02-02 21:02:31 -0800496 "(id: " + viewId + ")");
Adam Cohenffc46a52012-04-30 19:54:39 -0700497 ApplicationInfo appInfo = root.getContext().getApplicationInfo();
498
499 // We let this slide for HC and ICS so as to not break compatibility. It should have
500 // been disabled from the outset, but was left open by accident.
501 if (appInfo != null &&
502 appInfo.targetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN) {
503 return;
504 }
Adam Cohenca6fd842010-09-03 18:10:35 -0700505 }
506
Adam Cohenc6151f22012-02-02 21:02:31 -0800507 if (target != null) {
508 // If the pendingIntent is null, we clear the onClickListener
509 OnClickListener listener = null;
510 if (pendingIntent != null) {
511 listener = new OnClickListener() {
512 public void onClick(View v) {
513 // Find target view location in screen coordinates and
514 // fill into PendingIntent before sending.
515 final float appScale = v.getContext().getResources()
516 .getCompatibilityInfo().applicationScale;
517 final int[] pos = new int[2];
518 v.getLocationOnScreen(pos);
519
520 final Rect rect = new Rect();
521 rect.left = (int) (pos[0] * appScale + 0.5f);
522 rect.top = (int) (pos[1] * appScale + 0.5f);
523 rect.right = (int) ((pos[0] + v.getWidth()) * appScale + 0.5f);
524 rect.bottom = (int) ((pos[1] + v.getHeight()) * appScale + 0.5f);
525
526 final Intent intent = new Intent();
527 intent.setSourceBounds(rect);
Winson Chungdc6f79b2012-04-17 17:27:31 -0700528 startIntentSafely(v, pendingIntent, intent);
Adam Cohenc6151f22012-02-02 21:02:31 -0800529 }
530 };
531 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800532 target.setOnClickListener(listener);
533 }
534 }
Adam Cohenc6151f22012-02-02 21:02:31 -0800535
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800536 int viewId;
537 PendingIntent pendingIntent;
538
539 public final static int TAG = 1;
540 }
541
542 /**
543 * Equivalent to calling a combination of {@link Drawable#setAlpha(int)},
544 * {@link Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)},
545 * and/or {@link Drawable#setLevel(int)} on the {@link Drawable} of a given view.
546 * <p>
547 * These operations will be performed on the {@link Drawable} returned by the
548 * target {@link View#getBackground()} by default. If targetBackground is false,
549 * we assume the target is an {@link ImageView} and try applying the operations
550 * to {@link ImageView#getDrawable()}.
551 * <p>
552 * You can omit specific calls by marking their values with null or -1.
553 */
554 private class SetDrawableParameters extends Action {
555 public SetDrawableParameters(int id, boolean targetBackground, int alpha,
556 int colorFilter, PorterDuff.Mode mode, int level) {
557 this.viewId = id;
558 this.targetBackground = targetBackground;
559 this.alpha = alpha;
560 this.colorFilter = colorFilter;
561 this.filterMode = mode;
562 this.level = level;
563 }
564
565 public SetDrawableParameters(Parcel parcel) {
566 viewId = parcel.readInt();
567 targetBackground = parcel.readInt() != 0;
568 alpha = parcel.readInt();
569 colorFilter = parcel.readInt();
570 boolean hasMode = parcel.readInt() != 0;
571 if (hasMode) {
572 filterMode = PorterDuff.Mode.valueOf(parcel.readString());
573 } else {
574 filterMode = null;
575 }
576 level = parcel.readInt();
577 }
578
579 public void writeToParcel(Parcel dest, int flags) {
580 dest.writeInt(TAG);
581 dest.writeInt(viewId);
582 dest.writeInt(targetBackground ? 1 : 0);
583 dest.writeInt(alpha);
584 dest.writeInt(colorFilter);
585 if (filterMode != null) {
586 dest.writeInt(1);
587 dest.writeString(filterMode.toString());
588 } else {
589 dest.writeInt(0);
590 }
591 dest.writeInt(level);
592 }
593
594 @Override
Winson Chung037300b2011-03-29 15:40:16 -0700595 public void apply(View root, ViewGroup rootParent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596 final View target = root.findViewById(viewId);
Joe Onorato2b69ce42010-10-31 11:35:41 -0700597 if (target == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598
599 // Pick the correct drawable to modify for this view
600 Drawable targetDrawable = null;
601 if (targetBackground) {
602 targetDrawable = target.getBackground();
603 } else if (target instanceof ImageView) {
604 ImageView imageView = (ImageView) target;
605 targetDrawable = imageView.getDrawable();
606 }
607
Romain Guya5475592009-07-01 17:20:08 -0700608 if (targetDrawable != null) {
609 // Perform modifications only if values are set correctly
610 if (alpha != -1) {
611 targetDrawable.setAlpha(alpha);
612 }
613 if (colorFilter != -1 && filterMode != null) {
614 targetDrawable.setColorFilter(colorFilter, filterMode);
615 }
616 if (level != -1) {
617 targetDrawable.setLevel(level);
618 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800619 }
620 }
Winson Chung3ec9a452010-09-23 16:40:28 -0700621
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800622 int viewId;
623 boolean targetBackground;
624 int alpha;
625 int colorFilter;
626 PorterDuff.Mode filterMode;
627 int level;
628
629 public final static int TAG = 3;
630 }
631
Adam Cohen2dd21972010-08-15 18:20:04 -0700632 private class ReflectionActionWithoutParams extends Action {
633 int viewId;
634 String methodName;
635
636 public final static int TAG = 5;
637
638 ReflectionActionWithoutParams(int viewId, String methodName) {
639 this.viewId = viewId;
640 this.methodName = methodName;
641 }
642
643 ReflectionActionWithoutParams(Parcel in) {
644 this.viewId = in.readInt();
645 this.methodName = in.readString();
646 }
647
648 public void writeToParcel(Parcel out, int flags) {
649 out.writeInt(TAG);
650 out.writeInt(this.viewId);
651 out.writeString(this.methodName);
652 }
653
654 @Override
Winson Chung037300b2011-03-29 15:40:16 -0700655 public void apply(View root, ViewGroup rootParent) {
Adam Cohen2dd21972010-08-15 18:20:04 -0700656 final View view = root.findViewById(viewId);
Joe Onorato2b69ce42010-10-31 11:35:41 -0700657 if (view == null) return;
Adam Cohen2dd21972010-08-15 18:20:04 -0700658
659 Class klass = view.getClass();
660 Method method;
661 try {
662 method = klass.getMethod(this.methodName);
663 } catch (NoSuchMethodException ex) {
664 throw new ActionException("view: " + klass.getName() + " doesn't have method: "
665 + this.methodName + "()");
666 }
667
668 if (!method.isAnnotationPresent(RemotableViewMethod.class)) {
669 throw new ActionException("view: " + klass.getName()
670 + " can't use method with RemoteViews: "
671 + this.methodName + "()");
672 }
673
674 try {
675 //noinspection ConstantIfStatement
676 if (false) {
677 Log.d("RemoteViews", "view: " + klass.getName() + " calling method: "
678 + this.methodName + "()");
679 }
680 method.invoke(view);
681 } catch (Exception ex) {
682 throw new ActionException(ex);
683 }
684 }
685 }
686
Adam Cohen5d200642012-04-24 10:43:31 -0700687 private static class BitmapCache {
688 ArrayList<Bitmap> mBitmaps;
689
690 public BitmapCache() {
691 mBitmaps = new ArrayList<Bitmap>();
692 }
693
694 public BitmapCache(Parcel source) {
695 int count = source.readInt();
696 mBitmaps = new ArrayList<Bitmap>();
697 for (int i = 0; i < count; i++) {
698 Bitmap b = Bitmap.CREATOR.createFromParcel(source);
699 mBitmaps.add(b);
700 }
701 }
702
703 public int getBitmapId(Bitmap b) {
704 if (b == null) {
705 return -1;
706 } else {
707 if (mBitmaps.contains(b)) {
708 return mBitmaps.indexOf(b);
709 } else {
710 mBitmaps.add(b);
711 return (mBitmaps.size() - 1);
712 }
713 }
714 }
715
716 public Bitmap getBitmapForId(int id) {
717 if (id == -1 || id >= mBitmaps.size()) {
718 return null;
719 } else {
720 return mBitmaps.get(id);
721 }
722 }
723
724 public void writeBitmapsToParcel(Parcel dest, int flags) {
725 int count = mBitmaps.size();
726 dest.writeInt(count);
727 for (int i = 0; i < count; i++) {
728 mBitmaps.get(i).writeToParcel(dest, flags);
729 }
730 }
731
732 public void assimilate(BitmapCache bitmapCache) {
733 ArrayList<Bitmap> bitmapsToBeAdded = bitmapCache.mBitmaps;
734 int count = bitmapsToBeAdded.size();
735 for (int i = 0; i < count; i++) {
736 Bitmap b = bitmapsToBeAdded.get(i);
737 if (!mBitmaps.contains(b)) {
738 mBitmaps.add(b);
739 }
740 }
741 }
742
743 public void addBitmapMemory(MemoryUsageCounter memoryCounter) {
744 for (int i = 0; i < mBitmaps.size(); i++) {
745 memoryCounter.addBitmapMemory(mBitmaps.get(i));
746 }
747 }
748 }
749
750 private class BitmapReflectionAction extends Action {
751 int bitmapId;
752 int viewId;
753 Bitmap bitmap;
754 String methodName;
755
756 BitmapReflectionAction(int viewId, String methodName, Bitmap bitmap) {
757 this.bitmap = bitmap;
758 this.viewId = viewId;
759 this.methodName = methodName;
760 bitmapId = mBitmapCache.getBitmapId(bitmap);
761 }
762
763 BitmapReflectionAction(Parcel in) {
764 viewId = in.readInt();
765 methodName = in.readString();
766 bitmapId = in.readInt();
767 bitmap = mBitmapCache.getBitmapForId(bitmapId);
768 }
769
770 @Override
771 public void writeToParcel(Parcel dest, int flags) {
772 dest.writeInt(TAG);
773 dest.writeInt(viewId);
774 dest.writeString(methodName);
775 dest.writeInt(bitmapId);
776 }
777
778 @Override
779 public void apply(View root, ViewGroup rootParent) throws ActionException {
780 ReflectionAction ra = new ReflectionAction(viewId, methodName, ReflectionAction.BITMAP,
781 bitmap);
782 ra.apply(root, rootParent);
783 }
784
785 @Override
786 public void setBitmapCache(BitmapCache bitmapCache) {
787 bitmapId = bitmapCache.getBitmapId(bitmap);
788 }
789
790 public final static int TAG = 12;
791 }
792
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800793 /**
794 * Base class for the reflection actions.
795 */
796 private class ReflectionAction extends Action {
797 static final int TAG = 2;
798
799 static final int BOOLEAN = 1;
800 static final int BYTE = 2;
801 static final int SHORT = 3;
802 static final int INT = 4;
803 static final int LONG = 5;
804 static final int FLOAT = 6;
805 static final int DOUBLE = 7;
806 static final int CHAR = 8;
807 static final int STRING = 9;
808 static final int CHAR_SEQUENCE = 10;
809 static final int URI = 11;
810 static final int BITMAP = 12;
Bjorn Bringertd755b062010-01-06 17:15:37 +0000811 static final int BUNDLE = 13;
Winson Chung499cb9f2010-07-16 11:18:17 -0700812 static final int INTENT = 14;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800813
814 int viewId;
815 String methodName;
816 int type;
817 Object value;
818
819 ReflectionAction(int viewId, String methodName, int type, Object value) {
820 this.viewId = viewId;
821 this.methodName = methodName;
822 this.type = type;
823 this.value = value;
824 }
825
826 ReflectionAction(Parcel in) {
827 this.viewId = in.readInt();
828 this.methodName = in.readString();
829 this.type = in.readInt();
Romain Guya5475592009-07-01 17:20:08 -0700830 //noinspection ConstantIfStatement
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800831 if (false) {
832 Log.d("RemoteViews", "read viewId=0x" + Integer.toHexString(this.viewId)
833 + " methodName=" + this.methodName + " type=" + this.type);
834 }
Adam Cohenc6151f22012-02-02 21:02:31 -0800835
836 // For some values that may have been null, we first check a flag to see if they were
837 // written to the parcel.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800838 switch (this.type) {
839 case BOOLEAN:
840 this.value = in.readInt() != 0;
841 break;
842 case BYTE:
843 this.value = in.readByte();
844 break;
845 case SHORT:
846 this.value = (short)in.readInt();
847 break;
848 case INT:
849 this.value = in.readInt();
850 break;
851 case LONG:
852 this.value = in.readLong();
853 break;
854 case FLOAT:
855 this.value = in.readFloat();
856 break;
857 case DOUBLE:
858 this.value = in.readDouble();
859 break;
860 case CHAR:
861 this.value = (char)in.readInt();
862 break;
863 case STRING:
864 this.value = in.readString();
865 break;
866 case CHAR_SEQUENCE:
867 this.value = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
868 break;
869 case URI:
Adam Cohenc6151f22012-02-02 21:02:31 -0800870 if (in.readInt() != 0) {
871 this.value = Uri.CREATOR.createFromParcel(in);
872 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800873 break;
874 case BITMAP:
Adam Cohenc6151f22012-02-02 21:02:31 -0800875 if (in.readInt() != 0) {
876 this.value = Bitmap.CREATOR.createFromParcel(in);
877 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800878 break;
Bjorn Bringertd755b062010-01-06 17:15:37 +0000879 case BUNDLE:
880 this.value = in.readBundle();
881 break;
Winson Chung499cb9f2010-07-16 11:18:17 -0700882 case INTENT:
Adam Cohenc6151f22012-02-02 21:02:31 -0800883 if (in.readInt() != 0) {
884 this.value = Intent.CREATOR.createFromParcel(in);
885 }
Winson Chung499cb9f2010-07-16 11:18:17 -0700886 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800887 default:
888 break;
889 }
890 }
891
892 public void writeToParcel(Parcel out, int flags) {
893 out.writeInt(TAG);
894 out.writeInt(this.viewId);
895 out.writeString(this.methodName);
896 out.writeInt(this.type);
Romain Guya5475592009-07-01 17:20:08 -0700897 //noinspection ConstantIfStatement
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800898 if (false) {
899 Log.d("RemoteViews", "write viewId=0x" + Integer.toHexString(this.viewId)
900 + " methodName=" + this.methodName + " type=" + this.type);
901 }
Adam Cohenc6151f22012-02-02 21:02:31 -0800902
903 // For some values which are null, we record an integer flag to indicate whether
904 // we have written a valid value to the parcel.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800905 switch (this.type) {
906 case BOOLEAN:
Romain Guya5475592009-07-01 17:20:08 -0700907 out.writeInt((Boolean) this.value ? 1 : 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800908 break;
909 case BYTE:
Romain Guya5475592009-07-01 17:20:08 -0700910 out.writeByte((Byte) this.value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800911 break;
912 case SHORT:
Romain Guya5475592009-07-01 17:20:08 -0700913 out.writeInt((Short) this.value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800914 break;
915 case INT:
Romain Guya5475592009-07-01 17:20:08 -0700916 out.writeInt((Integer) this.value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800917 break;
918 case LONG:
Romain Guya5475592009-07-01 17:20:08 -0700919 out.writeLong((Long) this.value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800920 break;
921 case FLOAT:
Romain Guya5475592009-07-01 17:20:08 -0700922 out.writeFloat((Float) this.value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800923 break;
924 case DOUBLE:
Romain Guya5475592009-07-01 17:20:08 -0700925 out.writeDouble((Double) this.value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800926 break;
927 case CHAR:
928 out.writeInt((int)((Character)this.value).charValue());
929 break;
930 case STRING:
931 out.writeString((String)this.value);
932 break;
933 case CHAR_SEQUENCE:
934 TextUtils.writeToParcel((CharSequence)this.value, out, flags);
935 break;
936 case URI:
Adam Cohenc6151f22012-02-02 21:02:31 -0800937 out.writeInt(this.value != null ? 1 : 0);
938 if (this.value != null) {
939 ((Uri)this.value).writeToParcel(out, flags);
940 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800941 break;
942 case BITMAP:
Adam Cohenc6151f22012-02-02 21:02:31 -0800943 out.writeInt(this.value != null ? 1 : 0);
944 if (this.value != null) {
945 ((Bitmap)this.value).writeToParcel(out, flags);
946 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800947 break;
Bjorn Bringertd755b062010-01-06 17:15:37 +0000948 case BUNDLE:
949 out.writeBundle((Bundle) this.value);
950 break;
Winson Chung499cb9f2010-07-16 11:18:17 -0700951 case INTENT:
Adam Cohenc6151f22012-02-02 21:02:31 -0800952 out.writeInt(this.value != null ? 1 : 0);
953 if (this.value != null) {
954 ((Intent)this.value).writeToParcel(out, flags);
955 }
Winson Chung499cb9f2010-07-16 11:18:17 -0700956 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800957 default:
958 break;
959 }
960 }
961
962 private Class getParameterType() {
963 switch (this.type) {
964 case BOOLEAN:
965 return boolean.class;
966 case BYTE:
967 return byte.class;
968 case SHORT:
969 return short.class;
970 case INT:
971 return int.class;
972 case LONG:
973 return long.class;
974 case FLOAT:
975 return float.class;
976 case DOUBLE:
977 return double.class;
978 case CHAR:
979 return char.class;
980 case STRING:
981 return String.class;
982 case CHAR_SEQUENCE:
983 return CharSequence.class;
984 case URI:
985 return Uri.class;
986 case BITMAP:
987 return Bitmap.class;
Bjorn Bringertd755b062010-01-06 17:15:37 +0000988 case BUNDLE:
989 return Bundle.class;
Winson Chung499cb9f2010-07-16 11:18:17 -0700990 case INTENT:
991 return Intent.class;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800992 default:
993 return null;
994 }
995 }
996
997 @Override
Winson Chung037300b2011-03-29 15:40:16 -0700998 public void apply(View root, ViewGroup rootParent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800999 final View view = root.findViewById(viewId);
Joe Onorato2b69ce42010-10-31 11:35:41 -07001000 if (view == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001001
1002 Class param = getParameterType();
1003 if (param == null) {
1004 throw new ActionException("bad type: " + this.type);
1005 }
1006
1007 Class klass = view.getClass();
Romain Guya5475592009-07-01 17:20:08 -07001008 Method method;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001009 try {
1010 method = klass.getMethod(this.methodName, getParameterType());
1011 }
1012 catch (NoSuchMethodException ex) {
1013 throw new ActionException("view: " + klass.getName() + " doesn't have method: "
1014 + this.methodName + "(" + param.getName() + ")");
1015 }
1016
1017 if (!method.isAnnotationPresent(RemotableViewMethod.class)) {
1018 throw new ActionException("view: " + klass.getName()
1019 + " can't use method with RemoteViews: "
1020 + this.methodName + "(" + param.getName() + ")");
1021 }
1022
1023 try {
Romain Guya5475592009-07-01 17:20:08 -07001024 //noinspection ConstantIfStatement
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001025 if (false) {
1026 Log.d("RemoteViews", "view: " + klass.getName() + " calling method: "
1027 + this.methodName + "(" + param.getName() + ") with "
1028 + (this.value == null ? "null" : this.value.getClass().getName()));
1029 }
1030 method.invoke(view, this.value);
1031 }
1032 catch (Exception ex) {
1033 throw new ActionException(ex);
1034 }
1035 }
Winson Chung3ec9a452010-09-23 16:40:28 -07001036
1037 @Override
1038 public void updateMemoryUsageEstimate(MemoryUsageCounter counter) {
1039 // We currently only calculate Bitmap memory usage
1040 switch (this.type) {
1041 case BITMAP:
1042 if (this.value != null) {
1043 final Bitmap b = (Bitmap) this.value;
Adam Cohen5d200642012-04-24 10:43:31 -07001044 counter.addBitmapMemory(b);
Winson Chung3ec9a452010-09-23 16:40:28 -07001045 }
1046 break;
1047 default:
1048 break;
1049 }
1050 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001051 }
1052
Adam Cohen5d200642012-04-24 10:43:31 -07001053 private void configureRemoteViewsAsChild(RemoteViews rv) {
1054 mBitmapCache.assimilate(rv.mBitmapCache);
1055 rv.setBitmapCache(mBitmapCache);
1056 rv.setNotRoot();
1057 }
1058
1059 void setNotRoot() {
1060 mIsRoot = false;
1061 }
1062
Jeff Sharkey1162fd72009-11-04 17:58:08 -08001063 /**
1064 * Equivalent to calling {@link ViewGroup#addView(View)} after inflating the
1065 * given {@link RemoteViews}, or calling {@link ViewGroup#removeAllViews()}
1066 * when null. This allows users to build "nested" {@link RemoteViews}.
1067 */
1068 private class ViewGroupAction extends Action {
1069 public ViewGroupAction(int viewId, RemoteViews nestedViews) {
1070 this.viewId = viewId;
1071 this.nestedViews = nestedViews;
Adam Cohenc431c152012-04-26 18:42:17 -07001072 if (nestedViews != null) {
1073 configureRemoteViewsAsChild(nestedViews);
1074 }
Jeff Sharkey1162fd72009-11-04 17:58:08 -08001075 }
1076
Adam Cohen5d200642012-04-24 10:43:31 -07001077 public ViewGroupAction(Parcel parcel, BitmapCache bitmapCache) {
Jeff Sharkey1162fd72009-11-04 17:58:08 -08001078 viewId = parcel.readInt();
Adam Cohen5d200642012-04-24 10:43:31 -07001079 boolean nestedViewsNull = parcel.readInt() == 0;
1080 if (!nestedViewsNull) {
1081 nestedViews = new RemoteViews(parcel, bitmapCache);
1082 } else {
1083 nestedViews = null;
1084 }
Jeff Sharkey1162fd72009-11-04 17:58:08 -08001085 }
1086
1087 public void writeToParcel(Parcel dest, int flags) {
1088 dest.writeInt(TAG);
1089 dest.writeInt(viewId);
Adam Cohen5d200642012-04-24 10:43:31 -07001090 if (nestedViews != null) {
1091 dest.writeInt(1);
1092 nestedViews.writeToParcel(dest, flags);
1093 } else {
1094 // signifies null
1095 dest.writeInt(0);
1096 }
Jeff Sharkey1162fd72009-11-04 17:58:08 -08001097 }
1098
1099 @Override
Winson Chung037300b2011-03-29 15:40:16 -07001100 public void apply(View root, ViewGroup rootParent) {
Jeff Sharkey1162fd72009-11-04 17:58:08 -08001101 final Context context = root.getContext();
1102 final ViewGroup target = (ViewGroup) root.findViewById(viewId);
Joe Onorato2b69ce42010-10-31 11:35:41 -07001103 if (target == null) return;
Jeff Sharkey1162fd72009-11-04 17:58:08 -08001104 if (nestedViews != null) {
1105 // Inflate nested views and add as children
1106 target.addView(nestedViews.apply(context, target));
Joe Onorato2b69ce42010-10-31 11:35:41 -07001107 } else {
Jeff Sharkey1162fd72009-11-04 17:58:08 -08001108 // Clear all children when nested views omitted
1109 target.removeAllViews();
1110 }
1111 }
1112
Winson Chung3ec9a452010-09-23 16:40:28 -07001113 @Override
1114 public void updateMemoryUsageEstimate(MemoryUsageCounter counter) {
1115 if (nestedViews != null) {
Adam Cohen5d200642012-04-24 10:43:31 -07001116 counter.increment(nestedViews.estimateMemoryUsage());
1117 }
1118 }
1119
1120 @Override
1121 public void setBitmapCache(BitmapCache bitmapCache) {
1122 if (nestedViews != null) {
1123 nestedViews.setBitmapCache(bitmapCache);
Winson Chung3ec9a452010-09-23 16:40:28 -07001124 }
1125 }
1126
Jeff Sharkey1162fd72009-11-04 17:58:08 -08001127 int viewId;
1128 RemoteViews nestedViews;
1129
1130 public final static int TAG = 4;
1131 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001132
1133 /**
Daniel Sandler820ba322012-03-23 16:36:00 -05001134 * Helper action to set compound drawables on a TextView. Supports relative
1135 * (s/t/e/b) or cardinal (l/t/r/b) arrangement.
1136 */
1137 private class TextViewDrawableAction extends Action {
1138 public TextViewDrawableAction(int viewId, boolean isRelative, int d1, int d2, int d3, int d4) {
1139 this.viewId = viewId;
1140 this.isRelative = isRelative;
1141 this.d1 = d1;
1142 this.d2 = d2;
1143 this.d3 = d3;
1144 this.d4 = d4;
1145 }
1146
1147 public TextViewDrawableAction(Parcel parcel) {
1148 viewId = parcel.readInt();
1149 isRelative = (parcel.readInt() != 0);
1150 d1 = parcel.readInt();
1151 d2 = parcel.readInt();
1152 d3 = parcel.readInt();
1153 d4 = parcel.readInt();
1154 }
1155
1156 public void writeToParcel(Parcel dest, int flags) {
1157 dest.writeInt(TAG);
1158 dest.writeInt(viewId);
1159 dest.writeInt(isRelative ? 1 : 0);
1160 dest.writeInt(d1);
1161 dest.writeInt(d2);
1162 dest.writeInt(d3);
1163 dest.writeInt(d4);
1164 }
1165
1166 @Override
1167 public void apply(View root, ViewGroup rootParent) {
1168 final Context context = root.getContext();
1169 final TextView target = (TextView) root.findViewById(viewId);
1170 if (target == null) return;
1171 if (isRelative) {
1172 target.setCompoundDrawablesRelativeWithIntrinsicBounds(d1, d2, d3, d4);
1173 } else {
1174 target.setCompoundDrawablesWithIntrinsicBounds(d1, d2, d3, d4);
1175 }
1176 }
1177
1178 int viewId;
1179 boolean isRelative = false;
1180 int d1, d2, d3, d4;
1181
1182 public final static int TAG = 11;
1183 }
1184
1185 /**
Daniel Sandler7264f712012-05-21 14:48:23 -04001186 * Helper action to set compound drawables on a TextView. Supports relative
1187 * (s/t/e/b) or cardinal (l/t/r/b) arrangement.
1188 */
1189 private class TextViewSizeAction extends Action {
1190 public TextViewSizeAction(int viewId, int units, float size) {
1191 this.viewId = viewId;
1192 this.units = units;
1193 this.size = size;
1194 }
1195
1196 public TextViewSizeAction(Parcel parcel) {
1197 viewId = parcel.readInt();
1198 units = parcel.readInt();
1199 size = parcel.readFloat();
1200 }
1201
1202 public void writeToParcel(Parcel dest, int flags) {
1203 dest.writeInt(TAG);
1204 dest.writeInt(viewId);
1205 dest.writeInt(units);
1206 dest.writeFloat(size);
1207 }
1208
1209 @Override
1210 public void apply(View root, ViewGroup rootParent) {
1211 final Context context = root.getContext();
1212 final TextView target = (TextView) root.findViewById(viewId);
1213 if (target == null) return;
1214 target.setTextSize(units, size);
1215 }
1216
1217 int viewId;
1218 int units;
1219 float size;
1220
1221 public final static int TAG = 13;
1222 }
1223
1224 /**
Winson Chung3ec9a452010-09-23 16:40:28 -07001225 * Simple class used to keep track of memory usage in a RemoteViews.
1226 *
1227 */
1228 private class MemoryUsageCounter {
1229 public void clear() {
Adam Cohen5d200642012-04-24 10:43:31 -07001230 mMemoryUsage = 0;
Winson Chung3ec9a452010-09-23 16:40:28 -07001231 }
1232
Adam Cohen5d200642012-04-24 10:43:31 -07001233 public void increment(int numBytes) {
1234 mMemoryUsage += numBytes;
Winson Chung3ec9a452010-09-23 16:40:28 -07001235 }
1236
Adam Cohen5d200642012-04-24 10:43:31 -07001237 public int getMemoryUsage() {
1238 return mMemoryUsage;
Winson Chung3ec9a452010-09-23 16:40:28 -07001239 }
1240
Adam Cohen5d200642012-04-24 10:43:31 -07001241 public void addBitmapMemory(Bitmap b) {
1242 final Bitmap.Config c = b.getConfig();
1243 // If we don't know, be pessimistic and assume 4
1244 int bpp = 4;
1245 if (c != null) {
1246 switch (c) {
1247 case ALPHA_8:
1248 bpp = 1;
1249 break;
1250 case RGB_565:
1251 case ARGB_4444:
1252 bpp = 2;
1253 break;
1254 case ARGB_8888:
1255 bpp = 4;
1256 break;
1257 }
1258 }
1259 increment(b.getWidth() * b.getHeight() * bpp);
1260 }
1261
1262 int mMemoryUsage;
Winson Chung3ec9a452010-09-23 16:40:28 -07001263 }
1264
1265 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001266 * Create a new RemoteViews object that will display the views contained
1267 * in the specified layout file.
1268 *
1269 * @param packageName Name of the package that contains the layout resource
1270 * @param layoutId The id of the layout resource
1271 */
1272 public RemoteViews(String packageName, int layoutId) {
1273 mPackage = packageName;
1274 mLayoutId = layoutId;
Adam Cohen5d200642012-04-24 10:43:31 -07001275 mBitmapCache = new BitmapCache();
Winson Chung3ec9a452010-09-23 16:40:28 -07001276
1277 // setup the memory usage statistics
1278 mMemoryUsageCounter = new MemoryUsageCounter();
1279 recalculateMemoryUsage();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001280 }
1281
Adam Cohen5d200642012-04-24 10:43:31 -07001282 private boolean hasLandscapeAndPortraitLayouts() {
1283 return (mLandscape != null) && (mPortrait != null);
1284 }
1285
1286 /**
1287 * Create a new RemoteViews object that will inflate as the specified
1288 * landspace or portrait RemoteViews, depending on the current configuration.
1289 *
1290 * @param landscape The RemoteViews to inflate in landscape configuration
1291 * @param portrait The RemoteViews to inflate in portrait configuration
1292 */
1293 public RemoteViews(RemoteViews landscape, RemoteViews portrait) {
1294 if (landscape == null || portrait == null) {
1295 throw new RuntimeException("Both RemoteViews must be non-null");
1296 }
1297 if (landscape.getPackage().compareTo(portrait.getPackage()) != 0) {
1298 throw new RuntimeException("Both RemoteViews must share the same package");
1299 }
1300 mPackage = portrait.getPackage();
1301 mLayoutId = portrait.getLayoutId();
1302
1303 mLandscape = landscape;
1304 mPortrait = portrait;
1305
1306 // setup the memory usage statistics
1307 mMemoryUsageCounter = new MemoryUsageCounter();
1308
1309 mBitmapCache = new BitmapCache();
1310 configureRemoteViewsAsChild(landscape);
1311 configureRemoteViewsAsChild(portrait);
1312
1313 recalculateMemoryUsage();
1314 }
1315
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001316 /**
1317 * Reads a RemoteViews object from a parcel.
1318 *
1319 * @param parcel
1320 */
1321 public RemoteViews(Parcel parcel) {
Adam Cohen5d200642012-04-24 10:43:31 -07001322 this(parcel, null);
1323 }
Adam Cohenca6fd842010-09-03 18:10:35 -07001324
Adam Cohen5d200642012-04-24 10:43:31 -07001325 private RemoteViews(Parcel parcel, BitmapCache bitmapCache) {
1326 int mode = parcel.readInt();
1327
1328 // We only store a bitmap cache in the root of the RemoteViews.
1329 if (bitmapCache == null) {
1330 mBitmapCache = new BitmapCache(parcel);
1331 } else {
1332 setBitmapCache(bitmapCache);
1333 setNotRoot();
1334 }
1335
1336 if (mode == MODE_NORMAL) {
1337 mPackage = parcel.readString();
1338 mLayoutId = parcel.readInt();
1339 mIsWidgetCollectionChild = parcel.readInt() == 1 ? true : false;
1340
1341 int count = parcel.readInt();
1342 if (count > 0) {
1343 mActions = new ArrayList<Action>(count);
1344 for (int i=0; i<count; i++) {
1345 int tag = parcel.readInt();
1346 switch (tag) {
1347 case SetOnClickPendingIntent.TAG:
1348 mActions.add(new SetOnClickPendingIntent(parcel));
1349 break;
1350 case SetDrawableParameters.TAG:
1351 mActions.add(new SetDrawableParameters(parcel));
1352 break;
1353 case ReflectionAction.TAG:
1354 mActions.add(new ReflectionAction(parcel));
1355 break;
1356 case ViewGroupAction.TAG:
1357 mActions.add(new ViewGroupAction(parcel, mBitmapCache));
1358 break;
1359 case ReflectionActionWithoutParams.TAG:
1360 mActions.add(new ReflectionActionWithoutParams(parcel));
1361 break;
1362 case SetEmptyView.TAG:
1363 mActions.add(new SetEmptyView(parcel));
1364 break;
1365 case SetPendingIntentTemplate.TAG:
1366 mActions.add(new SetPendingIntentTemplate(parcel));
1367 break;
1368 case SetOnClickFillInIntent.TAG:
1369 mActions.add(new SetOnClickFillInIntent(parcel));
1370 break;
1371 case SetRemoteViewsAdapterIntent.TAG:
1372 mActions.add(new SetRemoteViewsAdapterIntent(parcel));
1373 break;
1374 case TextViewDrawableAction.TAG:
1375 mActions.add(new TextViewDrawableAction(parcel));
1376 break;
Daniel Sandler7264f712012-05-21 14:48:23 -04001377 case TextViewSizeAction.TAG:
1378 mActions.add(new TextViewSizeAction(parcel));
1379 break;
Adam Cohen5d200642012-04-24 10:43:31 -07001380 case BitmapReflectionAction.TAG:
1381 mActions.add(new BitmapReflectionAction(parcel));
1382 break;
1383 default:
1384 throw new ActionException("Tag " + tag + " not found");
1385 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001386 }
1387 }
Adam Cohen5d200642012-04-24 10:43:31 -07001388 } else {
1389 // MODE_HAS_LANDSCAPE_AND_PORTRAIT
1390 mLandscape = new RemoteViews(parcel, mBitmapCache);
1391 mPortrait = new RemoteViews(parcel, mBitmapCache);
1392 mPackage = mPortrait.getPackage();
1393 mLayoutId = mPortrait.getLayoutId();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001394 }
Winson Chung3ec9a452010-09-23 16:40:28 -07001395
1396 // setup the memory usage statistics
1397 mMemoryUsageCounter = new MemoryUsageCounter();
1398 recalculateMemoryUsage();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001399 }
1400
Gilles Debunne30301932010-06-16 18:32:00 -07001401 @Override
Joe Onorato18e69df2010-05-17 22:26:12 -07001402 public RemoteViews clone() {
Adam Cohen5d200642012-04-24 10:43:31 -07001403 RemoteViews that;
1404 if (!hasLandscapeAndPortraitLayouts()) {
1405 that = new RemoteViews(mPackage, mLayoutId);
Winson Chung3ec9a452010-09-23 16:40:28 -07001406
Adam Cohen5d200642012-04-24 10:43:31 -07001407 if (mActions != null) {
1408 that.mActions = (ArrayList<Action>)mActions.clone();
1409 }
1410 } else {
1411 RemoteViews land = mLandscape.clone();
1412 RemoteViews port = mPortrait.clone();
1413 that = new RemoteViews(land, port);
1414 }
Winson Chung3ec9a452010-09-23 16:40:28 -07001415 // update the memory usage stats of the cloned RemoteViews
1416 that.recalculateMemoryUsage();
Joe Onorato18e69df2010-05-17 22:26:12 -07001417 return that;
1418 }
1419
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001420 public String getPackage() {
1421 return mPackage;
1422 }
1423
Adam Cohen5d200642012-04-24 10:43:31 -07001424 /**
1425 * Reutrns the layout id of the root layout associated with this RemoteViews. In the case
1426 * that the RemoteViews has both a landscape and portrait root, this will return the layout
1427 * id associated with the portrait layout.
1428 *
1429 * @return the layout id.
1430 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001431 public int getLayoutId() {
1432 return mLayoutId;
1433 }
1434
Winson Chung3ec9a452010-09-23 16:40:28 -07001435 /*
Adam Cohenca6fd842010-09-03 18:10:35 -07001436 * This flag indicates whether this RemoteViews object is being created from a
1437 * RemoteViewsService for use as a child of a widget collection. This flag is used
1438 * to determine whether or not certain features are available, in particular,
1439 * setting on click extras and setting on click pending intents. The former is enabled,
1440 * and the latter disabled when this flag is true.
1441 */
1442 void setIsWidgetCollectionChild(boolean isWidgetCollectionChild) {
1443 mIsWidgetCollectionChild = isWidgetCollectionChild;
1444 }
1445
1446 /**
Winson Chung3ec9a452010-09-23 16:40:28 -07001447 * Updates the memory usage statistics.
1448 */
1449 private void recalculateMemoryUsage() {
1450 mMemoryUsageCounter.clear();
1451
Adam Cohen5d200642012-04-24 10:43:31 -07001452 if (!hasLandscapeAndPortraitLayouts()) {
1453 // Accumulate the memory usage for each action
1454 if (mActions != null) {
1455 final int count = mActions.size();
1456 for (int i= 0; i < count; ++i) {
1457 mActions.get(i).updateMemoryUsageEstimate(mMemoryUsageCounter);
1458 }
Winson Chung3ec9a452010-09-23 16:40:28 -07001459 }
Adam Cohen5d200642012-04-24 10:43:31 -07001460 if (mIsRoot) {
1461 mBitmapCache.addBitmapMemory(mMemoryUsageCounter);
1462 }
1463 } else {
1464 mMemoryUsageCounter.increment(mLandscape.estimateMemoryUsage());
1465 mMemoryUsageCounter.increment(mPortrait.estimateMemoryUsage());
1466 mBitmapCache.addBitmapMemory(mMemoryUsageCounter);
1467 }
1468 }
1469
1470 /**
1471 * Recursively sets BitmapCache in the hierarchy and update the bitmap ids.
1472 */
1473 private void setBitmapCache(BitmapCache bitmapCache) {
1474 mBitmapCache = bitmapCache;
1475 if (!hasLandscapeAndPortraitLayouts()) {
1476 if (mActions != null) {
1477 final int count = mActions.size();
1478 for (int i= 0; i < count; ++i) {
1479 mActions.get(i).setBitmapCache(bitmapCache);
1480 }
1481 }
1482 } else {
1483 mLandscape.setBitmapCache(bitmapCache);
1484 mPortrait.setBitmapCache(bitmapCache);
Winson Chung3ec9a452010-09-23 16:40:28 -07001485 }
1486 }
1487
1488 /**
1489 * Returns an estimate of the bitmap heap memory usage for this RemoteViews.
1490 */
Adam Cohen311c79c2012-05-10 14:44:38 -07001491 /** @hide */
1492 public int estimateMemoryUsage() {
Adam Cohen5d200642012-04-24 10:43:31 -07001493 return mMemoryUsageCounter.getMemoryUsage();
Winson Chung3ec9a452010-09-23 16:40:28 -07001494 }
1495
1496 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001497 * Add an action to be executed on the remote side when apply is called.
1498 *
1499 * @param a The action to add
1500 */
1501 private void addAction(Action a) {
Adam Cohen5d200642012-04-24 10:43:31 -07001502 if (hasLandscapeAndPortraitLayouts()) {
1503 throw new RuntimeException("RemoteViews specifying separate landscape and portrait" +
1504 " layouts cannot be modified. Instead, fully configure the landscape and" +
1505 " portrait layouts individually before constructing the combined layout.");
1506 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001507 if (mActions == null) {
1508 mActions = new ArrayList<Action>();
1509 }
1510 mActions.add(a);
Winson Chung3ec9a452010-09-23 16:40:28 -07001511
1512 // update the memory usage stats
1513 a.updateMemoryUsageEstimate(mMemoryUsageCounter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001514 }
Jeff Sharkey1162fd72009-11-04 17:58:08 -08001515
1516 /**
1517 * Equivalent to calling {@link ViewGroup#addView(View)} after inflating the
1518 * given {@link RemoteViews}. This allows users to build "nested"
1519 * {@link RemoteViews}. In cases where consumers of {@link RemoteViews} may
1520 * recycle layouts, use {@link #removeAllViews(int)} to clear any existing
1521 * children.
1522 *
1523 * @param viewId The id of the parent {@link ViewGroup} to add child into.
1524 * @param nestedView {@link RemoteViews} that describes the child.
1525 */
1526 public void addView(int viewId, RemoteViews nestedView) {
1527 addAction(new ViewGroupAction(viewId, nestedView));
1528 }
1529
1530 /**
1531 * Equivalent to calling {@link ViewGroup#removeAllViews()}.
1532 *
1533 * @param viewId The id of the parent {@link ViewGroup} to remove all
1534 * children from.
1535 */
1536 public void removeAllViews(int viewId) {
1537 addAction(new ViewGroupAction(viewId, null));
1538 }
1539
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001540 /**
Adam Cohen0b96a572011-02-10 15:56:16 -08001541 * Equivalent to calling {@link AdapterViewAnimator#showNext()}
Adam Cohen2dd21972010-08-15 18:20:04 -07001542 *
Adam Cohen0b96a572011-02-10 15:56:16 -08001543 * @param viewId The id of the view on which to call {@link AdapterViewAnimator#showNext()}
Adam Cohen2dd21972010-08-15 18:20:04 -07001544 */
1545 public void showNext(int viewId) {
1546 addAction(new ReflectionActionWithoutParams(viewId, "showNext"));
1547 }
1548
1549 /**
Adam Cohen0b96a572011-02-10 15:56:16 -08001550 * Equivalent to calling {@link AdapterViewAnimator#showPrevious()}
Adam Cohen2dd21972010-08-15 18:20:04 -07001551 *
Adam Cohen0b96a572011-02-10 15:56:16 -08001552 * @param viewId The id of the view on which to call {@link AdapterViewAnimator#showPrevious()}
Adam Cohen2dd21972010-08-15 18:20:04 -07001553 */
1554 public void showPrevious(int viewId) {
1555 addAction(new ReflectionActionWithoutParams(viewId, "showPrevious"));
1556 }
1557
1558 /**
Adam Cohen0b96a572011-02-10 15:56:16 -08001559 * Equivalent to calling {@link AdapterViewAnimator#setDisplayedChild(int)}
1560 *
1561 * @param viewId The id of the view on which to call
1562 * {@link AdapterViewAnimator#setDisplayedChild(int)}
1563 */
1564 public void setDisplayedChild(int viewId, int childIndex) {
1565 setInt(viewId, "setDisplayedChild", childIndex);
1566 }
1567
1568 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001569 * Equivalent to calling View.setVisibility
1570 *
1571 * @param viewId The id of the view whose visibility should change
1572 * @param visibility The new visibility for the view
1573 */
1574 public void setViewVisibility(int viewId, int visibility) {
1575 setInt(viewId, "setVisibility", visibility);
1576 }
Adam Cohenca6fd842010-09-03 18:10:35 -07001577
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001578 /**
1579 * Equivalent to calling TextView.setText
1580 *
1581 * @param viewId The id of the view whose text should change
1582 * @param text The new text for the view
1583 */
1584 public void setTextViewText(int viewId, CharSequence text) {
1585 setCharSequence(viewId, "setText", text);
1586 }
Daniel Sandler7264f712012-05-21 14:48:23 -04001587
1588 /**
1589 * @hide
1590 * Equivalent to calling {@link TextView#setTextSize(int, float)}
1591 *
1592 * @param viewId The id of the view whose text size should change
1593 * @param units The units of size (e.g. COMPLEX_UNIT_SP)
1594 * @param size The size of the text
1595 */
1596 public void setTextViewTextSize(int viewId, int units, float size) {
1597 addAction(new TextViewSizeAction(viewId, units, size));
1598 }
1599
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001600 /**
Daniel Sandler820ba322012-03-23 16:36:00 -05001601 * Equivalent to calling
1602 * {@link TextView#setCompoundDrawablesWithIntrinsicBounds(int, int, int, int)}.
1603 *
1604 * @param viewId The id of the view whose text should change
1605 * @param left The id of a drawable to place to the left of the text, or 0
1606 * @param top The id of a drawable to place above the text, or 0
1607 * @param right The id of a drawable to place to the right of the text, or 0
1608 * @param bottom The id of a drawable to place below the text, or 0
1609 */
1610 public void setTextViewCompoundDrawables(int viewId, int left, int top, int right, int bottom) {
1611 addAction(new TextViewDrawableAction(viewId, false, left, top, right, bottom));
1612 }
1613
1614 /**
Daniel Sandler820ba322012-03-23 16:36:00 -05001615 * @param viewId The id of the view whose text should change
Fabrice Di Meglio66388dc2012-05-03 18:51:57 -07001616 * @param start The id of a drawable to place before the text (relative to the
Daniel Sandler820ba322012-03-23 16:36:00 -05001617 * layout direction), or 0
1618 * @param top The id of a drawable to place above the text, or 0
1619 * @param end The id of a drawable to place after the text, or 0
Fabrice Di Meglio66388dc2012-05-03 18:51:57 -07001620 * @param bottom The id of a drawable to place below the text, or 0
1621 * @hide
Daniel Sandler820ba322012-03-23 16:36:00 -05001622 */
1623 public void setTextViewCompoundDrawablesRelative(int viewId, int start, int top, int end, int bottom) {
1624 addAction(new TextViewDrawableAction(viewId, true, start, top, end, bottom));
1625 }
1626
1627 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001628 * Equivalent to calling ImageView.setImageResource
1629 *
1630 * @param viewId The id of the view whose drawable should change
1631 * @param srcId The new resource id for the drawable
1632 */
1633 public void setImageViewResource(int viewId, int srcId) {
1634 setInt(viewId, "setImageResource", srcId);
1635 }
1636
1637 /**
1638 * Equivalent to calling ImageView.setImageURI
1639 *
1640 * @param viewId The id of the view whose drawable should change
1641 * @param uri The Uri for the image
1642 */
1643 public void setImageViewUri(int viewId, Uri uri) {
1644 setUri(viewId, "setImageURI", uri);
1645 }
1646
1647 /**
1648 * Equivalent to calling ImageView.setImageBitmap
1649 *
Scott Main93dc6422012-02-24 12:04:06 -08001650 * @param viewId The id of the view whose bitmap should change
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001651 * @param bitmap The new Bitmap for the drawable
1652 */
1653 public void setImageViewBitmap(int viewId, Bitmap bitmap) {
1654 setBitmap(viewId, "setImageBitmap", bitmap);
1655 }
1656
1657 /**
Adam Cohen1480fdd2010-08-25 17:24:53 -07001658 * Equivalent to calling AdapterView.setEmptyView
1659 *
1660 * @param viewId The id of the view on which to set the empty view
1661 * @param emptyViewId The view id of the empty view
1662 */
1663 public void setEmptyView(int viewId, int emptyViewId) {
1664 addAction(new SetEmptyView(viewId, emptyViewId));
1665 }
1666
1667 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001668 * Equivalent to calling {@link Chronometer#setBase Chronometer.setBase},
1669 * {@link Chronometer#setFormat Chronometer.setFormat},
1670 * and {@link Chronometer#start Chronometer.start()} or
1671 * {@link Chronometer#stop Chronometer.stop()}.
1672 *
Scott Main93dc6422012-02-24 12:04:06 -08001673 * @param viewId The id of the {@link Chronometer} to change
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001674 * @param base The time at which the timer would have read 0:00. This
1675 * time should be based off of
1676 * {@link android.os.SystemClock#elapsedRealtime SystemClock.elapsedRealtime()}.
1677 * @param format The Chronometer format string, or null to
1678 * simply display the timer value.
1679 * @param started True if you want the clock to be started, false if not.
1680 */
1681 public void setChronometer(int viewId, long base, String format, boolean started) {
1682 setLong(viewId, "setBase", base);
1683 setString(viewId, "setFormat", format);
1684 setBoolean(viewId, "setStarted", started);
1685 }
1686
1687 /**
1688 * Equivalent to calling {@link ProgressBar#setMax ProgressBar.setMax},
1689 * {@link ProgressBar#setProgress ProgressBar.setProgress}, and
1690 * {@link ProgressBar#setIndeterminate ProgressBar.setIndeterminate}
1691 *
1692 * If indeterminate is true, then the values for max and progress are ignored.
1693 *
Scott Main93dc6422012-02-24 12:04:06 -08001694 * @param viewId The id of the {@link ProgressBar} to change
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001695 * @param max The 100% value for the progress bar
1696 * @param progress The current value of the progress bar.
1697 * @param indeterminate True if the progress bar is indeterminate,
1698 * false if not.
1699 */
1700 public void setProgressBar(int viewId, int max, int progress,
1701 boolean indeterminate) {
1702 setBoolean(viewId, "setIndeterminate", indeterminate);
1703 if (!indeterminate) {
1704 setInt(viewId, "setMax", max);
1705 setInt(viewId, "setProgress", progress);
1706 }
1707 }
1708
1709 /**
1710 * Equivalent to calling
1711 * {@link android.view.View#setOnClickListener(android.view.View.OnClickListener)}
1712 * to launch the provided {@link PendingIntent}.
1713 *
Adam Cohen35ae9ca2010-09-20 15:20:41 -07001714 * When setting the on-click action of items within collections (eg. {@link ListView},
1715 * {@link StackView} etc.), this method will not work. Instead, use {@link
1716 * RemoteViews#setPendingIntentTemplate(int, PendingIntent) in conjunction with
1717 * RemoteViews#setOnClickFillInIntent(int, Intent).
1718 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001719 * @param viewId The id of the view that will trigger the {@link PendingIntent} when clicked
1720 * @param pendingIntent The {@link PendingIntent} to send when user clicks
1721 */
1722 public void setOnClickPendingIntent(int viewId, PendingIntent pendingIntent) {
1723 addAction(new SetOnClickPendingIntent(viewId, pendingIntent));
1724 }
1725
1726 /**
Adam Cohen35ae9ca2010-09-20 15:20:41 -07001727 * When using collections (eg. {@link ListView}, {@link StackView} etc.) in widgets, it is very
1728 * costly to set PendingIntents on the individual items, and is hence not permitted. Instead
1729 * this method should be used to set a single PendingIntent template on the collection, and
1730 * individual items can differentiate their on-click behavior using
1731 * {@link RemoteViews#setOnClickFillInIntent(int, Intent)}.
Adam Cohenca6fd842010-09-03 18:10:35 -07001732 *
1733 * @param viewId The id of the collection who's children will use this PendingIntent template
1734 * when clicked
1735 * @param pendingIntentTemplate The {@link PendingIntent} to be combined with extras specified
1736 * by a child of viewId and executed when that child is clicked
1737 */
1738 public void setPendingIntentTemplate(int viewId, PendingIntent pendingIntentTemplate) {
1739 addAction(new SetPendingIntentTemplate(viewId, pendingIntentTemplate));
1740 }
1741
1742 /**
Adam Cohen35ae9ca2010-09-20 15:20:41 -07001743 * When using collections (eg. {@link ListView}, {@link StackView} etc.) in widgets, it is very
1744 * costly to set PendingIntents on the individual items, and is hence not permitted. Instead
1745 * a single PendingIntent template can be set on the collection, see {@link
1746 * RemoteViews#setPendingIntentTemplate(int, PendingIntent)}, and the individual on-click
1747 * action of a given item can be distinguished by setting a fillInIntent on that item. The
1748 * fillInIntent is then combined with the PendingIntent template in order to determine the final
1749 * intent which will be executed when the item is clicked. This works as follows: any fields
1750 * which are left blank in the PendingIntent template, but are provided by the fillInIntent
1751 * will be overwritten, and the resulting PendingIntent will be used.
1752 *
1753 *
1754 * of the PendingIntent template will then be filled in with the associated fields that are
1755 * set in fillInIntent. See {@link Intent#fillIn(Intent, int)} for more details.
1756 *
1757 * @param viewId The id of the view on which to set the fillInIntent
1758 * @param fillInIntent The intent which will be combined with the parent's PendingIntent
1759 * in order to determine the on-click behavior of the view specified by viewId
1760 */
1761 public void setOnClickFillInIntent(int viewId, Intent fillInIntent) {
1762 addAction(new SetOnClickFillInIntent(viewId, fillInIntent));
1763 }
1764
1765 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001766 * @hide
1767 * Equivalent to calling a combination of {@link Drawable#setAlpha(int)},
1768 * {@link Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)},
1769 * and/or {@link Drawable#setLevel(int)} on the {@link Drawable} of a given
1770 * view.
1771 * <p>
1772 * You can omit specific calls by marking their values with null or -1.
1773 *
1774 * @param viewId The id of the view that contains the target
1775 * {@link Drawable}
1776 * @param targetBackground If true, apply these parameters to the
1777 * {@link Drawable} returned by
1778 * {@link android.view.View#getBackground()}. Otherwise, assume
1779 * the target view is an {@link ImageView} and apply them to
1780 * {@link ImageView#getDrawable()}.
1781 * @param alpha Specify an alpha value for the drawable, or -1 to leave
1782 * unchanged.
1783 * @param colorFilter Specify a color for a
1784 * {@link android.graphics.ColorFilter} for this drawable, or -1
1785 * to leave unchanged.
1786 * @param mode Specify a PorterDuff mode for this drawable, or null to leave
1787 * unchanged.
1788 * @param level Specify the level for the drawable, or -1 to leave
1789 * unchanged.
1790 */
1791 public void setDrawableParameters(int viewId, boolean targetBackground, int alpha,
1792 int colorFilter, PorterDuff.Mode mode, int level) {
1793 addAction(new SetDrawableParameters(viewId, targetBackground, alpha,
1794 colorFilter, mode, level));
1795 }
1796
1797 /**
1798 * Equivalent to calling {@link android.widget.TextView#setTextColor(int)}.
1799 *
Scott Main93dc6422012-02-24 12:04:06 -08001800 * @param viewId The id of the view whose text color should change
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001801 * @param color Sets the text color for all the states (normal, selected,
1802 * focused) to be this color.
1803 */
1804 public void setTextColor(int viewId, int color) {
1805 setInt(viewId, "setTextColor", color);
1806 }
1807
Joe Onorato592d0652009-03-24 22:25:52 -07001808 /**
Winson Chung499cb9f2010-07-16 11:18:17 -07001809 * Equivalent to calling {@link android.widget.AbsListView#setRemoteViewsAdapter(Intent)}.
1810 *
Winson Chung037300b2011-03-29 15:40:16 -07001811 * @param appWidgetId The id of the app widget which contains the specified view. (This
1812 * parameter is ignored in this deprecated method)
Scott Main93dc6422012-02-24 12:04:06 -08001813 * @param viewId The id of the {@link AbsListView}
Winson Chung037300b2011-03-29 15:40:16 -07001814 * @param intent The intent of the service which will be
1815 * providing data to the RemoteViewsAdapter
1816 * @deprecated This method has been deprecated. See
1817 * {@link android.widget.RemoteViews#setRemoteAdapter(int, Intent)}
1818 */
1819 @Deprecated
1820 public void setRemoteAdapter(int appWidgetId, int viewId, Intent intent) {
1821 setRemoteAdapter(viewId, intent);
1822 }
1823
1824 /**
1825 * Equivalent to calling {@link android.widget.AbsListView#setRemoteViewsAdapter(Intent)}.
1826 * Can only be used for App Widgets.
1827 *
Scott Main93dc6422012-02-24 12:04:06 -08001828 * @param viewId The id of the {@link AbsListView}
Winson Chung81f39eb2011-01-11 18:05:01 -08001829 * @param intent The intent of the service which will be
1830 * providing data to the RemoteViewsAdapter
1831 */
Winson Chung037300b2011-03-29 15:40:16 -07001832 public void setRemoteAdapter(int viewId, Intent intent) {
1833 addAction(new SetRemoteViewsAdapterIntent(viewId, intent));
Winson Chung499cb9f2010-07-16 11:18:17 -07001834 }
1835
1836 /**
1837 * Equivalent to calling {@link android.widget.AbsListView#smoothScrollToPosition(int, int)}.
1838 *
Scott Main93dc6422012-02-24 12:04:06 -08001839 * @param viewId The id of the view to change
Winson Chung499cb9f2010-07-16 11:18:17 -07001840 * @param position Scroll to this adapter position
1841 */
1842 public void setScrollPosition(int viewId, int position) {
1843 setInt(viewId, "smoothScrollToPosition", position);
1844 }
1845
1846 /**
1847 * Equivalent to calling {@link android.widget.AbsListView#smoothScrollToPosition(int, int)}.
1848 *
Scott Main93dc6422012-02-24 12:04:06 -08001849 * @param viewId The id of the view to change
Winson Chung95362592010-07-19 16:05:50 -07001850 * @param offset Scroll by this adapter position offset
Winson Chung499cb9f2010-07-16 11:18:17 -07001851 */
1852 public void setRelativeScrollPosition(int viewId, int offset) {
1853 setInt(viewId, "smoothScrollByOffset", offset);
1854 }
1855
1856 /**
Joe Onorato592d0652009-03-24 22:25:52 -07001857 * Call a method taking one boolean on a view in the layout for this RemoteViews.
1858 *
Scott Main93dc6422012-02-24 12:04:06 -08001859 * @param viewId The id of the view on which to call the method.
Joe Onorato592d0652009-03-24 22:25:52 -07001860 * @param methodName The name of the method to call.
1861 * @param value The value to pass to the method.
1862 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001863 public void setBoolean(int viewId, String methodName, boolean value) {
1864 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.BOOLEAN, value));
1865 }
1866
Joe Onorato592d0652009-03-24 22:25:52 -07001867 /**
1868 * Call a method taking one byte on a view in the layout for this RemoteViews.
1869 *
Scott Main93dc6422012-02-24 12:04:06 -08001870 * @param viewId The id of the view on which to call the method.
Joe Onorato592d0652009-03-24 22:25:52 -07001871 * @param methodName The name of the method to call.
1872 * @param value The value to pass to the method.
1873 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001874 public void setByte(int viewId, String methodName, byte value) {
1875 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.BYTE, value));
1876 }
1877
Joe Onorato592d0652009-03-24 22:25:52 -07001878 /**
1879 * Call a method taking one short on a view in the layout for this RemoteViews.
1880 *
Scott Main93dc6422012-02-24 12:04:06 -08001881 * @param viewId The id of the view on which to call the method.
Joe Onorato592d0652009-03-24 22:25:52 -07001882 * @param methodName The name of the method to call.
1883 * @param value The value to pass to the method.
1884 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001885 public void setShort(int viewId, String methodName, short value) {
1886 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.SHORT, value));
1887 }
1888
Joe Onorato592d0652009-03-24 22:25:52 -07001889 /**
1890 * Call a method taking one int on a view in the layout for this RemoteViews.
1891 *
Scott Main93dc6422012-02-24 12:04:06 -08001892 * @param viewId The id of the view on which to call the method.
Joe Onorato592d0652009-03-24 22:25:52 -07001893 * @param methodName The name of the method to call.
1894 * @param value The value to pass to the method.
1895 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001896 public void setInt(int viewId, String methodName, int value) {
1897 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.INT, value));
1898 }
1899
Joe Onorato592d0652009-03-24 22:25:52 -07001900 /**
1901 * Call a method taking one long on a view in the layout for this RemoteViews.
1902 *
Scott Main93dc6422012-02-24 12:04:06 -08001903 * @param viewId The id of the view on which to call the method.
Joe Onorato592d0652009-03-24 22:25:52 -07001904 * @param methodName The name of the method to call.
1905 * @param value The value to pass to the method.
1906 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001907 public void setLong(int viewId, String methodName, long value) {
1908 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.LONG, value));
1909 }
1910
Joe Onorato592d0652009-03-24 22:25:52 -07001911 /**
1912 * Call a method taking one float on a view in the layout for this RemoteViews.
1913 *
Scott Main93dc6422012-02-24 12:04:06 -08001914 * @param viewId The id of the view on which to call the method.
Joe Onorato592d0652009-03-24 22:25:52 -07001915 * @param methodName The name of the method to call.
1916 * @param value The value to pass to the method.
1917 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001918 public void setFloat(int viewId, String methodName, float value) {
1919 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.FLOAT, value));
1920 }
1921
Joe Onorato592d0652009-03-24 22:25:52 -07001922 /**
1923 * Call a method taking one double on a view in the layout for this RemoteViews.
1924 *
Scott Main93dc6422012-02-24 12:04:06 -08001925 * @param viewId The id of the view on which to call the method.
Joe Onorato592d0652009-03-24 22:25:52 -07001926 * @param methodName The name of the method to call.
1927 * @param value The value to pass to the method.
1928 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001929 public void setDouble(int viewId, String methodName, double value) {
1930 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.DOUBLE, value));
1931 }
1932
Joe Onorato592d0652009-03-24 22:25:52 -07001933 /**
1934 * Call a method taking one char on a view in the layout for this RemoteViews.
1935 *
Scott Main93dc6422012-02-24 12:04:06 -08001936 * @param viewId The id of the view on which to call the method.
Joe Onorato592d0652009-03-24 22:25:52 -07001937 * @param methodName The name of the method to call.
1938 * @param value The value to pass to the method.
1939 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001940 public void setChar(int viewId, String methodName, char value) {
1941 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.CHAR, value));
1942 }
1943
Joe Onorato592d0652009-03-24 22:25:52 -07001944 /**
1945 * Call a method taking one String on a view in the layout for this RemoteViews.
1946 *
Scott Main93dc6422012-02-24 12:04:06 -08001947 * @param viewId The id of the view on which to call the method.
Joe Onorato592d0652009-03-24 22:25:52 -07001948 * @param methodName The name of the method to call.
1949 * @param value The value to pass to the method.
1950 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001951 public void setString(int viewId, String methodName, String value) {
1952 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.STRING, value));
1953 }
1954
Joe Onorato592d0652009-03-24 22:25:52 -07001955 /**
1956 * Call a method taking one CharSequence on a view in the layout for this RemoteViews.
1957 *
Scott Main93dc6422012-02-24 12:04:06 -08001958 * @param viewId The id of the view on which to call the method.
Joe Onorato592d0652009-03-24 22:25:52 -07001959 * @param methodName The name of the method to call.
1960 * @param value The value to pass to the method.
1961 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001962 public void setCharSequence(int viewId, String methodName, CharSequence value) {
1963 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.CHAR_SEQUENCE, value));
1964 }
1965
Joe Onorato592d0652009-03-24 22:25:52 -07001966 /**
1967 * Call a method taking one Uri on a view in the layout for this RemoteViews.
1968 *
Scott Main93dc6422012-02-24 12:04:06 -08001969 * @param viewId The id of the view on which to call the method.
Joe Onorato592d0652009-03-24 22:25:52 -07001970 * @param methodName The name of the method to call.
1971 * @param value The value to pass to the method.
1972 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001973 public void setUri(int viewId, String methodName, Uri value) {
1974 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.URI, value));
1975 }
1976
Joe Onorato592d0652009-03-24 22:25:52 -07001977 /**
1978 * Call a method taking one Bitmap on a view in the layout for this RemoteViews.
1979 * @more
1980 * <p class="note">The bitmap will be flattened into the parcel if this object is
1981 * sent across processes, so it may end up using a lot of memory, and may be fairly slow.</p>
1982 *
Scott Main93dc6422012-02-24 12:04:06 -08001983 * @param viewId The id of the view on which to call the method.
Joe Onorato592d0652009-03-24 22:25:52 -07001984 * @param methodName The name of the method to call.
1985 * @param value The value to pass to the method.
1986 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001987 public void setBitmap(int viewId, String methodName, Bitmap value) {
Adam Cohen5d200642012-04-24 10:43:31 -07001988 addAction(new BitmapReflectionAction(viewId, methodName, value));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001989 }
1990
1991 /**
Bjorn Bringertd755b062010-01-06 17:15:37 +00001992 * Call a method taking one Bundle on a view in the layout for this RemoteViews.
1993 *
Scott Main93dc6422012-02-24 12:04:06 -08001994 * @param viewId The id of the view on which to call the method.
Bjorn Bringertd755b062010-01-06 17:15:37 +00001995 * @param methodName The name of the method to call.
1996 * @param value The value to pass to the method.
1997 */
1998 public void setBundle(int viewId, String methodName, Bundle value) {
1999 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.BUNDLE, value));
2000 }
2001
2002 /**
Scott Main93dc6422012-02-24 12:04:06 -08002003 * Call a method taking one Intent on a view in the layout for this RemoteViews.
Winson Chung499cb9f2010-07-16 11:18:17 -07002004 *
Scott Main93dc6422012-02-24 12:04:06 -08002005 * @param viewId The id of the view on which to call the method.
2006 * @param methodName The name of the method to call.
2007 * @param value The {@link android.content.Intent} to pass the method.
Winson Chung499cb9f2010-07-16 11:18:17 -07002008 */
2009 public void setIntent(int viewId, String methodName, Intent value) {
2010 addAction(new ReflectionAction(viewId, methodName, ReflectionAction.INTENT, value));
2011 }
2012
2013 /**
Svetoslav Ganove261e282011-10-18 17:47:04 -07002014 * Equivalent to calling View.setContentDescription
2015 *
2016 * @param viewId The id of the view whose content description should change
2017 * @param contentDescription The new content description for the view
2018 */
2019 public void setContentDescription(int viewId, CharSequence contentDescription) {
2020 setCharSequence(viewId, "setContentDescription", contentDescription);
2021 }
2022
Adam Cohen5d200642012-04-24 10:43:31 -07002023 private RemoteViews getRemoteViewsToApply(Context context) {
2024 if (hasLandscapeAndPortraitLayouts()) {
2025 int orientation = context.getResources().getConfiguration().orientation;
2026 if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
2027 return mLandscape;
2028 } else {
2029 return mPortrait;
2030 }
2031 }
2032 return this;
2033 }
2034
Svetoslav Ganove261e282011-10-18 17:47:04 -07002035 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002036 * Inflates the view hierarchy represented by this object and applies
2037 * all of the actions.
2038 *
2039 * <p><strong>Caller beware: this may throw</strong>
2040 *
2041 * @param context Default context to use
2042 * @param parent Parent that the resulting view hierarchy will be attached to. This method
2043 * does <strong>not</strong> attach the hierarchy. The caller should do so when appropriate.
2044 * @return The inflated view hierarchy
2045 */
2046 public View apply(Context context, ViewGroup parent) {
Adam Cohen5d200642012-04-24 10:43:31 -07002047 RemoteViews rvToApply = getRemoteViewsToApply(context);
2048
Romain Guya5475592009-07-01 17:20:08 -07002049 View result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002050
2051 Context c = prepareContext(context);
2052
Romain Guya5475592009-07-01 17:20:08 -07002053 LayoutInflater inflater = (LayoutInflater)
2054 c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002055
2056 inflater = inflater.cloneInContext(c);
2057 inflater.setFilter(this);
2058
Adam Cohen5d200642012-04-24 10:43:31 -07002059 result = inflater.inflate(rvToApply.getLayoutId(), parent, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002060
Adam Cohen5d200642012-04-24 10:43:31 -07002061 rvToApply.performApply(result, parent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002062
2063 return result;
2064 }
Adam Cohen5d200642012-04-24 10:43:31 -07002065
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002066 /**
2067 * Applies all of the actions to the provided view.
2068 *
2069 * <p><strong>Caller beware: this may throw</strong>
2070 *
2071 * @param v The view to apply the actions to. This should be the result of
2072 * the {@link #apply(Context,ViewGroup)} call.
2073 */
2074 public void reapply(Context context, View v) {
Adam Cohen5d200642012-04-24 10:43:31 -07002075 RemoteViews rvToApply = getRemoteViewsToApply(context);
2076
2077 // In the case that a view has this RemoteViews applied in one orientation, is persisted
2078 // across orientation change, and has the RemoteViews re-applied in the new orientation,
2079 // we throw an exception, since the layouts may be completely unrelated.
2080 if (hasLandscapeAndPortraitLayouts()) {
2081 if (v.getId() != rvToApply.getLayoutId()) {
2082 throw new RuntimeException("Attempting to re-apply RemoteViews to a view that" +
2083 " that does not share the same root layout id.");
2084 }
2085 }
2086
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002087 prepareContext(context);
Adam Cohen5d200642012-04-24 10:43:31 -07002088 rvToApply.performApply(v, (ViewGroup) v.getParent());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002089 }
2090
Winson Chung037300b2011-03-29 15:40:16 -07002091 private void performApply(View v, ViewGroup parent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002092 if (mActions != null) {
2093 final int count = mActions.size();
2094 for (int i = 0; i < count; i++) {
2095 Action a = mActions.get(i);
Winson Chung037300b2011-03-29 15:40:16 -07002096 a.apply(v, parent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002097 }
2098 }
2099 }
2100
2101 private Context prepareContext(Context context) {
Romain Guya5475592009-07-01 17:20:08 -07002102 Context c;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002103 String packageName = mPackage;
2104
2105 if (packageName != null) {
2106 try {
Romain Guy870e09f2009-07-06 16:35:25 -07002107 c = context.createPackageContext(packageName, Context.CONTEXT_RESTRICTED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002108 } catch (NameNotFoundException e) {
2109 Log.e(LOG_TAG, "Package name " + packageName + " not found");
2110 c = context;
2111 }
2112 } else {
2113 c = context;
2114 }
2115
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002116 return c;
2117 }
2118
2119 /* (non-Javadoc)
2120 * Used to restrict the views which can be inflated
2121 *
2122 * @see android.view.LayoutInflater.Filter#onLoadClass(java.lang.Class)
2123 */
Gilles Debunnee6ac8b92010-06-17 10:55:04 -07002124 public boolean onLoadClass(Class clazz) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002125 return clazz.isAnnotationPresent(RemoteView.class);
2126 }
Adam Cohen5d200642012-04-24 10:43:31 -07002127
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002128 public int describeContents() {
2129 return 0;
2130 }
2131
2132 public void writeToParcel(Parcel dest, int flags) {
Adam Cohen5d200642012-04-24 10:43:31 -07002133 if (!hasLandscapeAndPortraitLayouts()) {
2134 dest.writeInt(MODE_NORMAL);
2135 // We only write the bitmap cache if we are the root RemoteViews, as this cache
2136 // is shared by all children.
2137 if (mIsRoot) {
2138 mBitmapCache.writeBitmapsToParcel(dest, flags);
2139 }
2140 dest.writeString(mPackage);
2141 dest.writeInt(mLayoutId);
2142 dest.writeInt(mIsWidgetCollectionChild ? 1 : 0);
2143 int count;
2144 if (mActions != null) {
2145 count = mActions.size();
2146 } else {
2147 count = 0;
2148 }
2149 dest.writeInt(count);
2150 for (int i=0; i<count; i++) {
2151 Action a = mActions.get(i);
2152 a.writeToParcel(dest, 0);
2153 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002154 } else {
Adam Cohen5d200642012-04-24 10:43:31 -07002155 dest.writeInt(MODE_HAS_LANDSCAPE_AND_PORTRAIT);
2156 // We only write the bitmap cache if we are the root RemoteViews, as this cache
2157 // is shared by all children.
2158 if (mIsRoot) {
2159 mBitmapCache.writeBitmapsToParcel(dest, flags);
2160 }
2161 mLandscape.writeToParcel(dest, flags);
2162 mPortrait.writeToParcel(dest, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002163 }
2164 }
2165
2166 /**
2167 * Parcelable.Creator that instantiates RemoteViews objects
2168 */
2169 public static final Parcelable.Creator<RemoteViews> CREATOR = new Parcelable.Creator<RemoteViews>() {
2170 public RemoteViews createFromParcel(Parcel parcel) {
2171 return new RemoteViews(parcel);
2172 }
2173
2174 public RemoteViews[] newArray(int size) {
2175 return new RemoteViews[size];
2176 }
2177 };
2178}