• 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 
17 package android.provider.cts;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertNotNull;
22 import static org.junit.Assert.assertNull;
23 import static org.junit.Assert.assertTrue;
24 
25 import android.app.Instrumentation;
26 import android.content.Context;
27 import android.content.pm.PackageInfo;
28 import android.content.pm.PackageManager;
29 import android.content.pm.PackageManager.NameNotFoundException;
30 import android.content.pm.Signature;
31 import android.graphics.Typeface;
32 import android.os.Handler;
33 import android.os.Looper;
34 import android.provider.FontRequest;
35 import android.provider.FontsContract;
36 import android.provider.FontsContract.Columns;
37 import android.provider.FontsContract.FontFamilyResult;
38 import android.provider.FontsContract.FontInfo;
39 
40 import androidx.test.InstrumentationRegistry;
41 import androidx.test.filters.SmallTest;
42 import androidx.test.runner.AndroidJUnit4;
43 
44 import org.junit.After;
45 import org.junit.Before;
46 import org.junit.Test;
47 import org.junit.runner.RunWith;
48 
49 import java.util.ArrayList;
50 import java.util.List;
51 
52 @SmallTest
53 @RunWith(AndroidJUnit4.class)
54 public class FontsContractTest {
55     private static final String AUTHORITY = "android.provider.fonts.cts.font";
56     private static final String PACKAGE = "android.provider.cts";
57 
58     // Signature to be used for authentication to access content provider.
59     // In this test case, the content provider and consumer live in the same package, self package's
60     // signature works.
61     private static List<List<byte[]>> SIGNATURE;
62     static {
63         final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
64         try {
65             PackageManager manager = context.getPackageManager();
66             PackageInfo info = manager.getPackageInfo(
67                     context.getPackageName(), PackageManager.GET_SIGNATURES);
68             ArrayList<byte[]> out = new ArrayList<>();
69             for (Signature sig : info.signatures) {
sig.toByteArray()70                 out.add(sig.toByteArray());
71             }
72             SIGNATURE = new ArrayList<>();
73             SIGNATURE.add(out);
74         } catch (PackageManager.NameNotFoundException e) {
75             throw new RuntimeException(e);
76         }
77     }
78 
79     private Instrumentation mInstrumentation;
80     private Context mContext;
81     private Handler mMainThreadHandler;
82 
83     @Before
setUp()84     public void setUp() throws Exception {
85         mMainThreadHandler = new Handler(Looper.getMainLooper());
86         mInstrumentation = InstrumentationRegistry.getInstrumentation();
87         mContext = mInstrumentation.getTargetContext();
88         MockFontProvider.prepareFontFiles(
89                 InstrumentationRegistry.getInstrumentation().getTargetContext());
90     }
91 
92     @After
tearDown()93     public void tearDown() {
94         mMainThreadHandler = null;
95         MockFontProvider.cleanUpFontFiles(
96                 InstrumentationRegistry.getInstrumentation().getTargetContext());
97     }
98 
99     private static class TestCallback extends FontsContract.FontRequestCallback {
100         private final Object mLock = new Object();
101         // @GuardedBy("mLock")
102         private Typeface mTypeface;
103         // @GuardedBy("mLock")
104         private int mFailedReason;
105         // @GuardedBy("mLock")
106         private int mSuccessCallCount;
107         // @GuardedBy("mLock")
108         private int mFailedCallCount;
109 
onTypefaceRetrieved(Typeface typeface)110         public void onTypefaceRetrieved(Typeface typeface) {
111             synchronized(mLock) {
112                 mTypeface = typeface;
113                 mSuccessCallCount++;
114             }
115         }
116 
onTypefaceRequestFailed(int reason)117         public void onTypefaceRequestFailed(int reason) {
118             synchronized(mLock) {
119                 mFailedCallCount++;
120                 mFailedReason = reason;
121             }
122         }
123 
getTypeface()124         public Typeface getTypeface() {
125             synchronized(mLock) {
126                 return mTypeface;
127             }
128         }
129 
getFailedReason()130         public int getFailedReason() {
131             synchronized(mLock) {
132                 return mFailedReason;
133             }
134         }
135 
getSuccessCallCount()136         public int getSuccessCallCount() {
137             synchronized(mLock) {
138                 return mSuccessCallCount;
139             }
140         }
141 
getFailedCallCount()142         public int getFailedCallCount() {
143             synchronized(mLock) {
144                 return mFailedCallCount;
145             }
146         }
147     }
148 
149 
150     @Test
requestFont()151     public void requestFont() throws NameNotFoundException {
152         FontRequest request = new FontRequest(AUTHORITY, PACKAGE,
153                 MockFontProvider.SINGLE_FONT_FAMILY_QUERY, SIGNATURE);
154         TestCallback callback = new TestCallback();
155 
156         mInstrumentation.runOnMainSync(() -> FontsContract.requestFonts(
157                 mContext, request, mMainThreadHandler, null, callback));
158 
159         mInstrumentation.waitForIdleSync();
160         assertEquals(1, callback.getSuccessCallCount());
161         assertEquals(0, callback.getFailedCallCount());
162         assertNotNull(callback.mTypeface);
163     }
164 
165     @Test
requestFontNegativeErrorCode()166     public void requestFontNegativeErrorCode() throws NameNotFoundException {
167         FontRequest request = new FontRequest(AUTHORITY, PACKAGE,
168                 MockFontProvider.NEGATIVE_ERROR_CODE_QUERY, SIGNATURE);
169         TestCallback callback = new TestCallback();
170 
171         mInstrumentation.runOnMainSync(() -> FontsContract.requestFonts(
172                 mContext, request, mMainThreadHandler, null, callback));
173 
174         mInstrumentation.waitForIdleSync();
175         assertNull(callback.mTypeface);
176         assertEquals(1, callback.getFailedCallCount());
177         assertEquals(0, callback.getSuccessCallCount());
178         assertEquals(FontsContract.FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR,
179                 callback.getFailedReason());
180     }
181 
182     @Test
querySingleFont()183     public void querySingleFont() throws NameNotFoundException {
184         FontRequest request = new FontRequest(AUTHORITY, PACKAGE,
185                 MockFontProvider.SINGLE_FONT_FAMILY_QUERY, SIGNATURE);
186         FontFamilyResult result = FontsContract.fetchFonts(
187                 mContext, null /* cancellation signal */, request);
188         assertNotNull(result);
189         assertEquals(FontFamilyResult.STATUS_OK, result.getStatusCode());
190 
191         FontInfo[] fonts = result.getFonts();
192         assertEquals(1, fonts.length);
193         FontInfo font = fonts[0];
194         assertNotNull(font.getUri());
195         assertEquals(Columns.RESULT_CODE_OK, font.getResultCode());
196         assertNotNull(FontsContract.buildTypeface(mContext, null /* cancellation signal */, fonts));
197     }
198 
199     @Test
queryMultipleFont()200     public void queryMultipleFont() throws NameNotFoundException {
201         FontRequest request = new FontRequest(AUTHORITY, PACKAGE,
202                 MockFontProvider.MULTIPLE_FAMILY_QUERY, SIGNATURE);
203         FontFamilyResult result = FontsContract.fetchFonts(
204                 mContext, null /* cancellation signal */, request);
205         assertNotNull(result);
206         assertEquals(FontFamilyResult.STATUS_OK, result.getStatusCode());
207 
208         FontInfo[] fonts = result.getFonts();
209         assertEquals(4, fonts.length);
210         for (FontInfo font: fonts) {
211             assertNotNull(font.getUri());
212             assertEquals(Columns.RESULT_CODE_OK, font.getResultCode());
213         }
214         assertNotNull(FontsContract.buildTypeface(mContext, null /* cancellation signal */, fonts));
215     }
216 
217     @Test
queryAttributes()218     public void queryAttributes() throws NameNotFoundException {
219         FontRequest request = new FontRequest(AUTHORITY, PACKAGE,
220                 MockFontProvider.ALL_ATTRIBUTE_VALUES_QUERY, SIGNATURE);
221         FontFamilyResult result = FontsContract.fetchFonts(
222                 mContext, null /* cancellation signal */, request);
223         assertNotNull(result);
224         assertEquals(FontFamilyResult.STATUS_OK, result.getStatusCode());
225 
226         FontInfo[] fonts = result.getFonts();
227         assertEquals(2, fonts.length);
228         FontInfo font = fonts[0];
229         assertNotNull(font.getUri());
230         assertEquals(400, font.getWeight());
231         assertEquals(1, font.getAxes().length);
232         assertEquals(0, font.getTtcIndex());
233         assertFalse(font.isItalic());
234         assertEquals(Columns.RESULT_CODE_OK, font.getResultCode());
235 
236         font = fonts[1];
237         assertNotNull(font.getUri());
238         assertEquals(700, font.getWeight());
239         assertEquals(1, font.getAxes().length);
240         assertEquals(1, font.getTtcIndex());
241         assertTrue(font.isItalic());
242         assertEquals(Columns.RESULT_CODE_OK, font.getResultCode());
243 
244         assertNotNull(FontsContract.buildTypeface(mContext, null /* cancellation signal */, fonts));
245     }
246 
247     @Test
queryNotFound()248     public void queryNotFound() throws NameNotFoundException {
249         FontRequest request = new FontRequest(AUTHORITY, PACKAGE,
250                 MockFontProvider.NOT_FOUND_QUERY, SIGNATURE);
251         FontFamilyResult result = FontsContract.fetchFonts(
252                 mContext, null /* cancellation signal */, request);
253         assertNotNull(result);
254         assertEquals(FontFamilyResult.STATUS_OK, result.getStatusCode());
255 
256         FontInfo[] fonts = result.getFonts();
257         assertEquals(1, fonts.length);
258         FontInfo font = fonts[0];
259         assertEquals(Columns.RESULT_CODE_FONT_NOT_FOUND, font.getResultCode());
260         assertNull(FontsContract.buildTypeface(mContext, null /* cancellation signal */, fonts));
261     }
262 
263     @Test
queryUnavailable()264     public void queryUnavailable() throws NameNotFoundException {
265         FontRequest request = new FontRequest(AUTHORITY, PACKAGE,
266                 MockFontProvider.UNAVAILABLE_QUERY, SIGNATURE);
267         FontFamilyResult result = FontsContract.fetchFonts(
268                 mContext, null /* cancellation signal */, request);
269         assertNotNull(result);
270         assertEquals(FontFamilyResult.STATUS_OK, result.getStatusCode());
271 
272         FontInfo[] fonts = result.getFonts();
273         assertEquals(1, fonts.length);
274         FontInfo font = fonts[0];
275         assertEquals(Columns.RESULT_CODE_FONT_UNAVAILABLE, font.getResultCode());
276         assertNull(FontsContract.buildTypeface(mContext, null /* cancellation signal */, fonts));
277     }
278 
279     @Test
queryMalformed()280     public void queryMalformed() throws NameNotFoundException {
281         FontRequest request = new FontRequest(AUTHORITY, PACKAGE,
282                 MockFontProvider.MALFORMED_QUERY, SIGNATURE);
283         FontFamilyResult result = FontsContract.fetchFonts(
284                 mContext, null /* cancellation signal */, request);
285         assertNotNull(result);
286         assertEquals(FontFamilyResult.STATUS_OK, result.getStatusCode());
287 
288         FontInfo[] fonts = result.getFonts();
289         assertEquals(1, fonts.length);
290         FontInfo font = fonts[0];
291         assertEquals(Columns.RESULT_CODE_MALFORMED_QUERY, font.getResultCode());
292         assertNull(FontsContract.buildTypeface(mContext, null /* cancellation signal */, fonts));
293     }
294 
295     @Test
queryMultipleOneNotFound()296     public void queryMultipleOneNotFound() throws NameNotFoundException {
297         FontRequest request = new FontRequest(AUTHORITY, PACKAGE,
298                 MockFontProvider.NOT_FOUND_SECOND_QUERY, SIGNATURE);
299         FontFamilyResult result = FontsContract.fetchFonts(
300                 mContext, null /* cancellation signal */, request);
301         assertNotNull(result);
302         assertEquals(FontFamilyResult.STATUS_OK, result.getStatusCode());
303 
304         FontInfo[] fonts = result.getFonts();
305         assertEquals(2, fonts.length);
306         FontInfo font = fonts[0];
307         assertEquals(Columns.RESULT_CODE_OK, font.getResultCode());
308         FontInfo font2 = fonts[1];
309         assertEquals(Columns.RESULT_CODE_FONT_NOT_FOUND, font2.getResultCode());
310         assertNotNull(FontsContract.buildTypeface(mContext, null /* cancellation signal */, fonts));
311     }
312 
313     @Test
queryMandatoryFieldsOnly()314     public void queryMandatoryFieldsOnly() throws NameNotFoundException {
315         FontRequest request = new FontRequest(AUTHORITY, PACKAGE,
316                 MockFontProvider.MANDATORY_FIELDS_ONLY_QUERY, SIGNATURE);
317         FontFamilyResult result = FontsContract.fetchFonts(
318                 mContext, null /* cancellation signal */, request);
319         assertNotNull(result);
320         assertEquals(FontFamilyResult.STATUS_OK, result.getStatusCode());
321 
322         FontInfo[] fonts = result.getFonts();
323         assertEquals(1, fonts.length);
324         FontInfo font = fonts[0];
325         assertNotNull(font.getUri());
326         assertEquals(400, font.getWeight());
327         assertNull(font.getAxes());
328         assertFalse(font.isItalic());
329         assertEquals(Columns.RESULT_CODE_OK, font.getResultCode());
330         assertNotNull(FontsContract.buildTypeface(mContext, null /* cancellation signal */, fonts));
331     }
332 
333     @Test
restrictContextRejection()334     public void restrictContextRejection() throws NameNotFoundException {
335         Context restrictedContext = mContext.createPackageContext(
336                 PACKAGE, Context.CONTEXT_RESTRICTED);
337 
338         FontRequest request = new FontRequest(AUTHORITY, PACKAGE,
339                 MockFontProvider.SINGLE_FONT_FAMILY_QUERY, SIGNATURE);
340 
341         // Rejected if restricted context is used.
342         FontFamilyResult result = FontsContract.fetchFonts(
343                 restrictedContext, null /* cancellation signal */, request);
344         assertEquals(FontFamilyResult.STATUS_REJECTED, result.getStatusCode());
345 
346         // Even if you have a result, buildTypeface should fail with restricted context.
347         result = FontsContract.fetchFonts(mContext, null /* cancellation signal */, request);
348         assertEquals(FontFamilyResult.STATUS_OK, result.getStatusCode());
349         assertNull(FontsContract.buildTypeface(
350                 restrictedContext, null /* cancellation signal */, result.getFonts()));
351     }
352 }
353