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