1ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng/* 2ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng * Copyright (C) 2010 The Android Open Source Project 3ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng * 4ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng * Licensed under the Apache License, Version 2.0 (the "License"); 5ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng * you may not use this file except in compliance with the License. 6ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng * You may obtain a copy of the License at 7ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng * 8ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng * http://www.apache.org/licenses/LICENSE-2.0 9ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng * 10ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng * Unless required by applicable law or agreed to in writing, software 11ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng * distributed under the License is distributed on an "AS IS" BASIS, 12ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng * See the License for the specific language governing permissions and 14ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng * limitations under the License 15ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng */ 16ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng 17ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengpackage com.android.contacts.common.util; 18ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng 19612b408f55e4a42635925c52f93c4b8f1a0916a7Ihab Awadimport android.accounts.AccountManager; 20ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.accounts.AuthenticatorDescription; 21ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.content.Context; 22ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.content.pm.PackageInfo; 23ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.content.pm.PackageManager; 24ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.content.pm.PackageManager.NameNotFoundException; 25ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.content.pm.ServiceInfo; 26ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.content.res.Resources; 27ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.content.res.Resources.NotFoundException; 28ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.content.res.TypedArray; 29ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.content.res.XmlResourceParser; 30ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.util.AttributeSet; 31ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.util.Log; 32ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.util.Xml; 33ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng 343aa2cb56ece8461f2df69d9300c9a1abf03f6989Yorke Leeimport com.android.contacts.common.R; 353aa2cb56ece8461f2df69d9300c9a1abf03f6989Yorke Lee 36ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport org.xmlpull.v1.XmlPullParser; 37ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport org.xmlpull.v1.XmlPullParserException; 38ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng 39ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport java.io.IOException; 40ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng 41ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng/** 42ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng * Retrieves localized names per account type. This allows customizing texts like 43ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng * "All Contacts" for certain account types, but e.g. "All Friends" or "All Connections" for others. 44ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng */ 45ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengpublic class LocalizedNameResolver { 46ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng private static final String TAG = "LocalizedNameResolver"; 47ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng 48ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng /** 49ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng * Meta-data key for the contacts configuration associated with a sync service. 50ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng */ 51ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng private static final String METADATA_CONTACTS = "android.provider.CONTACTS_STRUCTURE"; 52ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng 53ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng private static final String CONTACTS_DATA_KIND = "ContactsDataKind"; 54ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng 55ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng /** 56ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng * Returns the name for All Contacts for the specified account type. 57ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng */ 58ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng public static String getAllContactsName(Context context, String accountType) { 59ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng if (context == null) throw new IllegalArgumentException("Context must not be null"); 60ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng if (accountType == null) return null; 61ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng 62ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng return resolveAllContactsName(context, accountType); 63ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng } 64ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng 65ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng /** 66ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng * Finds "All Contacts"-Name for the specified account type. 67ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng */ 68ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng private static String resolveAllContactsName(Context context, String accountType) { 69612b408f55e4a42635925c52f93c4b8f1a0916a7Ihab Awad final AccountManager am = AccountManager.get(context); 70ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng 71ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng for (AuthenticatorDescription auth : am.getAuthenticatorTypes()) { 72ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng if (accountType.equals(auth.type)) { 73ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng return resolveAllContactsNameFromMetaData(context, auth.packageName); 74ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng } 75ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng } 76ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng 77ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng return null; 78ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng } 79ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng 80ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng /** 81ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng * Finds the meta-data XML containing the contacts configuration and 82ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng * reads the picture priority from that file. 83ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng */ 84ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng private static String resolveAllContactsNameFromMetaData(Context context, String packageName) { 85ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng final PackageManager pm = context.getPackageManager(); 86ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng try { 87ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng PackageInfo pi = pm.getPackageInfo(packageName, PackageManager.GET_SERVICES 88ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng | PackageManager.GET_META_DATA); 89ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng if (pi != null && pi.services != null) { 90ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng for (ServiceInfo si : pi.services) { 91ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng final XmlResourceParser parser = si.loadXmlMetaData(pm, METADATA_CONTACTS); 92ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng if (parser != null) { 93ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng return loadAllContactsNameFromXml(context, parser, packageName); 94ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng } 95ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng } 96ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng } 97ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng } catch (NameNotFoundException e) { 98ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng Log.w(TAG, "Problem loading \"All Contacts\"-name: " + e.toString()); 99ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng } 100ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng return null; 101ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng } 102ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng 103ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng private static String loadAllContactsNameFromXml(Context context, XmlPullParser parser, 104ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng String packageName) { 105ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng try { 106ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng final AttributeSet attrs = Xml.asAttributeSet(parser); 107ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng int type; 108ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng while ((type = parser.next()) != XmlPullParser.START_TAG 109ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng && type != XmlPullParser.END_DOCUMENT) { 110ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng // Drain comments and whitespace 111ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng } 112ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng 113ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng if (type != XmlPullParser.START_TAG) { 114ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng throw new IllegalStateException("No start tag found"); 115ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng } 116ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng 117ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng final int depth = parser.getDepth(); 118ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) 119ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng && type != XmlPullParser.END_DOCUMENT) { 120ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng String name = parser.getName(); 121ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng if (type == XmlPullParser.START_TAG && CONTACTS_DATA_KIND.equals(name)) { 122ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng final TypedArray typedArray = context.obtainStyledAttributes(attrs, 1233aa2cb56ece8461f2df69d9300c9a1abf03f6989Yorke Lee R.styleable.ContactsDataKind); 124ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng try { 125ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng // See if a string has been hardcoded directly into the xml 126ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng final String nonResourceString = typedArray.getNonResourceString( 1273aa2cb56ece8461f2df69d9300c9a1abf03f6989Yorke Lee R.styleable.ContactsDataKind_android_allContactsName); 128ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng if (nonResourceString != null) { 129ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng return nonResourceString; 130ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng } 131ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng 132ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng // See if a resource is referenced. We can't rely on getString 133ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng // to automatically resolve it as the resource lives in a different package 134ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng int id = typedArray.getResourceId( 1353aa2cb56ece8461f2df69d9300c9a1abf03f6989Yorke Lee R.styleable.ContactsDataKind_android_allContactsName, 0); 136ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng if (id == 0) return null; 137ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng 138ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng // Resolve the resource Id 139ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng final PackageManager packageManager = context.getPackageManager(); 140ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng final Resources resources; 141ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng try { 142ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng resources = packageManager.getResourcesForApplication(packageName); 143ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng } catch (NameNotFoundException e) { 144ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng return null; 145ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng } 146ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng try { 147ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng return resources.getString(id); 148ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng } catch (NotFoundException e) { 149ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng return null; 150ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng } 151ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng } finally { 152ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng typedArray.recycle(); 153ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng } 154ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng } 155ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng } 156ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng return null; 157ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng } catch (XmlPullParserException e) { 158ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng throw new IllegalStateException("Problem reading XML", e); 159ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng } catch (IOException e) { 160ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng throw new IllegalStateException("Problem reading XML", e); 161ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng } 162ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng } 163ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng} 164