• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 package android.content.res;
17 
18 import android.annotation.NonNull;
19 import android.annotation.Nullable;
20 import android.graphics.Typeface;
21 import android.ravenwood.annotation.RavenwoodKeepWholeClass;
22 import android.util.AttributeSet;
23 import android.util.Log;
24 import android.util.Xml;
25 
26 import com.android.internal.R;
27 
28 import org.xmlpull.v1.XmlPullParser;
29 import org.xmlpull.v1.XmlPullParserException;
30 
31 import java.io.IOException;
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.List;
35 
36 /**
37  * Parser for xml type font resources.
38  * @hide
39  */
40 @RavenwoodKeepWholeClass
41 public class FontResourcesParser {
42     private static final String TAG = "FontResourcesParser";
43 
44     // A class represents single entry of font-family in xml file.
45     public interface FamilyResourceEntry {}
46 
47     // A class represents font provider based font-family element in xml file.
48     public static final class ProviderResourceEntry implements FamilyResourceEntry {
49         private final @NonNull String mProviderAuthority;
50         private final @NonNull String mProviderPackage;
51         private final @NonNull String mQuery;
52         private final @Nullable String mSystemFontFamilyName;
53         private final @Nullable List<List<String>> mCerts;
54 
ProviderResourceEntry(@onNull String authority, @NonNull String pkg, @NonNull String query, @Nullable List<List<String>> certs, @Nullable String systemFontFamilyName)55         public ProviderResourceEntry(@NonNull String authority, @NonNull String pkg,
56                 @NonNull String query, @Nullable List<List<String>> certs,
57                 @Nullable String systemFontFamilyName) {
58             mProviderAuthority = authority;
59             mProviderPackage = pkg;
60             mQuery = query;
61             mCerts = certs;
62             mSystemFontFamilyName = systemFontFamilyName;
63         }
64 
getAuthority()65         public @NonNull String getAuthority() {
66             return mProviderAuthority;
67         }
68 
getPackage()69         public @NonNull String getPackage() {
70             return mProviderPackage;
71         }
72 
getQuery()73         public @NonNull String getQuery() {
74             return mQuery;
75         }
76 
getSystemFontFamilyName()77         public @NonNull String getSystemFontFamilyName() {
78             return mSystemFontFamilyName;
79         }
80 
getCerts()81         public @Nullable List<List<String>> getCerts() {
82             return mCerts;
83         }
84     }
85 
86     // A class represents font element in xml file which points a file in resource.
87     public static final class FontFileResourceEntry {
88         public static final int RESOLVE_BY_FONT_TABLE = Typeface.RESOLVE_BY_FONT_TABLE;
89         public static final int UPRIGHT = 0;
90         public static final int ITALIC = 1;
91 
92         private final @NonNull String mFileName;
93         private int mWeight;
94         private int mItalic;
95         private int mTtcIndex;
96         private String mVariationSettings;
97         private int mResourceId;
98 
FontFileResourceEntry(@onNull String fileName, int weight, int italic, @Nullable String variationSettings, int ttcIndex)99         public FontFileResourceEntry(@NonNull String fileName, int weight, int italic,
100                 @Nullable String variationSettings, int ttcIndex) {
101             mFileName = fileName;
102             mWeight = weight;
103             mItalic = italic;
104             mVariationSettings = variationSettings;
105             mTtcIndex = ttcIndex;
106         }
107 
getFileName()108         public @NonNull String getFileName() {
109             return mFileName;
110         }
111 
getWeight()112         public int getWeight() {
113             return mWeight;
114         }
115 
getItalic()116         public int getItalic() {
117             return mItalic;
118         }
119 
getVariationSettings()120         public @Nullable String getVariationSettings() {
121             return mVariationSettings;
122         }
123 
getTtcIndex()124         public int getTtcIndex() {
125             return mTtcIndex;
126         }
127     }
128 
129     // A class represents file based font-family element in xml file.
130     public static final class FontFamilyFilesResourceEntry implements FamilyResourceEntry {
131         private final @NonNull FontFileResourceEntry[] mEntries;
132 
FontFamilyFilesResourceEntry(@onNull FontFileResourceEntry[] entries)133         public FontFamilyFilesResourceEntry(@NonNull FontFileResourceEntry[] entries) {
134             mEntries = entries;
135         }
136 
getEntries()137         public @NonNull FontFileResourceEntry[] getEntries() {
138             return mEntries;
139         }
140     }
141 
parse(XmlPullParser parser, Resources resources)142     public static @Nullable FamilyResourceEntry parse(XmlPullParser parser, Resources resources)
143             throws XmlPullParserException, IOException {
144         int type;
145         while ((type=parser.next()) != XmlPullParser.START_TAG
146                 && type != XmlPullParser.END_DOCUMENT) {
147             // Empty loop.
148         }
149 
150         if (type != XmlPullParser.START_TAG) {
151             throw new XmlPullParserException("No start tag found");
152         }
153         return readFamilies(parser, resources);
154     }
155 
readFamilies(XmlPullParser parser, Resources resources)156     private static @Nullable FamilyResourceEntry readFamilies(XmlPullParser parser,
157             Resources resources) throws XmlPullParserException, IOException {
158         parser.require(XmlPullParser.START_TAG, null, "font-family");
159         String tag = parser.getName();
160         FamilyResourceEntry result = null;
161         if (tag.equals("font-family")) {
162             return readFamily(parser, resources);
163         } else {
164             skip(parser);
165             Log.e(TAG, "Failed to find font-family tag");
166             return null;
167         }
168     }
169 
readFamily(XmlPullParser parser, Resources resources)170     private static @Nullable FamilyResourceEntry readFamily(XmlPullParser parser,
171             Resources resources) throws XmlPullParserException, IOException {
172         AttributeSet attrs = Xml.asAttributeSet(parser);
173         TypedArray array = resources.obtainAttributes(attrs, R.styleable.FontFamily);
174         String authority = array.getString(R.styleable.FontFamily_fontProviderAuthority);
175         String providerPackage = array.getString(R.styleable.FontFamily_fontProviderPackage);
176         String query = array.getString(R.styleable.FontFamily_fontProviderQuery);
177         int certsId = array.getResourceId(R.styleable.FontFamily_fontProviderCerts, 0);
178         String systemFontFamilyName = array.getString(
179                 R.styleable.FontFamily_fontProviderSystemFontFamily);
180         array.recycle();
181         if (authority != null && providerPackage != null && query != null) {
182             while (parser.next() != XmlPullParser.END_TAG) {
183                 skip(parser);
184             }
185             List<List<String>> certs = null;
186             if (certsId != 0) {
187                 TypedArray typedArray = resources.obtainTypedArray(certsId);
188                 if (typedArray.length() > 0) {
189                     certs = new ArrayList<>();
190                     boolean isArrayOfArrays = typedArray.getResourceId(0, 0) != 0;
191                     if (isArrayOfArrays) {
192                         for (int i = 0; i < typedArray.length(); i++) {
193                             int certId = typedArray.getResourceId(i, 0);
194                             String[] certsArray = resources.getStringArray(certId);
195                             List<String> certsList = Arrays.asList(certsArray);
196                             certs.add(certsList);
197                         }
198                     } else {
199                         String[] certsArray = resources.getStringArray(certsId);
200                         List<String> certsList = Arrays.asList(certsArray);
201                         certs.add(certsList);
202                     }
203                 }
204                 typedArray.recycle();
205             }
206             return new ProviderResourceEntry(
207                     authority,
208                     providerPackage,
209                     query,
210                     certs,
211                     systemFontFamilyName
212             );
213         }
214         List<FontFileResourceEntry> fonts = new ArrayList<>();
215         while (parser.next() != XmlPullParser.END_TAG) {
216             if (parser.getEventType() != XmlPullParser.START_TAG) continue;
217             String tag = parser.getName();
218             if (tag.equals("font")) {
219                 final FontFileResourceEntry entry = readFont(parser, resources);
220                 if (entry != null) {
221                     fonts.add(entry);
222                 }
223             } else {
224                 skip(parser);
225             }
226         }
227         if (fonts.isEmpty()) {
228             return null;
229         }
230         return new FontFamilyFilesResourceEntry(fonts.toArray(
231                 new FontFileResourceEntry[fonts.size()]));
232     }
233 
readFont(XmlPullParser parser, Resources resources)234     private static FontFileResourceEntry readFont(XmlPullParser parser, Resources resources)
235             throws XmlPullParserException, IOException {
236         AttributeSet attrs = Xml.asAttributeSet(parser);
237         TypedArray array = resources.obtainAttributes(attrs, R.styleable.FontFamilyFont);
238         int weight = array.getInt(R.styleable.FontFamilyFont_fontWeight,
239                 Typeface.RESOLVE_BY_FONT_TABLE);
240         int italic = array.getInt(R.styleable.FontFamilyFont_fontStyle,
241                 FontFileResourceEntry.RESOLVE_BY_FONT_TABLE);
242         String variationSettings = array.getString(
243                 R.styleable.FontFamilyFont_fontVariationSettings);
244         int ttcIndex = array.getInt(R.styleable.FontFamilyFont_ttcIndex, 0);
245         String filename = array.getString(R.styleable.FontFamilyFont_font);
246         array.recycle();
247         while (parser.next() != XmlPullParser.END_TAG) {
248             skip(parser);
249         }
250         if (filename == null) {
251             return null;
252         }
253         return new FontFileResourceEntry(filename, weight, italic, variationSettings, ttcIndex);
254     }
255 
skip(XmlPullParser parser)256     private static void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
257         int depth = 1;
258         while (depth > 0) {
259             switch (parser.next()) {
260                 case XmlPullParser.START_TAG:
261                     depth++;
262                     break;
263                 case XmlPullParser.END_TAG:
264                     depth--;
265                     break;
266             }
267         }
268     }
269 }
270