• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.providers.contacts;
18 
19 import com.android.internal.util.XmlUtils;
20 import com.google.android.collect.Maps;
21 
22 import org.xmlpull.v1.XmlPullParser;
23 import org.xmlpull.v1.XmlPullParserException;
24 
25 import android.accounts.AccountManager;
26 import android.accounts.AuthenticatorDescription;
27 import android.content.Context;
28 import android.content.pm.PackageInfo;
29 import android.content.pm.PackageManager;
30 import android.content.pm.ServiceInfo;
31 import android.content.pm.PackageManager.NameNotFoundException;
32 import android.content.res.XmlResourceParser;
33 import android.util.Log;
34 
35 import java.io.IOException;
36 import java.util.HashMap;
37 
38 /**
39  * Maintains a cache of photo priority per account type.  During contact aggregation
40  * photo with a higher priority is chosen for the the entire contact, barring an
41  * explicit override by the user, which is captured as the is_superprimary flag
42  * on the photo itself.
43  */
44 public class PhotoPriorityResolver  {
45     private static final String TAG = "PhotoPriorityResolver";
46 
47     public static final int DEFAULT_PRIORITY = 7;
48 
49     /**
50      * Meta-data key for the contacts configuration associated with a sync service.
51      */
52     private static final String METADATA_CONTACTS = "android.provider.CONTACTS_STRUCTURE";
53 
54     /**
55      * The XML tag capturing the picture priority. The syntax is:
56      * <code>&lt;Picture android:priority="6"/&gt;</code>
57      */
58     private static final String PICTURE_TAG = "Picture";
59 
60     /**
61      * Name of the attribute of the Picture tag capturing the priority itself.
62      */
63     private static final String PRIORITY_ATTR = "priority";
64 
65     private Context mContext;
66     private HashMap<String, Integer> mPhotoPriorities = Maps.newHashMap();
67 
PhotoPriorityResolver(Context context)68     public PhotoPriorityResolver(Context context) {
69         mContext = context;
70     }
71 
72     /**
73      * Returns the photo priority for the specified account type.  Maintains cache
74      * of photo priorities.
75      */
getPhotoPriority(String accountType)76     public synchronized int getPhotoPriority(String accountType) {
77         if (accountType == null) {
78             return DEFAULT_PRIORITY;
79         }
80 
81         Integer priority = mPhotoPriorities.get(accountType);
82         if (priority == null) {
83             priority = resolvePhotoPriority(accountType);
84             mPhotoPriorities.put(accountType, priority);
85         }
86         return priority;
87      }
88 
89     /**
90      * Finds photo priority for the specified account type.
91      */
resolvePhotoPriority(String accountType)92     private int resolvePhotoPriority(String accountType) {
93         final AccountManager am = AccountManager.get(mContext);
94 
95         for (AuthenticatorDescription auth : am.getAuthenticatorTypes()) {
96             if (accountType.equals(auth.type)) {
97                 return resolvePhotoPriorityFromMetaData(auth.packageName);
98             }
99         }
100 
101         return DEFAULT_PRIORITY;
102     }
103 
104     /**
105      * Finds the meta-data XML containing the contacts configuration and
106      * reads the picture priority from that file.
107      */
resolvePhotoPriorityFromMetaData(String packageName)108     /* package */ int resolvePhotoPriorityFromMetaData(String packageName) {
109         final PackageManager pm = mContext.getPackageManager();
110         try {
111             PackageInfo pi = pm.getPackageInfo(packageName, PackageManager.GET_SERVICES
112                     | PackageManager.GET_META_DATA);
113             if (pi != null && pi.services != null) {
114                 for (ServiceInfo si : pi.services) {
115                     final XmlResourceParser parser = si.loadXmlMetaData(pm, METADATA_CONTACTS);
116                     if (parser != null) {
117                         return loadPhotoPriorityFromXml(mContext, parser);
118                     }
119                 }
120             }
121         } catch (NameNotFoundException e) {
122             Log.w(TAG, "Problem loading photo priorities: " + e.toString());
123         }
124         return DEFAULT_PRIORITY;
125     }
126 
loadPhotoPriorityFromXml(Context context, XmlPullParser parser)127     private int loadPhotoPriorityFromXml(Context context, XmlPullParser parser) {
128         int priority = DEFAULT_PRIORITY;
129         try {
130             int type;
131             while ((type = parser.next()) != XmlPullParser.START_TAG
132                     && type != XmlPullParser.END_DOCUMENT) {
133                 // Drain comments and whitespace
134             }
135 
136             if (type != XmlPullParser.START_TAG) {
137                 throw new IllegalStateException("No start tag found");
138             }
139 
140             final int depth = parser.getDepth();
141             while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
142                     && type != XmlPullParser.END_DOCUMENT) {
143                 String name = parser.getName();
144                 if (type == XmlPullParser.START_TAG && PICTURE_TAG.equals(name)) {
145                     int attributeCount = parser.getAttributeCount();
146                     for (int i = 0; i < attributeCount; i++) {
147                         String attr = parser.getAttributeName(i);
148                         if (PRIORITY_ATTR.equals(attr)) {
149                             priority = XmlUtils.convertValueToInt(parser.getAttributeValue(i),
150                                     DEFAULT_PRIORITY);
151                         } else {
152                             throw new IllegalStateException("Unsupported attribute " + attr);
153                         }
154                     }
155                 }
156             }
157         } catch (XmlPullParserException e) {
158             throw new IllegalStateException("Problem reading XML", e);
159         } catch (IOException e) {
160             throw new IllegalStateException("Problem reading XML", e);
161         }
162 
163         return priority;
164     }
165 }
166