• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 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.loaderapp.model;
18 
19 import org.xmlpull.v1.XmlPullParser;
20 import org.xmlpull.v1.XmlPullParserException;
21 
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.pm.PackageManager;
25 import android.content.pm.ResolveInfo;
26 import android.content.res.TypedArray;
27 import android.content.res.XmlResourceParser;
28 import android.util.AttributeSet;
29 import android.util.Xml;
30 
31 import java.io.IOException;
32 import java.util.List;
33 
34 /*
35 
36 <!-- example of what SourceConstraints would look like in XML -->
37 <!-- NOTE: may not directly match the current structure version -->
38 
39 <DataKind
40     mimeType="vnd.android.cursor.item/email"
41     title="@string/title_postal"
42     icon="@drawable/icon_postal"
43     weight="12"
44     editable="true">
45 
46     <!-- these are defined using string-builder-ish -->
47     <ActionHeader></ActionHeader>
48     <ActionBody socialSummary="true" />  <!-- can pull together various columns -->
49 
50     <!-- ordering handles precedence the "insert/add" case -->
51     <!-- assume uniform type when missing "column", use title in place -->
52     <EditTypes column="data5" overallMax="-1">
53         <EditType rawValue="0" label="@string/type_home" specificMax="-1" />
54         <EditType rawValue="1" label="@string/type_work" specificMax="-1" secondary="true" />
55         <EditType rawValue="4" label="@string/type_custom" customColumn="data6" specificMax="-1" secondary="true" />
56     </EditTypes>
57 
58     <!-- when single edit field, simplifies edit case -->
59     <EditField column="data1" title="@string/field_family_name" android:inputType="textCapWords|textPhonetic" />
60     <EditField column="data2" title="@string/field_given_name" android:minLines="2" />
61     <EditField column="data3" title="@string/field_suffix" />
62 
63 </DataKind>
64 
65 */
66 
67 /**
68  * Internal structure that represents constraints and styles for a specific data
69  * source, such as the various data types they support, including details on how
70  * those types should be rendered and edited.
71  * <p>
72  * In the future this may be inflated from XML defined by a data source.
73  */
74 public class ExternalSource extends FallbackSource {
75     private static final String ACTION_SYNC_ADAPTER = "android.content.SyncAdapter";
76     private static final String METADATA_CONTACTS = "android.provider.CONTACTS_STRUCTURE";
77 
78     private interface InflateTags {
79         final String CONTACTS_SOURCE = "ContactsSource";
80         final String CONTACTS_DATA_KIND = "ContactsDataKind";
81     }
82 
ExternalSource(String resPackageName)83     public ExternalSource(String resPackageName) {
84         this.resPackageName = resPackageName;
85         this.summaryResPackageName = resPackageName;
86     }
87 
88     /**
89      * Ensure that the constraint rules behind this {@link ContactsSource} have
90      * been inflated. Because this may involve parsing meta-data from
91      * {@link PackageManager}, it shouldn't be called from a UI thread.
92      */
93     @Override
inflate(Context context, int inflateLevel)94     public void inflate(Context context, int inflateLevel) {
95         // Handle unknown sources by searching their package
96         final PackageManager pm = context.getPackageManager();
97         final Intent syncAdapter = new Intent(ACTION_SYNC_ADAPTER);
98         final List<ResolveInfo> matches = pm.queryIntentServices(syncAdapter,
99                 PackageManager.GET_META_DATA);
100         for (ResolveInfo info : matches) {
101             final XmlResourceParser parser = info.serviceInfo.loadXmlMetaData(pm,
102                     METADATA_CONTACTS);
103             if (parser == null) continue;
104             inflate(context, parser);
105         }
106 
107         // Bring in name and photo from fallback source, which are non-optional
108         inflateStructuredName(context, inflateLevel);
109         inflatePhoto(context, inflateLevel);
110 
111         setInflatedLevel(inflateLevel);
112     }
113 
114     /**
115      * Inflate this {@link ContactsSource} from the given parser. This may only
116      * load details matching the publicly-defined schema.
117      */
inflate(Context context, XmlPullParser parser)118     protected void inflate(Context context, XmlPullParser parser) {
119         final AttributeSet attrs = Xml.asAttributeSet(parser);
120 
121         try {
122             int type;
123             while ((type = parser.next()) != XmlPullParser.START_TAG
124                     && type != XmlPullParser.END_DOCUMENT) {
125                 // Drain comments and whitespace
126             }
127 
128             if (type != XmlPullParser.START_TAG) {
129                 throw new IllegalStateException("No start tag found");
130             }
131 
132             if (!InflateTags.CONTACTS_SOURCE.equals(parser.getName())) {
133                 throw new IllegalStateException("Top level element must be "
134                         + InflateTags.CONTACTS_SOURCE);
135             }
136 
137             // Parse all children kinds
138             final int depth = parser.getDepth();
139             while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
140                     && type != XmlPullParser.END_DOCUMENT) {
141                 if (type == XmlPullParser.END_TAG
142                         || !InflateTags.CONTACTS_DATA_KIND.equals(parser.getName())) {
143                     continue;
144                 }
145 
146                 final TypedArray a = context.obtainStyledAttributes(attrs,
147                         android.R.styleable.ContactsDataKind);
148                 final DataKind kind = new DataKind();
149 
150                 kind.mimeType = a
151                         .getString(com.android.internal.R.styleable.ContactsDataKind_mimeType);
152                 kind.iconRes = a.getResourceId(
153                         com.android.internal.R.styleable.ContactsDataKind_icon, -1);
154 
155                 final String summaryColumn = a
156                         .getString(com.android.internal.R.styleable.ContactsDataKind_summaryColumn);
157                 if (summaryColumn != null) {
158                     // Inflate a specific column as summary when requested
159                     kind.actionHeader = new FallbackSource.SimpleInflater(summaryColumn);
160                 }
161 
162                 final String detailColumn = a
163                         .getString(com.android.internal.R.styleable.ContactsDataKind_detailColumn);
164                 final boolean detailSocialSummary = a.getBoolean(
165                         com.android.internal.R.styleable.ContactsDataKind_detailSocialSummary,
166                         false);
167 
168                 if (detailSocialSummary) {
169                     // Inflate social summary when requested
170                     kind.actionBodySocial = true;
171                 }
172 
173                 if (detailColumn != null) {
174                     // Inflate specific column as summary
175                     kind.actionBody = new FallbackSource.SimpleInflater(detailColumn);
176                 }
177 
178                 addKind(kind);
179             }
180         } catch (XmlPullParserException e) {
181             throw new IllegalStateException("Problem reading XML", e);
182         } catch (IOException e) {
183             throw new IllegalStateException("Problem reading XML", e);
184         }
185     }
186 
187     @Override
getHeaderColor(Context context)188     public int getHeaderColor(Context context) {
189         return 0xff6d86b4;
190     }
191 
192     @Override
getSideBarColor(Context context)193     public int getSideBarColor(Context context) {
194         return 0xff6d86b4;
195     }
196 }
197