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