RemoteViewsService.java revision 9b3a2cf2a0a482ce8212eb2775176dd4c23e8e9a
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 Chungimport java.util.Map;
21499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
22499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport android.app.Service;
23499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport android.content.Intent;
24499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport android.os.IBinder;
25499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport android.util.Pair;
26499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
27499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport com.android.internal.widget.IRemoteViewsFactory;
28499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
29499cb9f516062b654952d282f211bee44c31a3c2Winson Chung/**
30499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * The service to be connected to for a remote adapter to request RemoteViews.  Users should
31499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * extend the RemoteViewsService to provide the appropriate RemoteViewsFactory's used to
32499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * populate the remote collection view (ListView, GridView, etc).
33499cb9f516062b654952d282f211bee44c31a3c2Winson Chung */
34499cb9f516062b654952d282f211bee44c31a3c2Winson Chungpublic abstract class RemoteViewsService extends Service {
35499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
36499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    private static final String LOG_TAG = "RemoteViewsService";
37499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
38499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    // multimap implementation for reference counting
399b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung    private HashMap<Intent.FilterComparison, Pair<RemoteViewsFactory, Integer>> mRemoteViewFactories;
40499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    private final Object mLock = new Object();
41499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
42499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    /**
43499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * An interface for an adapter between a remote collection view (ListView, GridView, etc) and
44499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * the underlying data for that view.  The implementor is responsible for making a RemoteView
45499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * for each item in the data set.
466394c0e52cf641d93f678fd052499aa952e3595dWinson Chung     *
476394c0e52cf641d93f678fd052499aa952e3595dWinson Chung     * @see android.widget.Adapter
486eceb00db916e2435a1625af631623bf95ae0e7fWinson Chung     * @see android.appwidget.AppWidgetManager
49499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     */
50499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    public interface RemoteViewsFactory {
516394c0e52cf641d93f678fd052499aa952e3595dWinson Chung        /**
526394c0e52cf641d93f678fd052499aa952e3595dWinson Chung         * Called when your factory is first constructed. The same factory may be shared across
536394c0e52cf641d93f678fd052499aa952e3595dWinson Chung         * multiple RemoteViewAdapters depending on the intent passed.
546394c0e52cf641d93f678fd052499aa952e3595dWinson Chung         */
55499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public void onCreate();
566394c0e52cf641d93f678fd052499aa952e3595dWinson Chung        /**
576eceb00db916e2435a1625af631623bf95ae0e7fWinson Chung         * Called when notifyDataSetChanged() is triggered on the remote adapter. This allows a
586eceb00db916e2435a1625af631623bf95ae0e7fWinson Chung         * RemoteViewsFactory to respond to data changes by updating any internal references.
596eceb00db916e2435a1625af631623bf95ae0e7fWinson Chung         *
606eceb00db916e2435a1625af631623bf95ae0e7fWinson Chung         * @see android.appwidget.AppWidgetManager#notifyAppWidgetViewDataChanged(int[], int)
616394c0e52cf641d93f678fd052499aa952e3595dWinson Chung         */
626394c0e52cf641d93f678fd052499aa952e3595dWinson Chung        public void onDataSetChanged();
636394c0e52cf641d93f678fd052499aa952e3595dWinson Chung        /**
646394c0e52cf641d93f678fd052499aa952e3595dWinson Chung         * Called when the last RemoteViewsAdapter that is associated with this factory is
656394c0e52cf641d93f678fd052499aa952e3595dWinson Chung         * unbound.
666394c0e52cf641d93f678fd052499aa952e3595dWinson Chung         */
67499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public void onDestroy();
68499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
69499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public int getCount();
70499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public RemoteViews getViewAt(int position);
71499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public RemoteViews getLoadingView();
72499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public int getViewTypeCount();
73499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public long getItemId(int position);
74499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public boolean hasStableIds();
75499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    }
76499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
77499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    /**
78499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * A private proxy class for the private IRemoteViewsFactory interface through the
79499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * public RemoteViewsFactory interface.
80499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     */
81499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    private class RemoteViewsFactoryAdapter extends IRemoteViewsFactory.Stub {
82499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public RemoteViewsFactoryAdapter(RemoteViewsFactory factory) {
83499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            mFactory = factory;
84499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
856394c0e52cf641d93f678fd052499aa952e3595dWinson Chung        public void onDataSetChanged() {
866394c0e52cf641d93f678fd052499aa952e3595dWinson Chung            mFactory.onDataSetChanged();
876394c0e52cf641d93f678fd052499aa952e3595dWinson Chung        }
88499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public int getCount() {
89499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            return mFactory.getCount();
90499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
91499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public RemoteViews getViewAt(int position) {
92499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            return mFactory.getViewAt(position);
93499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
94499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public RemoteViews getLoadingView() {
95499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            return mFactory.getLoadingView();
96499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
97499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public int getViewTypeCount() {
98499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            return mFactory.getViewTypeCount();
99499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
100499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public long getItemId(int position) {
101499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            return mFactory.getItemId(position);
102499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
103499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public boolean hasStableIds() {
104499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            return mFactory.hasStableIds();
105499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
106499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
107499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        private RemoteViewsFactory mFactory;
108499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    }
109499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
110499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    public RemoteViewsService() {
1119b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung        mRemoteViewFactories =
1129b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung                new HashMap<Intent.FilterComparison, Pair<RemoteViewsFactory, Integer>>();
113499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    }
114499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
115499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    @Override
116499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    public IBinder onBind(Intent intent) {
117499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        synchronized (mLock) {
118499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            // increment the reference count to the particular factory associated with this intent
1199b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung            Intent.FilterComparison fc = new Intent.FilterComparison(intent);
120499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            Pair<RemoteViewsFactory, Integer> factoryRef = null;
121499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            RemoteViewsFactory factory = null;
1229b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung            if (!mRemoteViewFactories.containsKey(fc)) {
123499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                factory = onGetViewFactory(intent);
124499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                factoryRef = new Pair<RemoteViewsFactory, Integer>(factory, 1);
1259b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung                mRemoteViewFactories.put(fc, factoryRef);
126499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                factory.onCreate();
127499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            } else {
1289b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung                Pair<RemoteViewsFactory, Integer> oldFactoryRef = mRemoteViewFactories.get(fc);
129499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                factory = oldFactoryRef.first;
130499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                int newRefCount = oldFactoryRef.second.intValue() + 1;
131499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                factoryRef = new Pair<RemoteViewsFactory, Integer>(oldFactoryRef.first, newRefCount);
1329b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung                mRemoteViewFactories.put(fc, factoryRef);
133499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            }
134499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            return new RemoteViewsFactoryAdapter(factory);
135499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
136499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    }
137499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
138499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    @Override
139499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    public boolean onUnbind(Intent intent) {
140499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        synchronized (mLock) {
1419b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung            Intent.FilterComparison fc = new Intent.FilterComparison(intent);
1429b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung            if (mRemoteViewFactories.containsKey(fc)) {
143499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                // this alleviates the user's responsibility of having to clear all factories
1449b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung                Pair<RemoteViewsFactory, Integer> oldFactoryRef =
1459b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung                        mRemoteViewFactories.get(fc);
146499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                int newRefCount = oldFactoryRef.second.intValue() - 1;
147499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                if (newRefCount <= 0) {
148499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    oldFactoryRef.first.onDestroy();
1499b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung                    mRemoteViewFactories.remove(fc);
150499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                } else {
1519b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung                    Pair<RemoteViewsFactory, Integer> factoryRef =
1529b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung                            new Pair<RemoteViewsFactory, Integer>(oldFactoryRef.first, newRefCount);
1539b3a2cf2a0a482ce8212eb2775176dd4c23e8e9aWinson Chung                    mRemoteViewFactories.put(fc, factoryRef);
154499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                }
155499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            }
156499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
157499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        return super.onUnbind(intent);
158499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    }
159499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
160499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    /**
161499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * To be implemented by the derived service to generate appropriate factories for
162499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * the data.
163499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     */
164499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    public abstract RemoteViewsFactory onGetViewFactory(Intent intent);
165499cb9f516062b654952d282f211bee44c31a3c2Winson Chung}
166