1 /* 2 * 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 package android.appwidget; 17 18 import android.content.Context; 19 import android.os.Handler; 20 import android.os.IBinder; 21 import android.os.Looper; 22 import android.os.Message; 23 import android.os.RemoteException; 24 import android.os.ServiceManager; 25 import android.widget.RemoteViews; 26 27 import java.util.ArrayList; 28 import java.util.HashMap; 29 30 import com.android.internal.appwidget.IAppWidgetHost; 31 import com.android.internal.appwidget.IAppWidgetService; 32 33 /** 34 * AppWidgetHost provides the interaction with the AppWidget service for apps, 35 * like the home screen, that want to embed AppWidgets in their UI. 36 */ 37 public class AppWidgetHost { 38 39 static final int HANDLE_UPDATE = 1; 40 static final int HANDLE_PROVIDER_CHANGED = 2; 41 42 final static Object sServiceLock = new Object(); 43 static IAppWidgetService sService; 44 45 Context mContext; 46 String mPackageName; 47 48 class Callbacks extends IAppWidgetHost.Stub { updateAppWidget(int appWidgetId, RemoteViews views)49 public void updateAppWidget(int appWidgetId, RemoteViews views) { 50 Message msg = mHandler.obtainMessage(HANDLE_UPDATE); 51 msg.arg1 = appWidgetId; 52 msg.obj = views; 53 msg.sendToTarget(); 54 } 55 providerChanged(int appWidgetId, AppWidgetProviderInfo info)56 public void providerChanged(int appWidgetId, AppWidgetProviderInfo info) { 57 Message msg = mHandler.obtainMessage(HANDLE_PROVIDER_CHANGED); 58 msg.arg1 = appWidgetId; 59 msg.obj = info; 60 msg.sendToTarget(); 61 } 62 } 63 64 class UpdateHandler extends Handler { UpdateHandler(Looper looper)65 public UpdateHandler(Looper looper) { 66 super(looper); 67 } 68 handleMessage(Message msg)69 public void handleMessage(Message msg) { 70 switch (msg.what) { 71 case HANDLE_UPDATE: { 72 updateAppWidgetView(msg.arg1, (RemoteViews)msg.obj); 73 break; 74 } 75 case HANDLE_PROVIDER_CHANGED: { 76 onProviderChanged(msg.arg1, (AppWidgetProviderInfo)msg.obj); 77 break; 78 } 79 } 80 } 81 } 82 83 Handler mHandler; 84 85 int mHostId; 86 Callbacks mCallbacks = new Callbacks(); 87 final HashMap<Integer,AppWidgetHostView> mViews = new HashMap<Integer, AppWidgetHostView>(); 88 AppWidgetHost(Context context, int hostId)89 public AppWidgetHost(Context context, int hostId) { 90 mContext = context; 91 mHostId = hostId; 92 mHandler = new UpdateHandler(context.getMainLooper()); 93 synchronized (sServiceLock) { 94 if (sService == null) { 95 IBinder b = ServiceManager.getService(Context.APPWIDGET_SERVICE); 96 sService = IAppWidgetService.Stub.asInterface(b); 97 } 98 } 99 } 100 101 /** 102 * Start receiving onAppWidgetChanged calls for your AppWidgets. Call this when your activity 103 * becomes visible, i.e. from onStart() in your Activity. 104 */ startListening()105 public void startListening() { 106 int[] updatedIds; 107 ArrayList<RemoteViews> updatedViews = new ArrayList<RemoteViews>(); 108 109 try { 110 if (mPackageName == null) { 111 mPackageName = mContext.getPackageName(); 112 } 113 updatedIds = sService.startListening(mCallbacks, mPackageName, mHostId, updatedViews); 114 } 115 catch (RemoteException e) { 116 throw new RuntimeException("system server dead?", e); 117 } 118 119 final int N = updatedIds.length; 120 for (int i=0; i<N; i++) { 121 updateAppWidgetView(updatedIds[i], updatedViews.get(i)); 122 } 123 } 124 125 /** 126 * Stop receiving onAppWidgetChanged calls for your AppWidgets. Call this when your activity is 127 * no longer visible, i.e. from onStop() in your Activity. 128 */ stopListening()129 public void stopListening() { 130 try { 131 sService.stopListening(mHostId); 132 } 133 catch (RemoteException e) { 134 throw new RuntimeException("system server dead?", e); 135 } 136 } 137 138 /** 139 * Get a appWidgetId for a host in the calling process. 140 * 141 * @return a appWidgetId 142 */ allocateAppWidgetId()143 public int allocateAppWidgetId() { 144 try { 145 if (mPackageName == null) { 146 mPackageName = mContext.getPackageName(); 147 } 148 return sService.allocateAppWidgetId(mPackageName, mHostId); 149 } 150 catch (RemoteException e) { 151 throw new RuntimeException("system server dead?", e); 152 } 153 } 154 155 /** 156 * Stop listening to changes for this AppWidget. 157 */ deleteAppWidgetId(int appWidgetId)158 public void deleteAppWidgetId(int appWidgetId) { 159 synchronized (mViews) { 160 mViews.remove(appWidgetId); 161 try { 162 sService.deleteAppWidgetId(appWidgetId); 163 } 164 catch (RemoteException e) { 165 throw new RuntimeException("system server dead?", e); 166 } 167 } 168 } 169 170 /** 171 * Remove all records about this host from the AppWidget manager. 172 * <ul> 173 * <li>Call this when initializing your database, as it might be because of a data wipe.</li> 174 * <li>Call this to have the AppWidget manager release all resources associated with your 175 * host. Any future calls about this host will cause the records to be re-allocated.</li> 176 * </ul> 177 */ deleteHost()178 public void deleteHost() { 179 try { 180 sService.deleteHost(mHostId); 181 } 182 catch (RemoteException e) { 183 throw new RuntimeException("system server dead?", e); 184 } 185 } 186 187 /** 188 * Remove all records about all hosts for your package. 189 * <ul> 190 * <li>Call this when initializing your database, as it might be because of a data wipe.</li> 191 * <li>Call this to have the AppWidget manager release all resources associated with your 192 * host. Any future calls about this host will cause the records to be re-allocated.</li> 193 * </ul> 194 */ deleteAllHosts()195 public static void deleteAllHosts() { 196 try { 197 sService.deleteAllHosts(); 198 } 199 catch (RemoteException e) { 200 throw new RuntimeException("system server dead?", e); 201 } 202 } 203 createView(Context context, int appWidgetId, AppWidgetProviderInfo appWidget)204 public final AppWidgetHostView createView(Context context, int appWidgetId, 205 AppWidgetProviderInfo appWidget) { 206 AppWidgetHostView view = onCreateView(context, appWidgetId, appWidget); 207 view.setAppWidget(appWidgetId, appWidget); 208 synchronized (mViews) { 209 mViews.put(appWidgetId, view); 210 } 211 RemoteViews views; 212 try { 213 views = sService.getAppWidgetViews(appWidgetId); 214 } catch (RemoteException e) { 215 throw new RuntimeException("system server dead?", e); 216 } 217 view.updateAppWidget(views); 218 return view; 219 } 220 221 /** 222 * Called to create the AppWidgetHostView. Override to return a custom subclass if you 223 * need it. {@more} 224 */ onCreateView(Context context, int appWidgetId, AppWidgetProviderInfo appWidget)225 protected AppWidgetHostView onCreateView(Context context, int appWidgetId, 226 AppWidgetProviderInfo appWidget) { 227 return new AppWidgetHostView(context); 228 } 229 230 /** 231 * Called when the AppWidget provider for a AppWidget has been upgraded to a new apk. 232 */ 233 @SuppressWarnings({"UnusedDeclaration"}) onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidget)234 protected void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidget) { 235 } 236 updateAppWidgetView(int appWidgetId, RemoteViews views)237 void updateAppWidgetView(int appWidgetId, RemoteViews views) { 238 AppWidgetHostView v; 239 synchronized (mViews) { 240 v = mViews.get(appWidgetId); 241 } 242 if (v != null) { 243 v.updateAppWidget(views); 244 } 245 } 246 } 247 248 249