16340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann/* 26340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann * Copyright (C) 2010 The Android Open Source Project 36340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann * 46340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann * Licensed under the Apache License, Version 2.0 (the "License"); 56340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann * you may not use this file except in compliance with the License. 66340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann * You may obtain a copy of the License at 76340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann * 86340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann * http://www.apache.org/licenses/LICENSE-2.0 96340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann * 106340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann * Unless required by applicable law or agreed to in writing, software 116340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann * distributed under the License is distributed on an "AS IS" BASIS, 126340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann * See the License for the specific language governing permissions and 146340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann * limitations under the License 156340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann */ 166340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann 176340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmannpackage com.android.contacts.util; 186340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann 196340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmannimport android.accounts.AccountManager; 206340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmannimport android.accounts.AuthenticatorDescription; 216340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmannimport android.content.Context; 226340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmannimport android.content.pm.PackageInfo; 236340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmannimport android.content.pm.PackageManager; 246340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmannimport android.content.pm.PackageManager.NameNotFoundException; 25e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport android.content.pm.ServiceInfo; 266340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmannimport android.content.res.Resources; 27e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport android.content.res.Resources.NotFoundException; 286340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmannimport android.content.res.TypedArray; 296340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmannimport android.content.res.XmlResourceParser; 306340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmannimport android.util.AttributeSet; 316340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmannimport android.util.Log; 326340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmannimport android.util.Xml; 336340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann 34e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport org.xmlpull.v1.XmlPullParser; 35e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport org.xmlpull.v1.XmlPullParserException; 36e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Cheng 376340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmannimport java.io.IOException; 386340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann 396340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann/** 406340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann * Retrieves localized names per account type. This allows customizing texts like 416340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann * "All Contacts" for certain account types, but e.g. "All Friends" or "All Connections" for others. 426340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann */ 436340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmannpublic class LocalizedNameResolver { 446340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann private static final String TAG = "LocalizedNameResolver"; 456340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann 466340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann /** 476340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann * Meta-data key for the contacts configuration associated with a sync service. 486340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann */ 496340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann private static final String METADATA_CONTACTS = "android.provider.CONTACTS_STRUCTURE"; 506340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann 516340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann private static final String CONTACTS_DATA_KIND = "ContactsDataKind"; 526340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann 536340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann /** 546340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann * Returns the name for All Contacts for the specified account type. 556340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann */ 566340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann public static String getAllContactsName(Context context, String accountType) { 576340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann if (context == null) throw new IllegalArgumentException("Context must not be null"); 586340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann if (accountType == null) return null; 596340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann 606340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann return resolveAllContactsName(context, accountType); 616340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann } 626340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann 636340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann /** 646340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann * Finds "All Contacts"-Name for the specified account type. 656340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann */ 666340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann private static String resolveAllContactsName(Context context, String accountType) { 676340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann final AccountManager am = AccountManager.get(context); 686340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann 696340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann for (AuthenticatorDescription auth : am.getAuthenticatorTypes()) { 706340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann if (accountType.equals(auth.type)) { 716340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann return resolveAllContactsNameFromMetaData(context, auth.packageName); 726340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann } 736340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann } 746340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann 756340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann return null; 766340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann } 776340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann 786340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann /** 796340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann * Finds the meta-data XML containing the contacts configuration and 806340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann * reads the picture priority from that file. 816340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann */ 826340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann private static String resolveAllContactsNameFromMetaData(Context context, String packageName) { 836340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann final PackageManager pm = context.getPackageManager(); 846340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann try { 856340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann PackageInfo pi = pm.getPackageInfo(packageName, PackageManager.GET_SERVICES 866340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann | PackageManager.GET_META_DATA); 876340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann if (pi != null && pi.services != null) { 886340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann for (ServiceInfo si : pi.services) { 896340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann final XmlResourceParser parser = si.loadXmlMetaData(pm, METADATA_CONTACTS); 906340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann if (parser != null) { 916340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann return loadAllContactsNameFromXml(context, parser, packageName); 926340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann } 936340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann } 946340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann } 956340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann } catch (NameNotFoundException e) { 966340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann Log.w(TAG, "Problem loading \"All Contacts\"-name: " + e.toString()); 976340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann } 986340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann return null; 996340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann } 1006340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann 1016340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann private static String loadAllContactsNameFromXml(Context context, XmlPullParser parser, 1026340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann String packageName) { 1036340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann try { 1046340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann final AttributeSet attrs = Xml.asAttributeSet(parser); 1056340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann int type; 1066340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann while ((type = parser.next()) != XmlPullParser.START_TAG 1076340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann && type != XmlPullParser.END_DOCUMENT) { 1086340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann // Drain comments and whitespace 1096340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann } 1106340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann 1116340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann if (type != XmlPullParser.START_TAG) { 1126340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann throw new IllegalStateException("No start tag found"); 1136340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann } 1146340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann 1156340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann final int depth = parser.getDepth(); 1166340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) 1176340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann && type != XmlPullParser.END_DOCUMENT) { 1186340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann String name = parser.getName(); 1196340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann if (type == XmlPullParser.START_TAG && CONTACTS_DATA_KIND.equals(name)) { 1206340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann final TypedArray typedArray = context.obtainStyledAttributes(attrs, 1216340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann android.R.styleable.ContactsDataKind); 1226340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann try { 1236340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann // See if a string has been hardcoded directly into the xml 1246340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann final String nonResourceString = typedArray.getNonResourceString( 1256340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann android.R.styleable.ContactsDataKind_allContactsName); 1266340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann if (nonResourceString != null) { 1276340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann return nonResourceString; 1286340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann } 1296340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann 1306340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann // See if a resource is referenced. We can't rely on getString 1316340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann // to automatically resolve it as the resource lives in a different package 1326340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann int id = typedArray.getResourceId( 1336340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann android.R.styleable.ContactsDataKind_allContactsName, 0); 1346340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann if (id == 0) return null; 1356340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann 1366340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann // Resolve the resource Id 1376340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann final PackageManager packageManager = context.getPackageManager(); 1386340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann final Resources resources; 1396340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann try { 1406340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann resources = packageManager.getResourcesForApplication(packageName); 1416340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann } catch (NameNotFoundException e) { 1426340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann return null; 1436340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann } 1446340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann try { 1456340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann return resources.getString(id); 1466340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann } catch (NotFoundException e) { 1476340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann return null; 1486340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann } 1496340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann } finally { 1506340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann typedArray.recycle(); 1516340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann } 1526340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann } 1536340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann } 1546340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann return null; 1556340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann } catch (XmlPullParserException e) { 1566340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann throw new IllegalStateException("Problem reading XML", e); 1576340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann } catch (IOException e) { 1586340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann throw new IllegalStateException("Problem reading XML", e); 1596340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann } 1606340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann } 1616340038524b0b11cfdc07c553e1f5669812b48d1Daniel Lehmann} 162