diff options
| author | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
|---|---|---|
| committer | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
| commit | 54b6cfa9a9e5b861a9930af873580d6dc20f773c (patch) | |
| tree | 35051494d2af230dce54d6b31c6af8fc24091316 /core/java/android/widget/RemoteViews.java | |
Initial Contribution
Diffstat (limited to 'core/java/android/widget/RemoteViews.java')
| -rw-r--r-- | core/java/android/widget/RemoteViews.java | 649 |
1 files changed, 649 insertions, 0 deletions
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java new file mode 100644 index 000000000000..54951b7d3206 --- /dev/null +++ b/core/java/android/widget/RemoteViews.java @@ -0,0 +1,649 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.widget; + +import android.content.Context; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.LayoutInflater.Filter; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.ArrayList; + + +/** + * A class that describes a view hierarchy that can be displayed in + * another process. The hierarchy is inflated from a layout resource + * file, and this class provides some basic operations for modifying + * the content of the inflated hierarchy. + */ +public class RemoteViews implements Parcelable, Filter { + + private static final String LOG_TAG = "RemoteViews"; + + /** + * The package name of the package containing the layout + * resource. (Added to the parcel) + */ + private String mPackage; + + /** + * The resource ID of the layout file. (Added to the parcel) + */ + private int mLayoutId; + + /** + * The Context object used to inflate the layout file. Also may + * be used by actions if they need access to the senders resources. + */ + private Context mContext; + + /** + * An array of actions to perform on the view tree once it has been + * inflated + */ + private ArrayList<Action> mActions; + + + /** + * This annotation indicates that a subclass of View is alllowed to be used with the + * {@link android.widget.RemoteViews} mechanism. + */ + @Target({ ElementType.TYPE }) + @Retention(RetentionPolicy.RUNTIME) + public @interface RemoteView { + } + + /** + * Exception to send when something goes wrong executing an action + * + */ + public static class ActionException extends RuntimeException { + public ActionException(String message) { + super(message); + } + } + + /** + * Base class for all actions that can be performed on an + * inflated view. + * + */ + private abstract static class Action implements Parcelable { + public abstract void apply(View root) throws ActionException; + + public int describeContents() { + return 0; + } + }; + + /** + * Equivalent to calling View.setVisibility + */ + private class SetViewVisibility extends Action { + public SetViewVisibility(int id, int vis) { + viewId = id; + visibility = vis; + } + + public SetViewVisibility(Parcel parcel) { + viewId = parcel.readInt(); + visibility = parcel.readInt(); + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(TAG); + dest.writeInt(viewId); + dest.writeInt(visibility); + } + + @Override + public void apply(View root) { + View target = root.findViewById(viewId); + if (target != null) { + target.setVisibility(visibility); + } + } + + private int viewId; + private int visibility; + public final static int TAG = 0; + } + + /** + * Equivalent to calling TextView.setText + */ + private class SetTextViewText extends Action { + public SetTextViewText(int id, CharSequence t) { + viewId = id; + text = t; + } + + public SetTextViewText(Parcel parcel) { + viewId = parcel.readInt(); + text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(TAG); + dest.writeInt(viewId); + TextUtils.writeToParcel(text, dest, flags); + } + + @Override + public void apply(View root) { + TextView target = (TextView) root.findViewById(viewId); + if (target != null) { + target.setText(text); + } + } + + int viewId; + CharSequence text; + public final static int TAG = 1; + } + + /** + * Equivalent to calling ImageView.setResource + */ + private class SetImageViewResource extends Action { + public SetImageViewResource(int id, int src) { + viewId = id; + srcId = src; + } + + public SetImageViewResource(Parcel parcel) { + viewId = parcel.readInt(); + srcId = parcel.readInt(); + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(TAG); + dest.writeInt(viewId); + dest.writeInt(srcId); + } + + @Override + public void apply(View root) { + ImageView target = (ImageView) root.findViewById(viewId); + Drawable d = mContext.getResources().getDrawable(srcId); + if (target != null) { + target.setImageDrawable(d); + } + } + + int viewId; + int srcId; + public final static int TAG = 2; + } + + /** + * Equivalent to calling ImageView.setImageURI + */ + private class SetImageViewUri extends Action { + public SetImageViewUri(int id, Uri u) { + viewId = id; + uri = u; + } + + public SetImageViewUri(Parcel parcel) { + viewId = parcel.readInt(); + uri = Uri.CREATOR.createFromParcel(parcel); + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(TAG); + dest.writeInt(viewId); + Uri.writeToParcel(dest, uri); + } + + @Override + public void apply(View root) { + ImageView target = (ImageView) root.findViewById(viewId); + if (target != null) { + target.setImageURI(uri); + } + } + + int viewId; + Uri uri; + public final static int TAG = 3; + } + + /** + * Equivalent to calling ImageView.setImageBitmap + */ + private class SetImageViewBitmap extends Action { + public SetImageViewBitmap(int id, Bitmap src) { + viewId = id; + bitmap = src; + } + + public SetImageViewBitmap(Parcel parcel) { + viewId = parcel.readInt(); + bitmap = Bitmap.CREATOR.createFromParcel(parcel); + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(TAG); + dest.writeInt(viewId); + if (bitmap != null) { + bitmap.writeToParcel(dest, flags); + } + } + + @Override + public void apply(View root) { + if (bitmap != null) { + ImageView target = (ImageView) root.findViewById(viewId); + Drawable d = new BitmapDrawable(bitmap); + if (target != null) { + target.setImageDrawable(d); + } + } + } + + int viewId; + Bitmap bitmap; + public final static int TAG = 4; + } + + /** + * Equivalent to calling Chronometer.setBase, Chronometer.setFormat, + * and Chronometer.start/stop. + */ + private class SetChronometer extends Action { + public SetChronometer(int id, long base, String format, boolean running) { + this.viewId = id; + this.base = base; + this.format = format; + this.running = running; + } + + public SetChronometer(Parcel parcel) { + viewId = parcel.readInt(); + base = parcel.readLong(); + format = parcel.readString(); + running = parcel.readInt() != 0; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(TAG); + dest.writeInt(viewId); + dest.writeLong(base); + dest.writeString(format); + dest.writeInt(running ? 1 : 0); + } + + @Override + public void apply(View root) { + Chronometer target = (Chronometer) root.findViewById(viewId); + if (target != null) { + target.setBase(base); + target.setFormat(format); + if (running) { + target.start(); + } else { + target.stop(); + } + } + } + + int viewId; + boolean running; + long base; + String format; + + public final static int TAG = 5; + } + + /** + * Equivalent to calling ProgressBar.setMax, ProgressBar.setProgress and + * ProgressBar.setIndeterminate + */ + private class SetProgressBar extends Action { + public SetProgressBar(int id, int max, int progress, boolean indeterminate) { + this.viewId = id; + this.progress = progress; + this.max = max; + this.indeterminate = indeterminate; + } + + public SetProgressBar(Parcel parcel) { + viewId = parcel.readInt(); + progress = parcel.readInt(); + max = parcel.readInt(); + indeterminate = parcel.readInt() != 0; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(TAG); + dest.writeInt(viewId); + dest.writeInt(progress); + dest.writeInt(max); + dest.writeInt(indeterminate ? 1 : 0); + } + + @Override + public void apply(View root) { + ProgressBar target = (ProgressBar) root.findViewById(viewId); + if (target != null) { + target.setIndeterminate(indeterminate); + if (!indeterminate) { + target.setMax(max); + target.setProgress(progress); + } + } + } + + int viewId; + boolean indeterminate; + int progress; + int max; + + public final static int TAG = 6; + } + + /** + * Create a new RemoteViews object that will display the views contained + * in the specified layout file. + * + * @param packageName Name of the package that contains the layout resource + * @param layoutId The id of the layout resource + */ + public RemoteViews(String packageName, int layoutId) { + mPackage = packageName; + mLayoutId = layoutId; + } + + /** + * Reads a RemoteViews object from a parcel. + * + * @param parcel + */ + public RemoteViews(Parcel parcel) { + mPackage = parcel.readString(); + mLayoutId = parcel.readInt(); + int count = parcel.readInt(); + if (count > 0) { + mActions = new ArrayList<Action>(count); + for (int i=0; i<count; i++) { + int tag = parcel.readInt(); + switch (tag) { + case SetViewVisibility.TAG: + mActions.add(new SetViewVisibility(parcel)); + break; + case SetTextViewText.TAG: + mActions.add(new SetTextViewText(parcel)); + break; + case SetImageViewResource.TAG: + mActions.add(new SetImageViewResource(parcel)); + break; + case SetImageViewUri.TAG: + mActions.add(new SetImageViewUri(parcel)); + break; + case SetImageViewBitmap.TAG: + mActions.add(new SetImageViewBitmap(parcel)); + break; + case SetChronometer.TAG: + mActions.add(new SetChronometer(parcel)); + break; + case SetProgressBar.TAG: + mActions.add(new SetProgressBar(parcel)); + break; + default: + throw new ActionException("Tag " + tag + "not found"); + } + } + } + } + + public String getPackage() { + return mPackage; + } + + public int getLayoutId() { + return mLayoutId; + } + + /** + * Add an action to be executed on the remote side when apply is called. + * + * @param a The action to add + */ + private void addAction(Action a) { + if (mActions == null) { + mActions = new ArrayList<Action>(); + } + mActions.add(a); + } + + /** + * Equivalent to calling View.setVisibility + * + * @param viewId The id of the view whose visibility should change + * @param visibility The new visibility for the view + */ + public void setViewVisibility(int viewId, int visibility) { + addAction(new SetViewVisibility(viewId, visibility)); + } + + /** + * Equivalent to calling TextView.setText + * + * @param viewId The id of the view whose text should change + * @param text The new text for the view + */ + public void setTextViewText(int viewId, CharSequence text) { + addAction(new SetTextViewText(viewId, text)); + } + + /** + * Equivalent to calling ImageView.setImageResource + * + * @param viewId The id of the view whose drawable should change + * @param srcId The new resource id for the drawable + */ + public void setImageViewResource(int viewId, int srcId) { + addAction(new SetImageViewResource(viewId, srcId)); + } + + /** + * Equivalent to calling ImageView.setImageURI + * + * @param viewId The id of the view whose drawable should change + * @param uri The Uri for the image + */ + public void setImageViewUri(int viewId, Uri uri) { + addAction(new SetImageViewUri(viewId, uri)); + } + + /** + * Equivalent to calling ImageView.setImageBitmap + * + * @param viewId The id of the view whose drawable should change + * @param bitmap The new Bitmap for the drawable + * + * @hide pending API Council approval to extend the public API + */ + public void setImageViewBitmap(int viewId, Bitmap bitmap) { + addAction(new SetImageViewBitmap(viewId, bitmap)); + } + + /** + * Equivalent to calling {@link Chronometer#setBase Chronometer.setBase}, + * {@link Chronometer#setFormat Chronometer.setFormat}, + * and {@link Chronometer#start Chronometer.start()} or + * {@link Chronometer#stop Chronometer.stop()}. + * + * @param viewId The id of the view whose text should change + * @param base The time at which the timer would have read 0:00. This + * time should be based off of + * {@link android.os.SystemClock#elapsedRealtime SystemClock.elapsedRealtime()}. + * @param format The Chronometer format string, or null to + * simply display the timer value. + * @param running True if you want the clock to be running, false if not. + */ + public void setChronometer(int viewId, long base, String format, boolean running) { + addAction(new SetChronometer(viewId, base, format, running)); + } + + /** + * Equivalent to calling {@link ProgressBar#setMax ProgressBar.setMax}, + * {@link ProgressBar#setProgress ProgressBar.setProgress}, and + * {@link ProgressBar#setIndeterminate ProgressBar.setIndeterminate} + * + * @param viewId The id of the view whose text should change + * @param max The 100% value for the progress bar + * @param progress The current value of the progress bar. + * @param indeterminate True if the progress bar is indeterminate, + * false if not. + */ + public void setProgressBar(int viewId, int max, int progress, + boolean indeterminate) { + addAction(new SetProgressBar(viewId, max, progress, indeterminate)); + } + + /** + * Inflates the view hierarchy represented by this object and applies + * all of the actions. + * + * <p><strong>Caller beware: this may throw</strong> + * + * @param context Default context to use + * @param parent Parent that the resulting view hierarchy will be attached to. This method + * does <strong>not</strong> attach the hierarchy. The caller should do so when appropriate. + * @return The inflated view hierarchy + */ + public View apply(Context context, ViewGroup parent) { + View result = null; + + Context c = prepareContext(context); + + Resources r = c.getResources(); + LayoutInflater inflater = (LayoutInflater) c + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + inflater = inflater.cloneInContext(c); + inflater.setFilter(this); + + result = inflater.inflate(mLayoutId, parent, false); + + performApply(result); + + return result; + } + + /** + * Applies all of the actions to the provided view. + * + * <p><strong>Caller beware: this may throw</strong> + * + * @param v The view to apply the actions to. This should be the result of + * the {@link #apply(Context,ViewGroup)} call. + */ + public void reapply(Context context, View v) { + prepareContext(context); + performApply(v); + } + + private void performApply(View v) { + if (mActions != null) { + final int count = mActions.size(); + for (int i = 0; i < count; i++) { + Action a = mActions.get(i); + a.apply(v); + } + } + } + + private Context prepareContext(Context context) { + Context c = null; + String packageName = mPackage; + + if (packageName != null) { + try { + c = context.createPackageContext(packageName, 0); + } catch (NameNotFoundException e) { + Log.e(LOG_TAG, "Package name " + packageName + " not found"); + c = context; + } + } else { + c = context; + } + + mContext = c; + + return c; + } + + /* (non-Javadoc) + * Used to restrict the views which can be inflated + * + * @see android.view.LayoutInflater.Filter#onLoadClass(java.lang.Class) + */ + public boolean onLoadClass(Class clazz) { + return clazz.isAnnotationPresent(RemoteView.class); + } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(mPackage); + dest.writeInt(mLayoutId); + int count; + if (mActions != null) { + count = mActions.size(); + } else { + count = 0; + } + dest.writeInt(count); + for (int i=0; i<count; i++) { + Action a = mActions.get(i); + a.writeToParcel(dest, 0); + } + } + + /** + * Parcelable.Creator that instantiates RemoteViews objects + */ + public static final Parcelable.Creator<RemoteViews> CREATOR = new Parcelable.Creator<RemoteViews>() { + public RemoteViews createFromParcel(Parcel parcel) { + return new RemoteViews(parcel); + } + + public RemoteViews[] newArray(int size) { + return new RemoteViews[size]; + } + }; +} |
