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