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