M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions

View File

@ -0,0 +1,255 @@
/*
* Copyright (C) 2009 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.appwidget;
import android.content.Context;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.widget.RemoteViews;
import java.util.ArrayList;
import java.util.HashMap;
import com.android.internal.appwidget.IAppWidgetHost;
import com.android.internal.appwidget.IAppWidgetService;
/**
* AppWidgetHost provides the interaction with the AppWidget service for apps,
* like the home screen, that want to embed AppWidgets in their UI.
*/
public class AppWidgetHost {
static final int HANDLE_UPDATE = 1;
static final int HANDLE_PROVIDER_CHANGED = 2;
final static Object sServiceLock = new Object();
static IAppWidgetService sService;
Context mContext;
String mPackageName;
class Callbacks extends IAppWidgetHost.Stub {
public void updateAppWidget(int appWidgetId, RemoteViews views) {
Message msg = mHandler.obtainMessage(HANDLE_UPDATE);
msg.arg1 = appWidgetId;
msg.obj = views;
msg.sendToTarget();
}
public void providerChanged(int appWidgetId, AppWidgetProviderInfo info) {
Message msg = mHandler.obtainMessage(HANDLE_PROVIDER_CHANGED);
msg.arg1 = appWidgetId;
msg.obj = info;
msg.sendToTarget();
}
}
class UpdateHandler extends Handler {
public UpdateHandler(Looper looper) {
super(looper);
}
public void handleMessage(Message msg) {
switch (msg.what) {
case HANDLE_UPDATE: {
updateAppWidgetView(msg.arg1, (RemoteViews)msg.obj);
break;
}
case HANDLE_PROVIDER_CHANGED: {
onProviderChanged(msg.arg1, (AppWidgetProviderInfo)msg.obj);
break;
}
}
}
}
Handler mHandler;
int mHostId;
Callbacks mCallbacks = new Callbacks();
final HashMap<Integer,AppWidgetHostView> mViews = new HashMap<Integer, AppWidgetHostView>();
public AppWidgetHost(Context context, int hostId) {
mContext = context;
mHostId = hostId;
mHandler = new UpdateHandler(context.getMainLooper());
synchronized (sServiceLock) {
if (sService == null) {
IBinder b = ServiceManager.getService(Context.APPWIDGET_SERVICE);
sService = IAppWidgetService.Stub.asInterface(b);
}
}
}
/**
* Start receiving onAppWidgetChanged calls for your AppWidgets. Call this when your activity
* becomes visible, i.e. from onStart() in your Activity.
*/
public void startListening() {
int[] updatedIds;
ArrayList<RemoteViews> updatedViews = new ArrayList<RemoteViews>();
try {
if (mPackageName == null) {
mPackageName = mContext.getPackageName();
}
updatedIds = sService.startListening(mCallbacks, mPackageName, mHostId, updatedViews);
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
}
final int N = updatedIds.length;
for (int i=0; i<N; i++) {
updateAppWidgetView(updatedIds[i], updatedViews.get(i));
}
}
/**
* Stop receiving onAppWidgetChanged calls for your AppWidgets. Call this when your activity is
* no longer visible, i.e. from onStop() in your Activity.
*/
public void stopListening() {
try {
sService.stopListening(mHostId);
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
}
}
/**
* Get a appWidgetId for a host in the calling process.
*
* @return a appWidgetId
*/
public int allocateAppWidgetId() {
try {
if (mPackageName == null) {
mPackageName = mContext.getPackageName();
}
return sService.allocateAppWidgetId(mPackageName, mHostId);
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
}
}
/**
* Stop listening to changes for this AppWidget.
*/
public void deleteAppWidgetId(int appWidgetId) {
synchronized (mViews) {
mViews.remove(appWidgetId);
try {
sService.deleteAppWidgetId(appWidgetId);
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
}
}
}
/**
* Remove all records about this host from the AppWidget manager.
* <ul>
* <li>Call this when initializing your database, as it might be because of a data wipe.</li>
* <li>Call this to have the AppWidget manager release all resources associated with your
* host. Any future calls about this host will cause the records to be re-allocated.</li>
* </ul>
*/
public void deleteHost() {
try {
sService.deleteHost(mHostId);
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
}
}
/**
* Remove all records about all hosts for your package.
* <ul>
* <li>Call this when initializing your database, as it might be because of a data wipe.</li>
* <li>Call this to have the AppWidget manager release all resources associated with your
* host. Any future calls about this host will cause the records to be re-allocated.</li>
* </ul>
*/
public static void deleteAllHosts() {
try {
sService.deleteAllHosts();
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
}
}
public final AppWidgetHostView createView(Context context, int appWidgetId,
AppWidgetProviderInfo appWidget) {
AppWidgetHostView view = onCreateView(context, appWidgetId, appWidget);
view.setAppWidget(appWidgetId, appWidget);
synchronized (mViews) {
mViews.put(appWidgetId, view);
}
RemoteViews views;
try {
views = sService.getAppWidgetViews(appWidgetId);
} catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
}
view.updateAppWidget(views);
return view;
}
/**
* Called to create the AppWidgetHostView. Override to return a custom subclass if you
* need it. {@more}
*/
protected AppWidgetHostView onCreateView(Context context, int appWidgetId,
AppWidgetProviderInfo appWidget) {
return new AppWidgetHostView(context);
}
/**
* Called when the AppWidget provider for a AppWidget has been upgraded to a new apk.
*/
protected void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidget) {
AppWidgetHostView v;
synchronized (mViews) {
v = mViews.get(appWidgetId);
}
if (v != null) {
v.resetAppWidget(appWidget);
}
}
void updateAppWidgetView(int appWidgetId, RemoteViews views) {
AppWidgetHostView v;
synchronized (mViews) {
v = mViews.get(appWidgetId);
}
if (v != null) {
v.updateAppWidget(views);
}
}
}

View File

@ -0,0 +1,415 @@
/*
* Copyright (C) 2008 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.appwidget;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.SystemClock;
import android.os.Parcelable;
import android.os.Parcel;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.RemoteViews;
import android.widget.TextView;
/**
* Provides the glue to show AppWidget views. This class offers automatic animation
* between updates, and will try recycling old views for each incoming
* {@link RemoteViews}.
*/
public class AppWidgetHostView extends FrameLayout {
static final String TAG = "AppWidgetHostView";
static final boolean LOGD = false;
static final boolean CROSSFADE = false;
static final int VIEW_MODE_NOINIT = 0;
static final int VIEW_MODE_CONTENT = 1;
static final int VIEW_MODE_ERROR = 2;
static final int VIEW_MODE_DEFAULT = 3;
static final int FADE_DURATION = 1000;
// When we're inflating the initialLayout for a AppWidget, we only allow
// views that are allowed in RemoteViews.
static final LayoutInflater.Filter sInflaterFilter = new LayoutInflater.Filter() {
public boolean onLoadClass(Class clazz) {
return clazz.isAnnotationPresent(RemoteViews.RemoteView.class);
}
};
Context mContext;
Context mRemoteContext;
int mAppWidgetId;
AppWidgetProviderInfo mInfo;
View mView;
int mViewMode = VIEW_MODE_NOINIT;
int mLayoutId = -1;
long mFadeStartTime = -1;
Bitmap mOld;
Paint mOldPaint = new Paint();
/**
* Create a host view. Uses default fade animations.
*/
public AppWidgetHostView(Context context) {
this(context, android.R.anim.fade_in, android.R.anim.fade_out);
}
/**
* Create a host view. Uses specified animations when pushing
* {@link #updateAppWidget(RemoteViews)}.
*
* @param animationIn Resource ID of in animation to use
* @param animationOut Resource ID of out animation to use
*/
@SuppressWarnings({"UnusedDeclaration"})
public AppWidgetHostView(Context context, int animationIn, int animationOut) {
super(context);
mContext = context;
}
/**
* Set the AppWidget that will be displayed by this view.
*/
public void setAppWidget(int appWidgetId, AppWidgetProviderInfo info) {
mAppWidgetId = appWidgetId;
mInfo = info;
}
public int getAppWidgetId() {
return mAppWidgetId;
}
public AppWidgetProviderInfo getAppWidgetInfo() {
return mInfo;
}
@Override
protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
final ParcelableSparseArray jail = new ParcelableSparseArray();
super.dispatchSaveInstanceState(jail);
container.put(generateId(), jail);
}
private int generateId() {
final int id = getId();
return id == View.NO_ID ? mAppWidgetId : id;
}
@Override
protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
final Parcelable parcelable = container.get(generateId());
ParcelableSparseArray jail = null;
if (parcelable != null && parcelable instanceof ParcelableSparseArray) {
jail = (ParcelableSparseArray) parcelable;
}
if (jail == null) jail = new ParcelableSparseArray();
super.dispatchRestoreInstanceState(jail);
}
/** {@inheritDoc} */
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
// We're being asked to inflate parameters, probably by a LayoutInflater
// in a remote Context. To help resolve any remote references, we
// inflate through our last mRemoteContext when it exists.
final Context context = mRemoteContext != null ? mRemoteContext : mContext;
return new FrameLayout.LayoutParams(context, attrs);
}
/**
* Update the AppWidgetProviderInfo for this view, and reset it to the
* initial layout.
*/
void resetAppWidget(AppWidgetProviderInfo info) {
mInfo = info;
mViewMode = VIEW_MODE_NOINIT;
updateAppWidget(null);
}
/**
* Process a set of {@link RemoteViews} coming in as an update from the
* AppWidget provider. Will animate into these new views as needed
*/
public void updateAppWidget(RemoteViews remoteViews) {
if (LOGD) Log.d(TAG, "updateAppWidget called mOld=" + mOld);
boolean recycled = false;
View content = null;
Exception exception = null;
// Capture the old view into a bitmap so we can do the crossfade.
if (CROSSFADE) {
if (mFadeStartTime < 0) {
if (mView != null) {
final int width = mView.getWidth();
final int height = mView.getHeight();
try {
mOld = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
} catch (OutOfMemoryError e) {
// we just won't do the fade
mOld = null;
}
if (mOld != null) {
//mView.drawIntoBitmap(mOld);
}
}
}
}
if (remoteViews == null) {
if (mViewMode == VIEW_MODE_DEFAULT) {
// We've already done this -- nothing to do.
return;
}
content = getDefaultView();
mLayoutId = -1;
mViewMode = VIEW_MODE_DEFAULT;
} else {
// Prepare a local reference to the remote Context so we're ready to
// inflate any requested LayoutParams.
mRemoteContext = getRemoteContext(remoteViews);
int layoutId = remoteViews.getLayoutId();
// If our stale view has been prepared to match active, and the new
// layout matches, try recycling it
if (content == null && layoutId == mLayoutId) {
try {
remoteViews.reapply(mContext, mView);
content = mView;
recycled = true;
if (LOGD) Log.d(TAG, "was able to recycled existing layout");
} catch (RuntimeException e) {
exception = e;
}
}
// Try normal RemoteView inflation
if (content == null) {
try {
content = remoteViews.apply(mContext, this);
if (LOGD) Log.d(TAG, "had to inflate new layout");
} catch (RuntimeException e) {
exception = e;
}
}
mLayoutId = layoutId;
mViewMode = VIEW_MODE_CONTENT;
}
if (content == null) {
if (mViewMode == VIEW_MODE_ERROR) {
// We've already done this -- nothing to do.
return ;
}
Log.w(TAG, "updateAppWidget couldn't find any view, using error view", exception);
content = getErrorView();
mViewMode = VIEW_MODE_ERROR;
}
if (!recycled) {
prepareView(content);
addView(content);
}
if (mView != content) {
removeView(mView);
mView = content;
}
if (CROSSFADE) {
if (mFadeStartTime < 0) {
// if there is already an animation in progress, don't do anything --
// the new view will pop in on top of the old one during the cross fade,
// and that looks okay.
mFadeStartTime = SystemClock.uptimeMillis();
invalidate();
}
}
}
/**
* Build a {@link Context} cloned into another package name, usually for the
* purposes of reading remote resources.
*/
private Context getRemoteContext(RemoteViews views) {
// Bail if missing package name
final String packageName = views.getPackage();
if (packageName == null) return mContext;
try {
// Return if cloned successfully, otherwise default
return mContext.createPackageContext(packageName, Context.CONTEXT_RESTRICTED);
} catch (NameNotFoundException e) {
Log.e(TAG, "Package name " + packageName + " not found");
return mContext;
}
}
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
if (CROSSFADE) {
int alpha;
int l = child.getLeft();
int t = child.getTop();
if (mFadeStartTime > 0) {
alpha = (int)(((drawingTime-mFadeStartTime)*255)/FADE_DURATION);
if (alpha > 255) {
alpha = 255;
}
Log.d(TAG, "drawChild alpha=" + alpha + " l=" + l + " t=" + t
+ " w=" + child.getWidth());
if (alpha != 255 && mOld != null) {
mOldPaint.setAlpha(255-alpha);
//canvas.drawBitmap(mOld, l, t, mOldPaint);
}
} else {
alpha = 255;
}
int restoreTo = canvas.saveLayerAlpha(l, t, child.getWidth(), child.getHeight(), alpha,
Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
boolean rv = super.drawChild(canvas, child, drawingTime);
canvas.restoreToCount(restoreTo);
if (alpha < 255) {
invalidate();
} else {
mFadeStartTime = -1;
if (mOld != null) {
mOld.recycle();
mOld = null;
}
}
return rv;
} else {
return super.drawChild(canvas, child, drawingTime);
}
}
/**
* Prepare the given view to be shown. This might include adjusting
* {@link FrameLayout.LayoutParams} before inserting.
*/
protected void prepareView(View view) {
// Take requested dimensions from child, but apply default gravity.
FrameLayout.LayoutParams requested = (FrameLayout.LayoutParams)view.getLayoutParams();
if (requested == null) {
requested = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
}
requested.gravity = Gravity.CENTER;
view.setLayoutParams(requested);
}
/**
* Inflate and return the default layout requested by AppWidget provider.
*/
protected View getDefaultView() {
if (LOGD) {
Log.d(TAG, "getDefaultView");
}
View defaultView = null;
Exception exception = null;
try {
if (mInfo != null) {
Context theirContext = mContext.createPackageContext(
mInfo.provider.getPackageName(), Context.CONTEXT_RESTRICTED);
mRemoteContext = theirContext;
LayoutInflater inflater = (LayoutInflater)
theirContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater = inflater.cloneInContext(theirContext);
inflater.setFilter(sInflaterFilter);
defaultView = inflater.inflate(mInfo.initialLayout, this, false);
} else {
Log.w(TAG, "can't inflate defaultView because mInfo is missing");
}
} catch (PackageManager.NameNotFoundException e) {
exception = e;
} catch (RuntimeException e) {
exception = e;
}
if (exception != null) {
Log.w(TAG, "Error inflating AppWidget " + mInfo + ": " + exception.toString());
}
if (defaultView == null) {
if (LOGD) Log.d(TAG, "getDefaultView couldn't find any view, so inflating error");
defaultView = getErrorView();
}
return defaultView;
}
/**
* Inflate and return a view that represents an error state.
*/
protected View getErrorView() {
TextView tv = new TextView(mContext);
tv.setText(com.android.internal.R.string.gadget_host_error_inflating);
// TODO: get this color from somewhere.
tv.setBackgroundColor(Color.argb(127, 0, 0, 0));
return tv;
}
private static class ParcelableSparseArray extends SparseArray<Parcelable> implements Parcelable {
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int flags) {
final int count = size();
dest.writeInt(count);
for (int i = 0; i < count; i++) {
dest.writeInt(keyAt(i));
dest.writeParcelable(valueAt(i), 0);
}
}
public static final Parcelable.Creator<ParcelableSparseArray> CREATOR =
new Parcelable.Creator<ParcelableSparseArray>() {
public ParcelableSparseArray createFromParcel(Parcel source) {
final ParcelableSparseArray array = new ParcelableSparseArray();
final ClassLoader loader = array.getClass().getClassLoader();
final int count = source.readInt();
for (int i = 0; i < count; i++) {
array.put(source.readInt(), source.readParcelable(loader));
}
return array;
}
public ParcelableSparseArray[] newArray(int size) {
return new ParcelableSparseArray[size];
}
};
}
}

View File

@ -0,0 +1,360 @@
/*
* Copyright (C) 2006 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.appwidget;
import android.content.ComponentName;
import android.content.Context;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.widget.RemoteViews;
import com.android.internal.appwidget.IAppWidgetService;
import java.lang.ref.WeakReference;
import java.util.List;
import java.util.WeakHashMap;
/**
* Updates AppWidget state; gets information about installed AppWidget providers and other
* AppWidget related state.
*/
public class AppWidgetManager {
static final String TAG = "AppWidgetManager";
/**
* Send this from your {@link AppWidgetHost} activity when you want to pick an AppWidget to display.
* The AppWidget picker activity will be launched.
* <p>
* You must supply the following extras:
* <table>
* <tr>
* <td>{@link #EXTRA_APPWIDGET_ID}</td>
* <td>A newly allocated appWidgetId, which will be bound to the AppWidget provider
* once the user has selected one.</td>
* </tr>
* </table>
*
* <p>
* The system will respond with an onActivityResult call with the following extras in
* the intent:
* <table>
* <tr>
* <td>{@link #EXTRA_APPWIDGET_ID}</td>
* <td>The appWidgetId that you supplied in the original intent.</td>
* </tr>
* </table>
* <p>
* When you receive the result from the AppWidget pick activity, if the resultCode is
* {@link android.app.Activity#RESULT_OK}, an AppWidget has been selected. You should then
* check the AppWidgetProviderInfo for the returned AppWidget, and if it has one, launch its configuration
* activity. If {@link android.app.Activity#RESULT_CANCELED} is returned, you should delete
* the appWidgetId.
*
* @see #ACTION_APPWIDGET_CONFIGURE
*/
public static final String ACTION_APPWIDGET_PICK = "android.appwidget.action.APPWIDGET_PICK";
/**
* Sent when it is time to configure your AppWidget while it is being added to a host.
* This action is not sent as a broadcast to the AppWidget provider, but as a startActivity
* to the activity specified in the {@link AppWidgetProviderInfo AppWidgetProviderInfo meta-data}.
*
* <p>
* The intent will contain the following extras:
* <table>
* <tr>
* <td>{@link #EXTRA_APPWIDGET_ID}</td>
* <td>The appWidgetId to configure.</td>
* </tr>
* </table>
*
* <p>If you return {@link android.app.Activity#RESULT_OK} using
* {@link android.app.Activity#setResult Activity.setResult()}, the AppWidget will be added,
* and you will receive an {@link #ACTION_APPWIDGET_UPDATE} broadcast for this AppWidget.
* If you return {@link android.app.Activity#RESULT_CANCELED}, the host will cancel the add
* and not display this AppWidget, and you will receive a {@link #ACTION_APPWIDGET_DELETED} broadcast.
*/
public static final String ACTION_APPWIDGET_CONFIGURE = "android.appwidget.action.APPWIDGET_CONFIGURE";
/**
* An intent extra that contains one appWidgetId.
* <p>
* The value will be an int that can be retrieved like this:
* {@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/AppWidgetHostActivity.java getExtra_EXTRA_APPWIDGET_ID}
*/
public static final String EXTRA_APPWIDGET_ID = "appWidgetId";
/**
* An intent extra that contains multiple appWidgetIds.
* <p>
* The value will be an int array that can be retrieved like this:
* {@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/TestAppWidgetProvider.java getExtra_EXTRA_APPWIDGET_IDS}
*/
public static final String EXTRA_APPWIDGET_IDS = "appWidgetIds";
/**
* An intent extra to pass to the AppWidget picker containing a {@link java.util.List} of
* {@link AppWidgetProviderInfo} objects to mix in to the list of AppWidgets that are
* installed. (This is how the launcher shows the search widget).
*/
public static final String EXTRA_CUSTOM_INFO = "customInfo";
/**
* An intent extra to pass to the AppWidget picker containing a {@link java.util.List} of
* {@link android.os.Bundle} objects to mix in to the list of AppWidgets that are
* installed. It will be added to the extras object on the {@link android.content.Intent}
* that is returned from the picker activity.
*
* {@more}
*/
public static final String EXTRA_CUSTOM_EXTRAS = "customExtras";
/**
* A sentiel value that the AppWidget manager will never return as a appWidgetId.
*/
public static final int INVALID_APPWIDGET_ID = 0;
/**
* Sent when it is time to update your AppWidget.
*
* <p>This may be sent in response to a new instance for this AppWidget provider having
* been instantiated, the requested {@link AppWidgetProviderInfo#updatePeriodMillis update interval}
* having lapsed, or the system booting.
*
* <p>
* The intent will contain the following extras:
* <table>
* <tr>
* <td>{@link #EXTRA_APPWIDGET_IDS}</td>
* <td>The appWidgetIds to update. This may be all of the AppWidgets created for this
* provider, or just a subset. The system tries to send updates for as few AppWidget
* instances as possible.</td>
* </tr>
* </table>
*
* @see AppWidgetProvider#onUpdate AppWidgetProvider.onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
*/
public static final String ACTION_APPWIDGET_UPDATE = "android.appwidget.action.APPWIDGET_UPDATE";
/**
* Sent when an instance of an AppWidget is deleted from its host.
*
* @see AppWidgetProvider#onDeleted AppWidgetProvider.onDeleted(Context context, int[] appWidgetIds)
*/
public static final String ACTION_APPWIDGET_DELETED = "android.appwidget.action.APPWIDGET_DELETED";
/**
* Sent when an instance of an AppWidget is removed from the last host.
*
* @see AppWidgetProvider#onEnabled AppWidgetProvider.onEnabled(Context context)
*/
public static final String ACTION_APPWIDGET_DISABLED = "android.appwidget.action.APPWIDGET_DISABLED";
/**
* Sent when an instance of an AppWidget is added to a host for the first time.
* This broadcast is sent at boot time if there is a AppWidgetHost installed with
* an instance for this provider.
*
* @see AppWidgetProvider#onEnabled AppWidgetProvider.onEnabled(Context context)
*/
public static final String ACTION_APPWIDGET_ENABLED = "android.appwidget.action.APPWIDGET_ENABLED";
/**
* Field for the manifest meta-data tag.
*
* @see AppWidgetProviderInfo
*/
public static final String META_DATA_APPWIDGET_PROVIDER = "android.appwidget.provider";
/**
* Field for the manifest meta-data tag used to indicate any previous name for the
* app widget receiver.
*
* @see AppWidgetProviderInfo
*
* @hide Pending API approval
*/
public static final String META_DATA_APPWIDGET_OLD_NAME = "android.appwidget.oldName";
static WeakHashMap<Context, WeakReference<AppWidgetManager>> sManagerCache = new WeakHashMap();
static IAppWidgetService sService;
Context mContext;
private DisplayMetrics mDisplayMetrics;
/**
* Get the AppWidgetManager instance to use for the supplied {@link android.content.Context
* Context} object.
*/
public static AppWidgetManager getInstance(Context context) {
synchronized (sManagerCache) {
if (sService == null) {
IBinder b = ServiceManager.getService(Context.APPWIDGET_SERVICE);
sService = IAppWidgetService.Stub.asInterface(b);
}
WeakReference<AppWidgetManager> ref = sManagerCache.get(context);
AppWidgetManager result = null;
if (ref != null) {
result = ref.get();
}
if (result == null) {
result = new AppWidgetManager(context);
sManagerCache.put(context, new WeakReference(result));
}
return result;
}
}
private AppWidgetManager(Context context) {
mContext = context;
mDisplayMetrics = context.getResources().getDisplayMetrics();
}
/**
* Set the RemoteViews to use for the specified appWidgetIds.
*
* <p>
* It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
* and outside of the handler.
* This method will only work when called from the uid that owns the AppWidget provider.
*
* @param appWidgetIds The AppWidget instances for which to set the RemoteViews.
* @param views The RemoteViews object to show.
*/
public void updateAppWidget(int[] appWidgetIds, RemoteViews views) {
try {
sService.updateAppWidgetIds(appWidgetIds, views);
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
}
}
/**
* Set the RemoteViews to use for the specified appWidgetId.
*
* <p>
* It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
* and outside of the handler.
* This method will only work when called from the uid that owns the AppWidget provider.
*
* @param appWidgetId The AppWidget instance for which to set the RemoteViews.
* @param views The RemoteViews object to show.
*/
public void updateAppWidget(int appWidgetId, RemoteViews views) {
updateAppWidget(new int[] { appWidgetId }, views);
}
/**
* Set the RemoteViews to use for all AppWidget instances for the supplied AppWidget provider.
*
* <p>
* It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
* and outside of the handler.
* This method will only work when called from the uid that owns the AppWidget provider.
*
* @param provider The {@link ComponentName} for the {@link
* android.content.BroadcastReceiver BroadcastReceiver} provider
* for your AppWidget.
* @param views The RemoteViews object to show.
*/
public void updateAppWidget(ComponentName provider, RemoteViews views) {
try {
sService.updateAppWidgetProvider(provider, views);
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
}
}
/**
* Return a list of the AppWidget providers that are currently installed.
*/
public List<AppWidgetProviderInfo> getInstalledProviders() {
try {
return sService.getInstalledProviders();
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
}
}
/**
* Get the available info about the AppWidget.
*
* @return A appWidgetId. If the appWidgetId has not been bound to a provider yet, or
* you don't have access to that appWidgetId, null is returned.
*/
public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
try {
AppWidgetProviderInfo info = sService.getAppWidgetInfo(appWidgetId);
if (info != null) {
// Converting complex to dp.
info.minWidth =
TypedValue.complexToDimensionPixelSize(info.minWidth, mDisplayMetrics);
info.minHeight =
TypedValue.complexToDimensionPixelSize(info.minHeight, mDisplayMetrics);
}
return info;
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
}
}
/**
* Set the component for a given appWidgetId.
*
* <p class="note">You need the APPWIDGET_LIST permission. This method is to be used by the
* AppWidget picker.
*
* @param appWidgetId The AppWidget instance for which to set the RemoteViews.
* @param provider The {@link android.content.BroadcastReceiver} that will be the AppWidget
* provider for this AppWidget.
*/
public void bindAppWidgetId(int appWidgetId, ComponentName provider) {
try {
sService.bindAppWidgetId(appWidgetId, provider);
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
}
}
/**
* Get the list of appWidgetIds that have been bound to the given AppWidget
* provider.
*
* @param provider The {@link android.content.BroadcastReceiver} that is the
* AppWidget provider to find appWidgetIds for.
*/
public int[] getAppWidgetIds(ComponentName provider) {
try {
return sService.getAppWidgetIds(provider);
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
}
}
}

View File

@ -0,0 +1,150 @@
/*
* Copyright (C) 2006 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.appwidget;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
/**
* A convenience class to aid in implementing an AppWidget provider.
* Everything you can do with AppWidgetProvider, you can do with a regular {@link BroadcastReceiver}.
* AppWidgetProvider merely parses the relevant fields out of the Intent that is received in
* {@link #onReceive(Context,Intent) onReceive(Context,Intent)}, and calls hook methods
* with the received extras.
*
* <p>Extend this class and override one or more of the {@link #onUpdate}, {@link #onDeleted},
* {@link #onEnabled} or {@link #onDisabled} methods to implement your own AppWidget functionality.
* </p>
* <p>For an example of how to write a AppWidget provider, see the
* <a href="{@docRoot}guide/topics/appwidgets/index.html#Providers">AppWidgets</a> documentation.</p>
*/
public class AppWidgetProvider extends BroadcastReceiver {
/**
* Constructor to initialize AppWidgetProvider.
*/
public AppWidgetProvider() {
}
/**
* Implements {@link BroadcastReceiver#onReceive} to dispatch calls to the various
* other methods on AppWidgetProvider.
*
* @param context The Context in which the receiver is running.
* @param intent The Intent being received.
*/
// BEGIN_INCLUDE(onReceive)
public void onReceive(Context context, Intent intent) {
// Protect against rogue update broadcasts (not really a security issue,
// just filter bad broacasts out so subclasses are less likely to crash).
String action = intent.getAction();
if (AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
Bundle extras = intent.getExtras();
if (extras != null) {
int[] appWidgetIds = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS);
if (appWidgetIds != null && appWidgetIds.length > 0) {
this.onUpdate(context, AppWidgetManager.getInstance(context), appWidgetIds);
}
}
}
else if (AppWidgetManager.ACTION_APPWIDGET_DELETED.equals(action)) {
Bundle extras = intent.getExtras();
if (extras != null && extras.containsKey(AppWidgetManager.EXTRA_APPWIDGET_ID)) {
final int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID);
this.onDeleted(context, new int[] { appWidgetId });
}
}
else if (AppWidgetManager.ACTION_APPWIDGET_ENABLED.equals(action)) {
this.onEnabled(context);
}
else if (AppWidgetManager.ACTION_APPWIDGET_DISABLED.equals(action)) {
this.onDisabled(context);
}
}
// END_INCLUDE(onReceive)
/**
* Called in response to the {@link AppWidgetManager#ACTION_APPWIDGET_UPDATE} broadcast when
* this AppWidget provider is being asked to provide {@link android.widget.RemoteViews RemoteViews}
* for a set of AppWidgets. Override this method to implement your own AppWidget functionality.
*
* {@more}
*
* @param context The {@link android.content.Context Context} in which this receiver is
* running.
* @param appWidgetManager A {@link AppWidgetManager} object you can call {@link
* AppWidgetManager#updateAppWidget} on.
* @param appWidgetIds The appWidgetIds for which an update is needed. Note that this
* may be all of the AppWidget instances for this provider, or just
* a subset of them.
*
* @see AppWidgetManager#ACTION_APPWIDGET_UPDATE
*/
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
}
/**
* Called in response to the {@link AppWidgetManager#ACTION_APPWIDGET_DELETED} broadcast when
* one or more AppWidget instances have been deleted. Override this method to implement
* your own AppWidget functionality.
*
* {@more}
*
* @param context The {@link android.content.Context Context} in which this receiver is
* running.
* @param appWidgetIds The appWidgetIds that have been deleted from their host.
*
* @see AppWidgetManager#ACTION_APPWIDGET_DELETED
*/
public void onDeleted(Context context, int[] appWidgetIds) {
}
/**
* Called in response to the {@link AppWidgetManager#ACTION_APPWIDGET_ENABLED} broadcast when
* the a AppWidget for this provider is instantiated. Override this method to implement your
* own AppWidget functionality.
*
* {@more}
* When the last AppWidget for this provider is deleted,
* {@link AppWidgetManager#ACTION_APPWIDGET_DISABLED} is sent by the AppWidget manager, and
* {@link #onDisabled} is called. If after that, an AppWidget for this provider is created
* again, onEnabled() will be called again.
*
* @param context The {@link android.content.Context Context} in which this receiver is
* running.
*
* @see AppWidgetManager#ACTION_APPWIDGET_ENABLED
*/
public void onEnabled(Context context) {
}
/**
* Called in response to the {@link AppWidgetManager#ACTION_APPWIDGET_DISABLED} broadcast, which
* is sent when the last AppWidget instance for this provider is deleted. Override this method
* to implement your own AppWidget functionality.
*
* {@more}
*
* @param context The {@link android.content.Context Context} in which this receiver is
* running.
*
* @see AppWidgetManager#ACTION_APPWIDGET_DISABLED
*/
public void onDisabled(Context context) {
}
}

View File

@ -0,0 +1,19 @@
/*
* 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.appwidget;
parcelable AppWidgetProviderInfo;

View File

@ -0,0 +1,183 @@
/*
* Copyright (C) 2006 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.appwidget;
import android.os.Parcel;
import android.os.Parcelable;
import android.content.ComponentName;
/**
* Describes the meta data for an installed AppWidget provider. The fields in this class
* correspond to the fields in the <code>&lt;appwidget-provider&gt;</code> xml tag.
*/
public class AppWidgetProviderInfo implements Parcelable {
/**
* Identity of this AppWidget component. This component should be a {@link
* android.content.BroadcastReceiver}, and it will be sent the AppWidget intents
* {@link android.appwidget as described in the AppWidget package documentation}.
*
* <p>This field corresponds to the <code>android:name</code> attribute in
* the <code>&lt;receiver&gt;</code> element in the AndroidManifest.xml file.
*/
public ComponentName provider;
/**
* Minimum width of the AppWidget, in dp.
*
* <p>This field corresponds to the <code>android:minWidth</code> attribute in
* the AppWidget meta-data file.
*/
public int minWidth;
/**
* Minimum height of the AppWidget, in dp.
*
* <p>This field corresponds to the <code>android:minHeight</code> attribute in
* the AppWidget meta-data file.
*/
public int minHeight;
/**
* How often, in milliseconds, that this AppWidget wants to be updated.
* The AppWidget manager may place a limit on how often a AppWidget is updated.
*
* <p>This field corresponds to the <code>android:updatePeriodMillis</code> attribute in
* the AppWidget meta-data file.
*
* <p class="note"><b>Note:</b> Updates requested with <code>updatePeriodMillis</code>
* will not be delivered more than once every 30 minutes.</p>
*/
public int updatePeriodMillis;
/**
* The resource id of the initial layout for this AppWidget. This should be
* displayed until the RemoteViews for the AppWidget is available.
*
* <p>This field corresponds to the <code>android:initialLayout</code> attribute in
* the AppWidget meta-data file.
*/
public int initialLayout;
/**
* The activity to launch that will configure the AppWidget.
*
* <p>This class name of field corresponds to the <code>android:configure</code> attribute in
* the AppWidget meta-data file. The package name always corresponds to the package containing
* the AppWidget provider.
*/
public ComponentName configure;
/**
* The label to display to the user in the AppWidget picker. If not supplied in the
* xml, the application label will be used.
*
* <p>This field corresponds to the <code>android:label</code> attribute in
* the <code>&lt;receiver&gt;</code> element in the AndroidManifest.xml file.
*/
public String label;
/**
* The icon to display for this AppWidget in the AppWidget picker. If not supplied in the
* xml, the application icon will be used.
*
* <p>This field corresponds to the <code>android:icon</code> attribute in
* the <code>&lt;receiver&gt;</code> element in the AndroidManifest.xml file.
*/
public int icon;
/**
* The previous name, if any, of the app widget receiver. If not supplied, it will be
* ignored.
*
* <p>This field corresponds to the <code>&lt;meta-data /&gt;</code> with the name
* <code>android.appwidget.oldName</code>.
*
* @hide Pending API approval
*/
public String oldName;
public AppWidgetProviderInfo() {
}
/**
* Unflatten the AppWidgetProviderInfo from a parcel.
*/
public AppWidgetProviderInfo(Parcel in) {
if (0 != in.readInt()) {
this.provider = new ComponentName(in);
}
this.minWidth = in.readInt();
this.minHeight = in.readInt();
this.updatePeriodMillis = in.readInt();
this.initialLayout = in.readInt();
if (0 != in.readInt()) {
this.configure = new ComponentName(in);
}
this.label = in.readString();
this.icon = in.readInt();
}
public void writeToParcel(android.os.Parcel out, int flags) {
if (this.provider != null) {
out.writeInt(1);
this.provider.writeToParcel(out, flags);
} else {
out.writeInt(0);
}
out.writeInt(this.minWidth);
out.writeInt(this.minHeight);
out.writeInt(this.updatePeriodMillis);
out.writeInt(this.initialLayout);
if (this.configure != null) {
out.writeInt(1);
this.configure.writeToParcel(out, flags);
} else {
out.writeInt(0);
}
out.writeString(this.label);
out.writeInt(this.icon);
}
public int describeContents() {
return 0;
}
/**
* Parcelable.Creator that instantiates AppWidgetProviderInfo objects
*/
public static final Parcelable.Creator<AppWidgetProviderInfo> CREATOR
= new Parcelable.Creator<AppWidgetProviderInfo>()
{
public AppWidgetProviderInfo createFromParcel(Parcel parcel)
{
return new AppWidgetProviderInfo(parcel);
}
public AppWidgetProviderInfo[] newArray(int size)
{
return new AppWidgetProviderInfo[size];
}
};
public String toString() {
return "AppWidgetProviderInfo(provider=" + this.provider + ")";
}
}

View File

@ -0,0 +1,32 @@
<body>
<p>Android allows applications to publish views to be embedded in other applications. These
views are called widgets, and are published by "AppWidget providers." The component that can
contain widgets is called a "AppWidget host."
</p>
<p>For more information, see the
<a href="{@docRoot}guide/topics/appwidgets/index.html">AppWidgets</a>
documentation in the Dev Guide.</p>
{@more}
<h2><a name="providers"></a>AppWidget Providers</h2>
<p>Any application can publish widgets. All an application needs to do to publish a widget is
to have a {@link android.content.BroadcastReceiver} that receives the {@link
android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE AppWidgetManager.ACTION_APPWIDGET_UPDATE} intent,
and provide some meta-data about the widget. Android provides the
{@link android.appwidget.AppWidgetProvider} class, which extends BroadcastReceiver, as a convenience
class to aid in handling the broadcasts.
<h2>AppWidget Hosts</h3>
<p>Widget hosts are the containers in which widgets can be placed. Most of the look and feel
details are left up to the widget hosts. For example, the home screen has one way of viewing
widgets, but the lock screen could also contain widgets, and it would have a different way of
adding, removing and otherwise managing widgets.</p>
<p>For more information on implementing your own widget host, see the
{@link android.appwidget.AppWidgetHost AppWidgetHost} class.</p>
</body>