1499cb9f516062b654952d282f211bee44c31a3c2Winson Chung/*
2499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * Copyright (C) 2007 The Android Open Source Project
3499cb9f516062b654952d282f211bee44c31a3c2Winson Chung *
4499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * Licensed under the Apache License, Version 2.0 (the "License");
5499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * you may not use this file except in compliance with the License.
6499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * You may obtain a copy of the License at
7499cb9f516062b654952d282f211bee44c31a3c2Winson Chung *
8499cb9f516062b654952d282f211bee44c31a3c2Winson Chung *      http://www.apache.org/licenses/LICENSE-2.0
9499cb9f516062b654952d282f211bee44c31a3c2Winson Chung *
10499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * Unless required by applicable law or agreed to in writing, software
11499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * distributed under the License is distributed on an "AS IS" BASIS,
12499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * See the License for the specific language governing permissions and
14499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * limitations under the License.
15499cb9f516062b654952d282f211bee44c31a3c2Winson Chung */
16499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
17499cb9f516062b654952d282f211bee44c31a3c2Winson Chungpackage android.widget;
18499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
19499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport java.util.HashMap;
20499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
21499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport android.app.Service;
22499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport android.content.Intent;
23499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport android.os.IBinder;
24499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
25499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport com.android.internal.widget.IRemoteViewsFactory;
26499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
27499cb9f516062b654952d282f211bee44c31a3c2Winson Chung/**
28499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * The service to be connected to for a remote adapter to request RemoteViews.  Users should
29499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * extend the RemoteViewsService to provide the appropriate RemoteViewsFactory's used to
30499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * populate the remote collection view (ListView, GridView, etc).
31499cb9f516062b654952d282f211bee44c31a3c2Winson Chung */
32499cb9f516062b654952d282f211bee44c31a3c2Winson Chungpublic abstract class RemoteViewsService extends Service {
33499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
34499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    private static final String LOG_TAG = "RemoteViewsService";
35499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
3616c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung    // Used for reference counting of RemoteViewsFactories
3716c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung    // Because we are now unbinding when we are not using the Service (to allow them to be
3816c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung    // reclaimed), the references to the factories that are created need to be stored and used when
3916c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung    // the service is restarted (in response to user input for example).  When the process is
4016c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung    // destroyed, so is this static cache of RemoteViewsFactories.
4184bbb020217adcdfe0694c44ccab57e208ffde16Winson Chung    private static final HashMap<Intent.FilterComparison, RemoteViewsFactory> sRemoteViewFactories =
4216c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung            new HashMap<Intent.FilterComparison, RemoteViewsFactory>();
4384bbb020217adcdfe0694c44ccab57e208ffde16Winson Chung    private static final Object sLock = new Object();
44499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
45499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    /**
46499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * An interface for an adapter between a remote collection view (ListView, GridView, etc) and
47499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * the underlying data for that view.  The implementor is responsible for making a RemoteView
480e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen     * for each item in the data set. This interface is a thin wrapper around {@link Adapter}.
496394c0e52cf641d93f678fd052499aa952e3595dWinson Chung     *
506394c0e52cf641d93f678fd052499aa952e3595dWinson Chung     * @see android.widget.Adapter
516eceb00db916e2435a1625af631623bf95ae0e7fWinson Chung     * @see android.appwidget.AppWidgetManager
52499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     */
53499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    public interface RemoteViewsFactory {
546394c0e52cf641d93f678fd052499aa952e3595dWinson Chung        /**
556394c0e52cf641d93f678fd052499aa952e3595dWinson Chung         * Called when your factory is first constructed. The same factory may be shared across
566394c0e52cf641d93f678fd052499aa952e3595dWinson Chung         * multiple RemoteViewAdapters depending on the intent passed.
576394c0e52cf641d93f678fd052499aa952e3595dWinson Chung         */
58499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public void onCreate();
590e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen
606394c0e52cf641d93f678fd052499aa952e3595dWinson Chung        /**
616eceb00db916e2435a1625af631623bf95ae0e7fWinson Chung         * Called when notifyDataSetChanged() is triggered on the remote adapter. This allows a
626eceb00db916e2435a1625af631623bf95ae0e7fWinson Chung         * RemoteViewsFactory to respond to data changes by updating any internal references.
636eceb00db916e2435a1625af631623bf95ae0e7fWinson Chung         *
640e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         * Note: expensive tasks can be safely performed synchronously within this method. In the
650e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         * interim, the old data will be displayed within the widget.
660e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         *
676eceb00db916e2435a1625af631623bf95ae0e7fWinson Chung         * @see android.appwidget.AppWidgetManager#notifyAppWidgetViewDataChanged(int[], int)
686394c0e52cf641d93f678fd052499aa952e3595dWinson Chung         */
696394c0e52cf641d93f678fd052499aa952e3595dWinson Chung        public void onDataSetChanged();
700e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen
716394c0e52cf641d93f678fd052499aa952e3595dWinson Chung        /**
726394c0e52cf641d93f678fd052499aa952e3595dWinson Chung         * Called when the last RemoteViewsAdapter that is associated with this factory is
736394c0e52cf641d93f678fd052499aa952e3595dWinson Chung         * unbound.
746394c0e52cf641d93f678fd052499aa952e3595dWinson Chung         */
75499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public void onDestroy();
76499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
770e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen        /**
780e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         * See {@link Adapter#getCount()}
790e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         *
800e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         * @return Count of items.
810e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         */
82499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public int getCount();
830e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen
840e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen        /**
850e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         * See {@link Adapter#getView(int, android.view.View, android.view.ViewGroup)}.
860e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         *
870e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         * Note: expensive tasks can be safely performed synchronously within this method, and a
880e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         * loading view will be displayed in the interim. See {@link #getLoadingView()}.
890e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         *
900e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         * @param position The position of the item within the Factory's data set of the item whose
910e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         *        view we want.
920e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         * @return A RemoteViews object corresponding to the data at the specified position.
930e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         */
94499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public RemoteViews getViewAt(int position);
950e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen
960e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen        /**
970e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         * This allows for the use of a custom loading view which appears between the time that
980e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         * {@link #getViewAt(int)} is called and returns. If null is returned, a default loading
990e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         * view will be used.
1000e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         *
1010e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         * @return The RemoteViews representing the desired loading view.
1020e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         */
103499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public RemoteViews getLoadingView();
1040e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen
1050e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen        /**
1060e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         * See {@link Adapter#getViewTypeCount()}.
1070e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         *
1080e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         * @return The number of types of Views that will be returned by this factory.
1090e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         */
110499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public int getViewTypeCount();
1110e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen
1120e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen        /**
1130e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         * See {@link Adapter#getItemId(int)}.
1140e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         *
1150e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         * @param position The position of the item within the data set whose row id we want.
1160e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         * @return The id of the item at the specified position.
1170e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         */
118499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public long getItemId(int position);
1190e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen
1200e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen        /**
1210e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         * See {@link Adapter#hasStableIds()}.
1220e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         *
1230e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         * @return True if the same id always refers to the same object.
1240e2de6d7187ef67ec00a2f2544450caa4a239c39Adam Cohen         */
125499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public boolean hasStableIds();
126499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    }
127499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
128499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    /**
129499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * A private proxy class for the private IRemoteViewsFactory interface through the
130499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * public RemoteViewsFactory interface.
131499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     */
13216c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung    private static class RemoteViewsFactoryAdapter extends IRemoteViewsFactory.Stub {
13316c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung        public RemoteViewsFactoryAdapter(RemoteViewsFactory factory, boolean isCreated) {
134499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            mFactory = factory;
13516c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung            mIsCreated = isCreated;
13616c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung        }
13716c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung        public synchronized boolean isCreated() {
13816c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung            return mIsCreated;
139499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
140f58a96152cecb480decf8c0352b01322663e5cbcWinson Chung        public synchronized void onDataSetChanged() {
1412625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            try {
1422625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen                mFactory.onDataSetChanged();
1432625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            } catch (Exception ex) {
1442625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen                Thread t = Thread.currentThread();
1452625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen                Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex);
1462625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            }
1476394c0e52cf641d93f678fd052499aa952e3595dWinson Chung        }
148c3f581b0474a216938810885f4f606e0db1f21ffWinson Chung        public synchronized void onDataSetChangedAsync() {
149c3f581b0474a216938810885f4f606e0db1f21ffWinson Chung            onDataSetChanged();
150c3f581b0474a216938810885f4f606e0db1f21ffWinson Chung        }
151f58a96152cecb480decf8c0352b01322663e5cbcWinson Chung        public synchronized int getCount() {
1522625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            int count = 0;
1532625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            try {
1542625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen                count = mFactory.getCount();
1552625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            } catch (Exception ex) {
1562625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen                Thread t = Thread.currentThread();
1572625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen                Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex);
1582625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            }
1592625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            return count;
160499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
161f58a96152cecb480decf8c0352b01322663e5cbcWinson Chung        public synchronized RemoteViews getViewAt(int position) {
1622625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            RemoteViews rv = null;
1632625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            try {
1642625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen                rv = mFactory.getViewAt(position);
1652625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen                if (rv != null) {
1662625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen                    rv.setIsWidgetCollectionChild(true);
1672625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen                }
1682625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            } catch (Exception ex) {
1692625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen                Thread t = Thread.currentThread();
1702625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen                Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex);
1712625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            }
172ca6fd847945464c2ddddcd165021082c048f05fbAdam Cohen            return rv;
173499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
174f58a96152cecb480decf8c0352b01322663e5cbcWinson Chung        public synchronized RemoteViews getLoadingView() {
1752625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            RemoteViews rv = null;
1762625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            try {
1772625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen                rv = mFactory.getLoadingView();
1782625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            } catch (Exception ex) {
1792625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen                Thread t = Thread.currentThread();
1802625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen                Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex);
1812625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            }
1822625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            return rv;
183499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
184f58a96152cecb480decf8c0352b01322663e5cbcWinson Chung        public synchronized int getViewTypeCount() {
1852625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            int count = 0;
1862625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            try {
1872625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen                count = mFactory.getViewTypeCount();
1882625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            } catch (Exception ex) {
1892625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen                Thread t = Thread.currentThread();
1902625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen                Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex);
1912625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            }
1922625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            return count;
193499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
194f58a96152cecb480decf8c0352b01322663e5cbcWinson Chung        public synchronized long getItemId(int position) {
1952625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            long id = 0;
1962625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            try {
1972625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen                id = mFactory.getItemId(position);
1982625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            } catch (Exception ex) {
1992625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen                Thread t = Thread.currentThread();
2002625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen                Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex);
2012625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            }
2022625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            return id;
203499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
204f58a96152cecb480decf8c0352b01322663e5cbcWinson Chung        public synchronized boolean hasStableIds() {
2052625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            boolean hasStableIds = false;
2062625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            try {
2072625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen                hasStableIds = mFactory.hasStableIds();
2082625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            } catch (Exception ex) {
2092625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen                Thread t = Thread.currentThread();
2102625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen                Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex);
2112625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            }
2122625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen            return hasStableIds;
213499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
21484bbb020217adcdfe0694c44ccab57e208ffde16Winson Chung        public void onDestroy(Intent intent) {
21584bbb020217adcdfe0694c44ccab57e208ffde16Winson Chung            synchronized (sLock) {
21684bbb020217adcdfe0694c44ccab57e208ffde16Winson Chung                Intent.FilterComparison fc = new Intent.FilterComparison(intent);
21784bbb020217adcdfe0694c44ccab57e208ffde16Winson Chung                if (RemoteViewsService.sRemoteViewFactories.containsKey(fc)) {
21884bbb020217adcdfe0694c44ccab57e208ffde16Winson Chung                    RemoteViewsFactory factory = RemoteViewsService.sRemoteViewFactories.get(fc);
2192625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen                    try {
2202625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen                        factory.onDestroy();
2212625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen                    } catch (Exception ex) {
2222625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen                        Thread t = Thread.currentThread();
2232625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen                        Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex);
2242625feae79ab418355c2a4dafe8b162bba3cc1cfAdam Cohen                    }
22584bbb020217adcdfe0694c44ccab57e208ffde16Winson Chung                    RemoteViewsService.sRemoteViewFactories.remove(fc);
22684bbb020217adcdfe0694c44ccab57e208ffde16Winson Chung                }
22784bbb020217adcdfe0694c44ccab57e208ffde16Winson Chung            }
22884bbb020217adcdfe0694c44ccab57e208ffde16Winson Chung        }
229499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
230499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        private RemoteViewsFactory mFactory;
23116c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung        private boolean mIsCreated;
232499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    }
233499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
234499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    @Override
235499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    public IBinder onBind(Intent intent) {
23684bbb020217adcdfe0694c44ccab57e208ffde16Winson Chung        synchronized (sLock) {
2379b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung            Intent.FilterComparison fc = new Intent.FilterComparison(intent);
238499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            RemoteViewsFactory factory = null;
23916c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung            boolean isCreated = false;
24084bbb020217adcdfe0694c44ccab57e208ffde16Winson Chung            if (!sRemoteViewFactories.containsKey(fc)) {
241499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                factory = onGetViewFactory(intent);
24284bbb020217adcdfe0694c44ccab57e208ffde16Winson Chung                sRemoteViewFactories.put(fc, factory);
243499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                factory.onCreate();
24416c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung                isCreated = false;
245499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            } else {
24684bbb020217adcdfe0694c44ccab57e208ffde16Winson Chung                factory = sRemoteViewFactories.get(fc);
24716c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung                isCreated = true;
248499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            }
24916c8d8a558f94ec14ef52bb5ac11044e2d0d902cWinson Chung            return new RemoteViewsFactoryAdapter(factory, isCreated);
250499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
251499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    }
252499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
253499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    /**
254499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * To be implemented by the derived service to generate appropriate factories for
255499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * the data.
256499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     */
257499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    public abstract RemoteViewsFactory onGetViewFactory(Intent intent);
258499cb9f516062b654952d282f211bee44c31a3c2Winson Chung}
259