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
17package android.provider;
18
19import static org.junit.Assert.assertEquals;
20import static org.junit.Assert.assertNotNull;
21import static org.junit.Assert.assertNotSame;
22import static org.junit.Assert.assertNull;
23import static org.junit.Assert.assertSame;
24
25import android.app.Instrumentation;
26import android.content.Context;
27import android.content.pm.PackageInfo;
28import android.content.pm.PackageManager.NameNotFoundException;
29import android.content.pm.PackageManager;
30import android.content.pm.Signature;
31import android.graphics.Typeface;
32import android.os.Handler;
33import android.provider.FontsContract.Columns;
34import android.provider.FontsContract.FontFamilyResult;
35import android.provider.FontsContract.FontInfo;
36import android.provider.FontsContract;
37import android.support.test.InstrumentationRegistry;
38import android.support.test.filters.SmallTest;
39import android.support.test.runner.AndroidJUnit4;
40import java.util.ArrayList;
41import java.util.List;
42import org.junit.After;
43import org.junit.Before;
44import org.junit.Test;
45import org.junit.runner.RunWith;
46
47@SmallTest
48@RunWith(AndroidJUnit4.class)
49public class FontsContractE2ETest {
50    private static final String AUTHORITY = "android.provider.fonts.font";
51    private static final String PACKAGE = "com.android.frameworks.coretests";
52
53    // Signature to be used for authentication to access content provider.
54    // In this test case, the content provider and consumer live in the same package, self package's
55    // signature works.
56    private static List<List<byte[]>> SIGNATURE;
57    static {
58        final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
59        try {
60            PackageManager manager = context.getPackageManager();
61            PackageInfo info = manager.getPackageInfo(
62                    context.getPackageName(), PackageManager.GET_SIGNATURES);
63            ArrayList<byte[]> out = new ArrayList<>();
64            for (Signature sig : info.signatures) {
65                out.add(sig.toByteArray());
66            }
67            SIGNATURE = new ArrayList<>();
68            SIGNATURE.add(out);
69        } catch (PackageManager.NameNotFoundException e) {
70            throw new RuntimeException(e);
71        }
72    }
73
74    @Before
75    public void setUp() {
76        MockFontProvider.prepareFontFiles(
77                InstrumentationRegistry.getInstrumentation().getTargetContext());
78    }
79
80    @After
81    public void tearDown() {
82        MockFontProvider.cleanUpFontFiles(
83                InstrumentationRegistry.getInstrumentation().getTargetContext());
84    }
85
86    private static class TestCallback extends FontsContract.FontRequestCallback {
87        private Typeface mTypeface;
88
89        private int mSuccessCallCount;
90        private int mFailedCallCount;
91
92        public void onTypefaceRetrieved(Typeface typeface) {
93            mTypeface = typeface;
94            mSuccessCallCount++;
95        }
96
97        public void onTypefaceRequestFailed(int reason) {
98            mFailedCallCount++;
99        }
100
101        public Typeface getTypeface() {
102            return mTypeface;
103        }
104
105        public int getSuccessCallCount() {
106            return mSuccessCallCount;
107        }
108
109        public int getFailedCallCount() {
110            return mFailedCallCount;
111        }
112    }
113
114    @Test
115    public void typefaceCacheTest() throws NameNotFoundException {
116        Instrumentation inst = InstrumentationRegistry.getInstrumentation();
117        Context ctx = inst.getTargetContext();
118
119        final TestCallback callback = new TestCallback();
120        inst.runOnMainSync(() -> {
121            FontRequest request = new FontRequest(
122                    AUTHORITY, PACKAGE, "singleFontFamily", SIGNATURE);
123            FontsContract.requestFonts(ctx, request, new Handler(), null, callback);
124        });
125        inst.waitForIdleSync();
126        assertEquals(1, callback.getSuccessCallCount());
127        assertEquals(0, callback.getFailedCallCount());
128        assertNotNull(callback.getTypeface());
129
130        final TestCallback callback2 = new TestCallback();
131        inst.runOnMainSync(() -> {
132            FontRequest request = new FontRequest(
133                    AUTHORITY, PACKAGE, "singleFontFamily", SIGNATURE);
134            FontsContract.requestFonts(ctx, request, new Handler(), null, callback2);
135        });
136        inst.waitForIdleSync();
137        assertEquals(1, callback2.getSuccessCallCount());
138        assertEquals(0, callback2.getFailedCallCount());
139        assertSame(callback.getTypeface(), callback2.getTypeface());
140
141        final TestCallback callback3 = new TestCallback();
142        inst.runOnMainSync(() -> {
143            FontRequest request = new FontRequest(
144                    AUTHORITY, PACKAGE, "singleFontFamily2", SIGNATURE);
145            FontsContract.requestFonts(ctx, request, new Handler(), null, callback3);
146        });
147        inst.waitForIdleSync();
148        assertEquals(1, callback3.getSuccessCallCount());
149        assertEquals(0, callback3.getFailedCallCount());
150        assertNotSame(callback.getTypeface(), callback3.getTypeface());
151    }
152
153    @Test
154    public void typefaceNotCacheTest() throws NameNotFoundException {
155        Instrumentation inst = InstrumentationRegistry.getInstrumentation();
156        Context ctx = inst.getTargetContext();
157
158        FontRequest request = new FontRequest(
159                AUTHORITY, PACKAGE, "singleFontFamily", SIGNATURE);
160        FontFamilyResult result = FontsContract.fetchFonts(
161                ctx, null /* cancellation signal */, request);
162        assertEquals(FontFamilyResult.STATUS_OK, result.getStatusCode());
163        Typeface typeface = FontsContract.buildTypeface(
164                ctx, null /* cancellation signal */, result.getFonts());
165
166        FontFamilyResult result2 = FontsContract.fetchFonts(
167                ctx, null /* cancellation signal */, request);
168        assertEquals(FontFamilyResult.STATUS_OK, result2.getStatusCode());
169        Typeface typeface2 = FontsContract.buildTypeface(
170                ctx, null /* cancellation signal */, result2.getFonts());
171
172        // Neighter fetchFonts nor buildTypeface should cache the Typeface.
173        assertNotSame(typeface, typeface2);
174    }
175
176    @Test
177    public void typefaceNullFdTest() throws NameNotFoundException {
178        Instrumentation inst = InstrumentationRegistry.getInstrumentation();
179        Context ctx = inst.getTargetContext();
180
181        FontRequest request = new FontRequest(
182                AUTHORITY, PACKAGE, MockFontProvider.NULL_FD_QUERY, SIGNATURE);
183        FontFamilyResult result = FontsContract.fetchFonts(
184                ctx, null /* cancellation signal */, request);
185        assertNull(FontsContract.buildTypeface(
186                ctx, null /* cancellation signal */, result.getFonts()));
187    }
188
189    @Test
190    public void getFontSyncTest() {
191        FontRequest request = new FontRequest(AUTHORITY, PACKAGE, "singleFontFamily", SIGNATURE);
192        assertNotNull(FontsContract.getFontSync(request));
193    }
194
195    @Test
196    public void getFontSyncTest_timeout() {
197        FontRequest request = new FontRequest(
198                AUTHORITY, PACKAGE, MockFontProvider.BLOCKING_QUERY, SIGNATURE);
199        assertNull(FontsContract.getFontSync(request));
200        MockFontProvider.unblock();
201    }
202}
203