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