19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Projectpackage android.appwidget; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 195d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohenimport android.content.ComponentName; 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 215d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohenimport android.content.pm.ApplicationInfo; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.PackageManager; 23b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkeyimport android.content.pm.PackageManager.NameNotFoundException; 245d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohenimport android.content.res.Resources; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Bitmap; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Canvas; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Color; 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Paint; 294c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohenimport android.graphics.Rect; 305d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohenimport android.os.Build; 31e8724c82ab1479f13c85a2c6219841e1fd95f2d2Adam Cohenimport android.os.Bundle; 3209ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guyimport android.os.Parcel; 333030193dc179b3010f2dd3bffe9c1dec54da38fcGilles Debunneimport android.os.Parcelable; 343030193dc179b3010f2dd3bffe9c1dec54da38fcGilles Debunneimport android.os.SystemClock; 35b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkeyimport android.util.AttributeSet; 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log; 3709ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guyimport android.util.SparseArray; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.Gravity; 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.LayoutInflater; 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View; 411affb937641fd42c3b94f0c2427b1b68336a572fGuang Zhuimport android.view.accessibility.AccessibilityNodeInfo; 42499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport android.widget.Adapter; 43499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport android.widget.AdapterView; 44499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport android.widget.BaseAdapter; 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.widget.FrameLayout; 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.widget.RemoteViews; 472148d43eb23c702e834c93ae427f822f32d280a2Adam Cohenimport android.widget.RemoteViewsAdapter.RemoteAdapterConnectionCallback; 484c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohenimport android.widget.TextView; 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 51c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * Provides the glue to show AppWidget views. This class offers automatic animation 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * between updates, and will try recycling old views for each incoming 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link RemoteViews}. 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 55c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Projectpublic class AppWidgetHostView extends FrameLayout { 56c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project static final String TAG = "AppWidgetHostView"; 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final boolean LOGD = false; 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final boolean CROSSFADE = false; 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final int VIEW_MODE_NOINIT = 0; 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final int VIEW_MODE_CONTENT = 1; 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final int VIEW_MODE_ERROR = 2; 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final int VIEW_MODE_DEFAULT = 3; 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final int FADE_DURATION = 1000; 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 67c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project // When we're inflating the initialLayout for a AppWidget, we only allow 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // views that are allowed in RemoteViews. 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final LayoutInflater.Filter sInflaterFilter = new LayoutInflater.Filter() { 70e6ac8b9aade9443ab8456c8f7a47cdfba3b70266Gilles Debunne public boolean onLoadClass(Class clazz) { 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return clazz.isAnnotationPresent(RemoteViews.RemoteView.class); 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Context mContext; 76b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey Context mRemoteContext; 77b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey 78c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project int mAppWidgetId; 79c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project AppWidgetProviderInfo mInfo; 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View mView; 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int mViewMode = VIEW_MODE_NOINIT; 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int mLayoutId = -1; 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long mFadeStartTime = -1; 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Bitmap mOld; 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Paint mOldPaint = new Paint(); 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Create a host view. Uses default fade animations. 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 90c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project public AppWidgetHostView(Context context) { 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this(context, android.R.anim.fade_in, android.R.anim.fade_out); 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Create a host view. Uses specified animations when pushing 96c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * {@link #updateAppWidget(RemoteViews)}. 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param animationIn Resource ID of in animation to use 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param animationOut Resource ID of out animation to use 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 101a54755962ca7725d1e2b6cacbbaece6f1cbf5af4Romain Guy @SuppressWarnings({"UnusedDeclaration"}) 102c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project public AppWidgetHostView(Context context, int animationIn, int animationOut) { 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(context); 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext = context; 105d110889cbca4d40f8cdeddfe6eb2f498f470ae4bAdam Cohen 106d110889cbca4d40f8cdeddfe6eb2f498f470ae4bAdam Cohen // We want to segregate the view ids within AppWidgets to prevent 107d110889cbca4d40f8cdeddfe6eb2f498f470ae4bAdam Cohen // problems when those ids collide with view ids in the AppWidgetHost. 108d110889cbca4d40f8cdeddfe6eb2f498f470ae4bAdam Cohen setIsRootNamespace(true); 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 110d110889cbca4d40f8cdeddfe6eb2f498f470ae4bAdam Cohen 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1124c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohen * Set the AppWidget that will be displayed by this view. This method also adds default padding 1134c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohen * to widgets, as described in {@link #getDefaultPaddingForWidget(Context, ComponentName, Rect)} 1144c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohen * and can be overridden in order to add custom padding. 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 116c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project public void setAppWidget(int appWidgetId, AppWidgetProviderInfo info) { 117c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project mAppWidgetId = appWidgetId; 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInfo = info; 1195d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohen 1205d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohen // Sometimes the AppWidgetManager returns a null AppWidgetProviderInfo object for 1215d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohen // a widget, eg. for some widgets in safe mode. 1225d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohen if (info != null) { 1235d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohen // We add padding to the AppWidgetHostView if necessary 1244c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohen Rect padding = getDefaultPaddingForWidget(mContext, info.provider, null); 1255d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohen setPadding(padding.left, padding.top, padding.right, padding.bottom); 1265d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohen } 1275d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohen } 1285d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohen 1295d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohen /** 1305d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohen * As of ICE_CREAM_SANDWICH we are automatically adding padding to widgets targeting 1315d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohen * ICE_CREAM_SANDWICH and higher. The new widget design guidelines strongly recommend 1325d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohen * that widget developers do not add extra padding to their widgets. This will help 1335d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohen * achieve consistency among widgets. 1344c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohen * 1354c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohen * Note: this method is only needed by developers of AppWidgetHosts. The method is provided in 1364c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohen * order for the AppWidgetHost to account for the automatic padding when computing the number 1374c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohen * of cells to allocate to a particular widget. 1384c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohen * 1394c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohen * @param context the current context 1404c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohen * @param component the component name of the widget 1414c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohen * @param padding Rect in which to place the output, if null, a new Rect will be allocated and 1424c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohen * returned 1434c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohen * @return default padding for this widget 1445d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohen */ 1454c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohen public static Rect getDefaultPaddingForWidget(Context context, ComponentName component, 1464c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohen Rect padding) { 1474c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohen PackageManager packageManager = context.getPackageManager(); 1485d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohen ApplicationInfo appInfo; 1495d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohen 1504c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohen if (padding == null) { 1514c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohen padding = new Rect(0, 0, 0, 0); 1524c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohen } else { 1534c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohen padding.set(0, 0, 0, 0); 1544c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohen } 1554c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohen 1565d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohen try { 1575d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohen appInfo = packageManager.getApplicationInfo(component.getPackageName(), 0); 1584c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohen } catch (NameNotFoundException e) { 1595d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohen // if we can't find the package, return 0 padding 1604c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohen return padding; 1615d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohen } 1625d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohen 1635d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohen if (appInfo.targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 1644c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohen Resources r = context.getResources(); 1654c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohen padding.left = r.getDimensionPixelSize(com.android.internal. 1665d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohen R.dimen.default_app_widget_padding_left); 1674c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohen padding.right = r.getDimensionPixelSize(com.android.internal. 1685d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohen R.dimen.default_app_widget_padding_right); 1694c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohen padding.top = r.getDimensionPixelSize(com.android.internal. 1705d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohen R.dimen.default_app_widget_padding_top); 1714c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohen padding.bottom = r.getDimensionPixelSize(com.android.internal. 1725d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohen R.dimen.default_app_widget_padding_bottom); 1735d5f3405204ecb5045edc756fde71c97d10bcda4Adam Cohen } 1744c96a59b4354c4a593a07a3273c186b51597bcc1Adam Cohen return padding; 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 176c27bb559805ae5cd06f7ecf575959c60c51a22aaJoe Onorato 177c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project public int getAppWidgetId() { 178c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project return mAppWidgetId; 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 181c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project public AppWidgetProviderInfo getAppWidgetInfo() { 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mInfo; 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18509ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy @Override 18609ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { 18709ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy final ParcelableSparseArray jail = new ParcelableSparseArray(); 18809ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy super.dispatchSaveInstanceState(jail); 18909ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy container.put(generateId(), jail); 19009ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy } 19109ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy 19209ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy private int generateId() { 19309ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy final int id = getId(); 19409ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy return id == View.NO_ID ? mAppWidgetId : id; 19509ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy } 19609ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy 19709ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy @Override 19809ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { 199ae8dd29c035fffa6e302bd485d0552f97db39127Romain Guy final Parcelable parcelable = container.get(generateId()); 200ae8dd29c035fffa6e302bd485d0552f97db39127Romain Guy 201ae8dd29c035fffa6e302bd485d0552f97db39127Romain Guy ParcelableSparseArray jail = null; 202ae8dd29c035fffa6e302bd485d0552f97db39127Romain Guy if (parcelable != null && parcelable instanceof ParcelableSparseArray) { 203ae8dd29c035fffa6e302bd485d0552f97db39127Romain Guy jail = (ParcelableSparseArray) parcelable; 204ae8dd29c035fffa6e302bd485d0552f97db39127Romain Guy } 205ae8dd29c035fffa6e302bd485d0552f97db39127Romain Guy 206a8a720d8cd208d7d265de28ab69f7e68eb10140aRomain Guy if (jail == null) jail = new ParcelableSparseArray(); 207ae8dd29c035fffa6e302bd485d0552f97db39127Romain Guy 20809ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy super.dispatchRestoreInstanceState(jail); 20909ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy } 21009ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy 211e8724c82ab1479f13c85a2c6219841e1fd95f2d2Adam Cohen /** 21288f041ed312299f1d2746e570b989c336bfd97c8Adam Cohen * Provide guidance about the size of this widget to the AppWidgetManager. The widths and 21388f041ed312299f1d2746e570b989c336bfd97c8Adam Cohen * heights should correspond to the full area the AppWidgetHostView is given. Padding added by 21488f041ed312299f1d2746e570b989c336bfd97c8Adam Cohen * the framework will be accounted for automatically. This information gets embedded into the 21588f041ed312299f1d2746e570b989c336bfd97c8Adam Cohen * AppWidget options and causes a callback to the AppWidgetProvider. 216d2097ebacf3a3658624cad10669a4d98e8d7d846Adam Cohen * @see AppWidgetProvider#onAppWidgetOptionsChanged(Context, AppWidgetManager, int, Bundle) 217c88d11f9493e65d318dcd3b094ef446e1905ebfdAdam Cohen * 218d2097ebacf3a3658624cad10669a4d98e8d7d846Adam Cohen * @param options The bundle of options, in addition to the size information, 219c88d11f9493e65d318dcd3b094ef446e1905ebfdAdam Cohen * can be null. 220c88d11f9493e65d318dcd3b094ef446e1905ebfdAdam Cohen * @param minWidth The minimum width that the widget will be displayed at. 221c88d11f9493e65d318dcd3b094ef446e1905ebfdAdam Cohen * @param minHeight The maximum height that the widget will be displayed at. 222d2097ebacf3a3658624cad10669a4d98e8d7d846Adam Cohen * @param maxWidth The maximum width that the widget will be displayed at. 223d2097ebacf3a3658624cad10669a4d98e8d7d846Adam Cohen * @param maxHeight The maximum height that the widget will be displayed at. 224e8724c82ab1479f13c85a2c6219841e1fd95f2d2Adam Cohen * 225e8724c82ab1479f13c85a2c6219841e1fd95f2d2Adam Cohen */ 226d2097ebacf3a3658624cad10669a4d98e8d7d846Adam Cohen public void updateAppWidgetSize(Bundle options, int minWidth, int minHeight, int maxWidth, 227c88d11f9493e65d318dcd3b094ef446e1905ebfdAdam Cohen int maxHeight) { 228d2097ebacf3a3658624cad10669a4d98e8d7d846Adam Cohen if (options == null) { 229d2097ebacf3a3658624cad10669a4d98e8d7d846Adam Cohen options = new Bundle(); 230e8724c82ab1479f13c85a2c6219841e1fd95f2d2Adam Cohen } 23188f041ed312299f1d2746e570b989c336bfd97c8Adam Cohen 23288f041ed312299f1d2746e570b989c336bfd97c8Adam Cohen Rect padding = new Rect(); 23388f041ed312299f1d2746e570b989c336bfd97c8Adam Cohen if (mInfo != null) { 23488f041ed312299f1d2746e570b989c336bfd97c8Adam Cohen padding = getDefaultPaddingForWidget(mContext, mInfo.provider, padding); 23588f041ed312299f1d2746e570b989c336bfd97c8Adam Cohen } 236f065c9663172094d2d79eb5f77c59d89e812437aAdam Cohen float density = getResources().getDisplayMetrics().density; 23788f041ed312299f1d2746e570b989c336bfd97c8Adam Cohen 238f065c9663172094d2d79eb5f77c59d89e812437aAdam Cohen int xPaddingDips = (int) ((padding.left + padding.right) / density); 239f065c9663172094d2d79eb5f77c59d89e812437aAdam Cohen int yPaddingDips = (int) ((padding.top + padding.bottom) / density); 24088f041ed312299f1d2746e570b989c336bfd97c8Adam Cohen 241f065c9663172094d2d79eb5f77c59d89e812437aAdam Cohen options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, minWidth - xPaddingDips); 242f065c9663172094d2d79eb5f77c59d89e812437aAdam Cohen options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, minHeight - yPaddingDips); 243f065c9663172094d2d79eb5f77c59d89e812437aAdam Cohen options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, maxWidth - xPaddingDips); 244f065c9663172094d2d79eb5f77c59d89e812437aAdam Cohen options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, maxHeight - yPaddingDips); 245d2097ebacf3a3658624cad10669a4d98e8d7d846Adam Cohen updateAppWidgetOptions(options); 246e8724c82ab1479f13c85a2c6219841e1fd95f2d2Adam Cohen } 247e8724c82ab1479f13c85a2c6219841e1fd95f2d2Adam Cohen 248c88d11f9493e65d318dcd3b094ef446e1905ebfdAdam Cohen /** 249c88d11f9493e65d318dcd3b094ef446e1905ebfdAdam Cohen * Specify some extra information for the widget provider. Causes a callback to the 250c88d11f9493e65d318dcd3b094ef446e1905ebfdAdam Cohen * AppWidgetProvider. 251d2097ebacf3a3658624cad10669a4d98e8d7d846Adam Cohen * @see AppWidgetProvider#onAppWidgetOptionsChanged(Context, AppWidgetManager, int, Bundle) 252c88d11f9493e65d318dcd3b094ef446e1905ebfdAdam Cohen * 253d2097ebacf3a3658624cad10669a4d98e8d7d846Adam Cohen * @param options The bundle of options information. 254c88d11f9493e65d318dcd3b094ef446e1905ebfdAdam Cohen */ 255d2097ebacf3a3658624cad10669a4d98e8d7d846Adam Cohen public void updateAppWidgetOptions(Bundle options) { 256d2097ebacf3a3658624cad10669a4d98e8d7d846Adam Cohen AppWidgetManager.getInstance(mContext).updateAppWidgetOptions(mAppWidgetId, options); 257e8724c82ab1479f13c85a2c6219841e1fd95f2d2Adam Cohen } 258e8724c82ab1479f13c85a2c6219841e1fd95f2d2Adam Cohen 259b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey /** {@inheritDoc} */ 260b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey @Override 261b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey public LayoutParams generateLayoutParams(AttributeSet attrs) { 262b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey // We're being asked to inflate parameters, probably by a LayoutInflater 263b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey // in a remote Context. To help resolve any remote references, we 264b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey // inflate through our last mRemoteContext when it exists. 265b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey final Context context = mRemoteContext != null ? mRemoteContext : mContext; 266b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey return new FrameLayout.LayoutParams(context, attrs); 267b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey } 268b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 270c27bb559805ae5cd06f7ecf575959c60c51a22aaJoe Onorato * Update the AppWidgetProviderInfo for this view, and reset it to the 271c27bb559805ae5cd06f7ecf575959c60c51a22aaJoe Onorato * initial layout. 272c27bb559805ae5cd06f7ecf575959c60c51a22aaJoe Onorato */ 273c27bb559805ae5cd06f7ecf575959c60c51a22aaJoe Onorato void resetAppWidget(AppWidgetProviderInfo info) { 274c27bb559805ae5cd06f7ecf575959c60c51a22aaJoe Onorato mInfo = info; 275c27bb559805ae5cd06f7ecf575959c60c51a22aaJoe Onorato mViewMode = VIEW_MODE_NOINIT; 276c27bb559805ae5cd06f7ecf575959c60c51a22aaJoe Onorato updateAppWidget(null); 277c27bb559805ae5cd06f7ecf575959c60c51a22aaJoe Onorato } 278c27bb559805ae5cd06f7ecf575959c60c51a22aaJoe Onorato 279c27bb559805ae5cd06f7ecf575959c60c51a22aaJoe Onorato /** 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Process a set of {@link RemoteViews} coming in as an update from the 281ae8dd29c035fffa6e302bd485d0552f97db39127Romain Guy * AppWidget provider. Will animate into these new views as needed 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 283c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project public void updateAppWidget(RemoteViews remoteViews) { 284c27bb559805ae5cd06f7ecf575959c60c51a22aaJoe Onorato if (LOGD) Log.d(TAG, "updateAppWidget called mOld=" + mOld); 285f140be6c3c21dd0f6d2214929e89d60de31d2c04Joe Onorato 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean recycled = false; 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View content = null; 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Exception exception = null; 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Capture the old view into a bitmap so we can do the crossfade. 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (CROSSFADE) { 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mFadeStartTime < 0) { 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mView != null) { 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int width = mView.getWidth(); 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int height = mView.getHeight(); 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOld = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (OutOfMemoryError e) { 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // we just won't do the fade 3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOld = null; 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mOld != null) { 3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //mView.drawIntoBitmap(mOld); 3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (remoteViews == null) { 3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mViewMode == VIEW_MODE_DEFAULT) { 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // We've already done this -- nothing to do. 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project content = getDefaultView(); 3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLayoutId = -1; 3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mViewMode = VIEW_MODE_DEFAULT; 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 318b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey // Prepare a local reference to the remote Context so we're ready to 319b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey // inflate any requested LayoutParams. 320b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey mRemoteContext = getRemoteContext(remoteViews); 3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int layoutId = remoteViews.getLayoutId(); 3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If our stale view has been prepared to match active, and the new 3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // layout matches, try recycling it 3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (content == null && layoutId == mLayoutId) { 3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project remoteViews.reapply(mContext, mView); 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project content = mView; 3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project recycled = true; 3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (LOGD) Log.d(TAG, "was able to recycled existing layout"); 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (RuntimeException e) { 3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project exception = e; 3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Try normal RemoteView inflation 3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (content == null) { 3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project content = remoteViews.apply(mContext, this); 3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (LOGD) Log.d(TAG, "had to inflate new layout"); 3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (RuntimeException e) { 3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project exception = e; 3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLayoutId = layoutId; 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mViewMode = VIEW_MODE_CONTENT; 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (content == null) { 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mViewMode == VIEW_MODE_ERROR) { 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // We've already done this -- nothing to do. 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ; 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 355c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project Log.w(TAG, "updateAppWidget couldn't find any view, using error view", exception); 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project content = getErrorView(); 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mViewMode = VIEW_MODE_ERROR; 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!recycled) { 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project prepareView(content); 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project addView(content); 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mView != content) { 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project removeView(mView); 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mView = content; 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (CROSSFADE) { 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mFadeStartTime < 0) { 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // if there is already an animation in progress, don't do anything -- 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the new view will pop in on top of the old one during the cross fade, 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // and that looks okay. 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFadeStartTime = SystemClock.uptimeMillis(); 3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invalidate(); 3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 381b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey /** 382499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * Process data-changed notifications for the specified view in the specified 383499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * set of {@link RemoteViews} views. 384499cb9f516062b654952d282f211bee44c31a3c2Winson Chung */ 3856394c0e52cf641d93f678fd052499aa952e3595dWinson Chung void viewDataChanged(int viewId) { 386499cb9f516062b654952d282f211bee44c31a3c2Winson Chung View v = findViewById(viewId); 387499cb9f516062b654952d282f211bee44c31a3c2Winson Chung if ((v != null) && (v instanceof AdapterView<?>)) { 388499cb9f516062b654952d282f211bee44c31a3c2Winson Chung AdapterView<?> adapterView = (AdapterView<?>) v; 389499cb9f516062b654952d282f211bee44c31a3c2Winson Chung Adapter adapter = adapterView.getAdapter(); 390499cb9f516062b654952d282f211bee44c31a3c2Winson Chung if (adapter instanceof BaseAdapter) { 391499cb9f516062b654952d282f211bee44c31a3c2Winson Chung BaseAdapter baseAdapter = (BaseAdapter) adapter; 392499cb9f516062b654952d282f211bee44c31a3c2Winson Chung baseAdapter.notifyDataSetChanged(); 3932148d43eb23c702e834c93ae427f822f32d280a2Adam Cohen } else if (adapter == null && adapterView instanceof RemoteAdapterConnectionCallback) { 3942148d43eb23c702e834c93ae427f822f32d280a2Adam Cohen // If the adapter is null, it may mean that the RemoteViewsAapter has not yet 3952148d43eb23c702e834c93ae427f822f32d280a2Adam Cohen // connected to its associated service, and hence the adapter hasn't been set. 3962148d43eb23c702e834c93ae427f822f32d280a2Adam Cohen // In this case, we need to defer the notify call until it has been set. 3972148d43eb23c702e834c93ae427f822f32d280a2Adam Cohen ((RemoteAdapterConnectionCallback) adapterView).deferNotifyDataSetChanged(); 398499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 399499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 400499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 401499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 402499cb9f516062b654952d282f211bee44c31a3c2Winson Chung /** 403b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey * Build a {@link Context} cloned into another package name, usually for the 404b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey * purposes of reading remote resources. 405b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey */ 406b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey private Context getRemoteContext(RemoteViews views) { 407b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey // Bail if missing package name 408b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey final String packageName = views.getPackage(); 409b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey if (packageName == null) return mContext; 410b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey 411b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey try { 412b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey // Return if cloned successfully, otherwise default 413b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey return mContext.createPackageContext(packageName, Context.CONTEXT_RESTRICTED); 414b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey } catch (NameNotFoundException e) { 415b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey Log.e(TAG, "Package name " + packageName + " not found"); 416b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey return mContext; 417b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey } 418b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey } 419b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey 4203030193dc179b3010f2dd3bffe9c1dec54da38fcGilles Debunne @Override 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected boolean drawChild(Canvas canvas, View child, long drawingTime) { 4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (CROSSFADE) { 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int alpha; 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int l = child.getLeft(); 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int t = child.getTop(); 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mFadeStartTime > 0) { 4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project alpha = (int)(((drawingTime-mFadeStartTime)*255)/FADE_DURATION); 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (alpha > 255) { 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project alpha = 255; 4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d(TAG, "drawChild alpha=" + alpha + " l=" + l + " t=" + t 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + " w=" + child.getWidth()); 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (alpha != 255 && mOld != null) { 4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOldPaint.setAlpha(255-alpha); 4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //canvas.drawBitmap(mOld, l, t, mOldPaint); 4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project alpha = 255; 4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int restoreTo = canvas.saveLayerAlpha(l, t, child.getWidth(), child.getHeight(), alpha, 4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG); 4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean rv = super.drawChild(canvas, child, drawingTime); 4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas.restoreToCount(restoreTo); 4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (alpha < 255) { 4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invalidate(); 4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFadeStartTime = -1; 4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mOld != null) { 4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOld.recycle(); 4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOld = null; 4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return rv; 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return super.drawChild(canvas, child, drawingTime); 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Prepare the given view to be shown. This might include adjusting 4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link FrameLayout.LayoutParams} before inserting. 4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void prepareView(View view) { 464b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey // Take requested dimensions from child, but apply default gravity. 465b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey FrameLayout.LayoutParams requested = (FrameLayout.LayoutParams)view.getLayoutParams(); 4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (requested == null) { 467980a938c1c9a6a5791a8240e5a1e6638ab28dc77Romain Guy requested = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, 468980a938c1c9a6a5791a8240e5a1e6638ab28dc77Romain Guy LayoutParams.MATCH_PARENT); 4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 470b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey 471b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey requested.gravity = Gravity.CENTER; 472b8560b66fd2bdf465a8c7fad983f2236778e8106Jeff Sharkey view.setLayoutParams(requested); 4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 476c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project * Inflate and return the default layout requested by AppWidget provider. 4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected View getDefaultView() { 479f140be6c3c21dd0f6d2214929e89d60de31d2c04Joe Onorato if (LOGD) { 480f140be6c3c21dd0f6d2214929e89d60de31d2c04Joe Onorato Log.d(TAG, "getDefaultView"); 481f140be6c3c21dd0f6d2214929e89d60de31d2c04Joe Onorato } 4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View defaultView = null; 4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Exception exception = null; 4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mInfo != null) { 4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Context theirContext = mContext.createPackageContext( 488870e09fcd2dfdc12ac318962efd28b0420c562bbRomain Guy mInfo.provider.getPackageName(), Context.CONTEXT_RESTRICTED); 489220dec2897d739ecb627e46b4cafbd664f4ff762Jeff Sharkey mRemoteContext = theirContext; 4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LayoutInflater inflater = (LayoutInflater) 4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project theirContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project inflater = inflater.cloneInContext(theirContext); 4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project inflater.setFilter(sInflaterFilter); 4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project defaultView = inflater.inflate(mInfo.initialLayout, this, false); 4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w(TAG, "can't inflate defaultView because mInfo is missing"); 4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (PackageManager.NameNotFoundException e) { 4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project exception = e; 5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (RuntimeException e) { 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project exception = e; 5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 504220dec2897d739ecb627e46b4cafbd664f4ff762Jeff Sharkey if (exception != null) { 505220dec2897d739ecb627e46b4cafbd664f4ff762Jeff Sharkey Log.w(TAG, "Error inflating AppWidget " + mInfo + ": " + exception.toString()); 5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (defaultView == null) { 5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (LOGD) Log.d(TAG, "getDefaultView couldn't find any view, so inflating error"); 5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project defaultView = getErrorView(); 5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return defaultView; 5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Inflate and return a view that represents an error state. 5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected View getErrorView() { 5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TextView tv = new TextView(mContext); 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project tv.setText(com.android.internal.R.string.gadget_host_error_inflating); 5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // TODO: get this color from somewhere. 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project tv.setBackgroundColor(Color.argb(127, 0, 0, 0)); 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return tv; 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 52609ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy 5271affb937641fd42c3b94f0c2427b1b68336a572fGuang Zhu @Override 5281affb937641fd42c3b94f0c2427b1b68336a572fGuang Zhu public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 5291affb937641fd42c3b94f0c2427b1b68336a572fGuang Zhu super.onInitializeAccessibilityNodeInfo(info); 5301affb937641fd42c3b94f0c2427b1b68336a572fGuang Zhu info.setClassName(AppWidgetHostView.class.getName()); 5311affb937641fd42c3b94f0c2427b1b68336a572fGuang Zhu } 5321affb937641fd42c3b94f0c2427b1b68336a572fGuang Zhu 53309ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy private static class ParcelableSparseArray extends SparseArray<Parcelable> implements Parcelable { 53409ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy public int describeContents() { 53509ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy return 0; 53609ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy } 53709ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy 53809ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy public void writeToParcel(Parcel dest, int flags) { 53909ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy final int count = size(); 54009ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy dest.writeInt(count); 54109ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy for (int i = 0; i < count; i++) { 54209ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy dest.writeInt(keyAt(i)); 54309ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy dest.writeParcelable(valueAt(i), 0); 54409ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy } 54509ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy } 54609ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy 54709ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy public static final Parcelable.Creator<ParcelableSparseArray> CREATOR = 54809ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy new Parcelable.Creator<ParcelableSparseArray>() { 54909ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy public ParcelableSparseArray createFromParcel(Parcel source) { 55009ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy final ParcelableSparseArray array = new ParcelableSparseArray(); 55109ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy final ClassLoader loader = array.getClass().getClassLoader(); 55209ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy final int count = source.readInt(); 55309ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy for (int i = 0; i < count; i++) { 55409ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy array.put(source.readInt(), source.readParcelable(loader)); 55509ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy } 55609ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy return array; 55709ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy } 55809ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy 55909ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy public ParcelableSparseArray[] newArray(int size) { 56009ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy return new ParcelableSparseArray[size]; 56109ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy } 56209ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy }; 56309ddc08b0d9c849e22f778666f383b7ceefbd9c8Romain Guy } 5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 565