AccountAuthenticatorCache.java revision 603073430bbcb1bd29db7afb9b14e2732ad589fb
1603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana/*
2603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * Copyright (C) 2009 The Android Open Source Project
3603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *
4603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * Licensed under the Apache License, Version 2.0 (the "License");
5603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * you may not use this file except in compliance with the License.
6603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * You may obtain a copy of the License at
7603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *
8603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *      http://www.apache.org/licenses/LICENSE-2.0
9603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *
10603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * Unless required by applicable law or agreed to in writing, software
11603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * distributed under the License is distributed on an "AS IS" BASIS,
12603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * See the License for the specific language governing permissions and
14603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * limitations under the License.
15603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana */
16603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
17603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanapackage android.accounts;
18603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
19603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.content.*;
20603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.content.res.XmlResourceParser;
21603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.content.res.TypedArray;
22603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.content.pm.PackageManager;
23603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.content.pm.ResolveInfo;
24603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.content.pm.ServiceInfo;
25603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.util.Log;
26603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.util.AttributeSet;
27603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.util.Xml;
28603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
29603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport java.util.*;
30603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport java.io.IOException;
31603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
32603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport com.google.android.collect.Maps;
33603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport org.xmlpull.v1.XmlPullParserException;
34603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport org.xmlpull.v1.XmlPullParser;
35603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
36603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana/**
37603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * A cache of services that export the {@link IAccountAuthenticator} interface. This cache
38603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * is built by interrogating the {@link PackageManager} and is updated as packages are added,
39603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * removed and changed. The authenticators are referred to by their account type and
40603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * are made available via the {@link #getAuthenticatorInfo(String type)} method.
41603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana */
42603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanapublic class AccountAuthenticatorCache {
43603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TAG = "Account";
44603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
45603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String SERVICE_INTERFACE = "android.accounts.AccountAuthenticator";
46603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String SERVICE_META_DATA = "android.accounts.AccountAuthenticator";
47603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
48603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private volatile Map<String, AuthenticatorInfo> mAuthenticators;
49603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
50603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final Context mContext;
51603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private BroadcastReceiver mReceiver;
52603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
53603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    public AccountAuthenticatorCache(Context context) {
54603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mContext = context;
55603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mReceiver = new BroadcastReceiver() {
56603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            public void onReceive(Context context, Intent intent) {
57603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                buildAuthenticatorList();
58603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
59603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        };
60603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
61603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
62603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private void monitorPackageChanges() {
63603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        IntentFilter intentFilter = new IntentFilter();
64603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
65603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
66603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
67603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mContext.registerReceiver(mReceiver, intentFilter);
68603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
69603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
70603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    /**
71603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana     * Value type that describes an AccountAuthenticator. The information within can be used
72603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana     * to bind to its {@link IAccountAuthenticator} interface.
73603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana     */
74603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    public class AuthenticatorInfo {
75603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public final String mType;
76603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public final String mComponentShortName;
77603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public final ComponentName mComponentName;
78603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
79603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        private AuthenticatorInfo(String type, ComponentName componentName) {
80603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mType = type;
81603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mComponentName = componentName;
82603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mComponentShortName = componentName.flattenToShortString();
83603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
84603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
85603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
86603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    /**
87603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana     * Accessor for the registered authenticators.
88603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana     * @param type the account type of the authenticator
89603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana     * @return the AuthenticatorInfo that matches the account type or null if none is present
90603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana     */
91603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    public AuthenticatorInfo getAuthenticatorInfo(String type) {
92603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        if (mAuthenticators == null) {
93603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            monitorPackageChanges();
94603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            buildAuthenticatorList();
95603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
96603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        return mAuthenticators.get(type);
97603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
98603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
99603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    /**
100603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana     * @return a collection of {@link AuthenticatorInfo} objects for all
101603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana     * registered authenticators.
102603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana     */
103603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    public Collection<AuthenticatorInfo> getAllAuthenticators() {
104603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        if (mAuthenticators == null) {
105603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            monitorPackageChanges();
106603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            buildAuthenticatorList();
107603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
108603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        return Collections.unmodifiableCollection(mAuthenticators.values());
109603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
110603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
111603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    /**
112603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana     * Stops the monitoring of package additions, removals and changes.
113603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana     */
114603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    public void close() {
115603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        if (mReceiver != null) {
116603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mContext.unregisterReceiver(mReceiver);
117603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mReceiver = null;
118603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
119603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
120603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
121603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    protected void finalize() throws Throwable {
122603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        if (mReceiver != null) {
123603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            Log.e(TAG, "AccountAuthenticatorCache finalized without being closed");
124603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
125603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        close();
126603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        super.finalize();
127603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
128603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
129603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private void buildAuthenticatorList() {
130603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        Map<String, AuthenticatorInfo> authenticators = Maps.newHashMap();
131603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        PackageManager pm = mContext.getPackageManager();
132603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
133603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        List<ResolveInfo> services =
134603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                pm.queryIntentServices(new Intent(SERVICE_INTERFACE), PackageManager.GET_META_DATA);
135603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
136603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        for (ResolveInfo resolveInfo : services) {
137603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            try {
138603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                AuthenticatorInfo info = parseAuthenticatorInfo(resolveInfo);
139603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                if (info != null) {
140603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    authenticators.put(info.mType, info);
141603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                } else {
142603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    Log.w(TAG, "Unable to load input method " + resolveInfo.toString());
143603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
144603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            } catch (XmlPullParserException e) {
145603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                Log.w(TAG, "Unable to load input method " + resolveInfo.toString(), e);
146603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            } catch (IOException e) {
147603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                Log.w(TAG, "Unable to load input method " + resolveInfo.toString(), e);
148603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
149603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
150603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
151603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mAuthenticators = authenticators;
152603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
153603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
154603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    public AuthenticatorInfo parseAuthenticatorInfo(ResolveInfo service)
155603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            throws XmlPullParserException, IOException {
156603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        ServiceInfo si = service.serviceInfo;
157603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        ComponentName componentName = new ComponentName(si.packageName, si.name);
158603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
159603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        PackageManager pm = mContext.getPackageManager();
160603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        String authenticatorType = null;
161603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
162603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        XmlResourceParser parser = null;
163603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
164603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            parser = si.loadXmlMetaData(pm, SERVICE_META_DATA);
165603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (parser == null) {
166603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                throw new XmlPullParserException("No " + SERVICE_META_DATA + " meta-data");
167603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
168603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
169603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            AttributeSet attrs = Xml.asAttributeSet(parser);
170603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
171603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            int type;
172603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
173603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    && type != XmlPullParser.START_TAG) {
174603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
175603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
176603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            String nodeName = parser.getName();
177603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (!"account-authenticator".equals(nodeName)) {
178603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                throw new XmlPullParserException(
179603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                        "Meta-data does not start with account-authenticator tag");
180603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
181603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
182603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            TypedArray sa = mContext.getResources().obtainAttributes(attrs,
183603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    com.android.internal.R.styleable.AccountAuthenticator);
184603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            authenticatorType = sa.getString(
185603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    com.android.internal.R.styleable.AccountAuthenticator_accountType);
186603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            sa.recycle();
187603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
188603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (parser != null) parser.close();
189603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
190603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
191603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        if (authenticatorType == null) {
192603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return null;
193603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
194603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
195603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        return new AuthenticatorInfo(authenticatorType, componentName);
196603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
197603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana}
198