12c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka/* 22c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka * Copyright (C) 2017 The Android Open Source Project 32c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka * 42c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka * Licensed under the Apache License, Version 2.0 (the "License"); 52c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka * you may not use this file except in compliance with the License. 62c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka * You may obtain a copy of the License at 72c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka * 82c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka * http://www.apache.org/licenses/LICENSE-2.0 92c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka * 102c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka * Unless required by applicable law or agreed to in writing, software 112c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka * distributed under the License is distributed on an "AS IS" BASIS, 122c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka * See the License for the specific language governing permissions and 142c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka * limitations under the License. 152c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka */ 162c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka 17ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.core.graphics; 182c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka 19ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP; 202c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka 212c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonakaimport android.content.Context; 222c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonakaimport android.content.res.Resources; 232c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonakaimport android.graphics.Typeface; 242c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonakaimport android.net.Uri; 2508df2afeec46f363ef5f17146750bdf011412e56Seigo Nonakaimport android.os.CancellationSignal; 269dede51868bbbe16aadcd65e04860bea8ea50e05Aurimas Liutikasimport android.util.Log; 279dede51868bbbe16aadcd65e04860bea8ea50e05Aurimas Liutikas 28ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.NonNull; 29ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.Nullable; 30ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.RequiresApi; 31ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.RestrictTo; 329dede51868bbbe16aadcd65e04860bea8ea50e05Aurimas Liutikasimport androidx.collection.SimpleArrayMap; 33ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.core.content.res.FontResourcesParserCompat.FontFamilyFilesResourceEntry; 34ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.core.content.res.FontResourcesParserCompat.FontFileResourceEntry; 35ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.core.provider.FontsContractCompat.FontInfo; 362c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka 372c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonakaimport java.lang.reflect.Array; 382c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonakaimport java.lang.reflect.Constructor; 392c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonakaimport java.lang.reflect.InvocationTargetException; 402c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonakaimport java.lang.reflect.Method; 412c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonakaimport java.nio.ByteBuffer; 422c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonakaimport java.util.List; 432c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka 442c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka 452c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka/** 462c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka * Implementation of the Typeface compat methods for API 24 and above. 472c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka * @hide 482c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka */ 492c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka@RestrictTo(LIBRARY_GROUP) 502c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka@RequiresApi(24) 5111e831738feba2bb6c5338358812a373bda9991aClara Bayarriclass TypefaceCompatApi24Impl extends TypefaceCompatBaseImpl { 522c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka private static final String TAG = "TypefaceCompatApi24Impl"; 532c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka 542c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka private static final String FONT_FAMILY_CLASS = "android.graphics.FontFamily"; 552c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka private static final String ADD_FONT_WEIGHT_STYLE_METHOD = "addFontWeightStyle"; 562c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka private static final String CREATE_FROM_FAMILIES_WITH_DEFAULT_METHOD = 572c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka "createFromFamiliesWithDefault"; 582c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka private static final Class sFontFamily; 592c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka private static final Constructor sFontFamilyCtor; 602c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka private static final Method sAddFontWeightStyle; 612c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka private static final Method sCreateFromFamiliesWithDefault; 622c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka 632c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka static { 642c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka Class fontFamilyClass; 652c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka Constructor fontFamilyCtor; 662c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka Method addFontMethod; 672c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka Method createFromFamiliesWithDefaultMethod; 682c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka try { 692c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka fontFamilyClass = Class.forName(FONT_FAMILY_CLASS); 702c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka fontFamilyCtor = fontFamilyClass.getConstructor(); 712c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka addFontMethod = fontFamilyClass.getMethod(ADD_FONT_WEIGHT_STYLE_METHOD, 722c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka ByteBuffer.class, Integer.TYPE, List.class, Integer.TYPE, Boolean.TYPE); 732c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka Object familyArray = Array.newInstance(fontFamilyClass, 1); 742c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka createFromFamiliesWithDefaultMethod = 752c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka Typeface.class.getMethod(CREATE_FROM_FAMILIES_WITH_DEFAULT_METHOD, 762c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka familyArray.getClass()); 772c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka } catch (ClassNotFoundException | NoSuchMethodException e) { 782c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka Log.e(TAG, e.getClass().getName(), e); 792c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka fontFamilyClass = null; 802c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka fontFamilyCtor = null; 812c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka addFontMethod = null; 822c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka createFromFamiliesWithDefaultMethod = null; 832c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka } 842c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka sFontFamilyCtor = fontFamilyCtor; 852c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka sFontFamily = fontFamilyClass; 862c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka sAddFontWeightStyle = addFontMethod; 872c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka sCreateFromFamiliesWithDefault = createFromFamiliesWithDefaultMethod; 882c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka } 892c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka 902c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka /** 912c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka * Returns true if API24 implementation is usable. 922c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka */ 932c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka public static boolean isUsable() { 9411e831738feba2bb6c5338358812a373bda9991aClara Bayarri if (sAddFontWeightStyle == null) { 9511e831738feba2bb6c5338358812a373bda9991aClara Bayarri Log.w(TAG, "Unable to collect necessary private methods." 9611e831738feba2bb6c5338358812a373bda9991aClara Bayarri + "Fallback to legacy implementation."); 9711e831738feba2bb6c5338358812a373bda9991aClara Bayarri } 982c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka return sAddFontWeightStyle != null; 992c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka } 1002c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka 1012c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka private static Object newFamily() { 1022c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka try { 1032c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka return sFontFamilyCtor.newInstance(); 1042c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka } catch (IllegalAccessException | InstantiationException | InvocationTargetException e) { 1052c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka throw new RuntimeException(e); 1062c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka } 1072c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka } 1082c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka 1092c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka private static boolean addFontWeightStyle(Object family, ByteBuffer buffer, int ttcIndex, 1102c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka int weight, boolean style) { 1112c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka try { 1122c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka final Boolean result = (Boolean) sAddFontWeightStyle.invoke( 1132c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka family, buffer, ttcIndex, null /* variation axis */, weight, style); 1142c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka return result.booleanValue(); 1152c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka } catch (IllegalAccessException | InvocationTargetException e) { 1162c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka throw new RuntimeException(e); 1172c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka } 1182c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka } 1192c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka 1202c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka private static Typeface createFromFamiliesWithDefault(Object family) { 1212c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka try { 1222c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka Object familyArray = Array.newInstance(sFontFamily, 1); 1232c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka Array.set(familyArray, 0, family); 1242c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka return (Typeface) sCreateFromFamiliesWithDefault.invoke( 1252c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka null /* static method */, familyArray); 1262c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka } catch (IllegalAccessException | InvocationTargetException e) { 1272c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka throw new RuntimeException(e); 1282c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka } 1292c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka } 1302c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka 1312c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka @Override 13208df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka public Typeface createFromFontInfo(Context context, 13308df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka @Nullable CancellationSignal cancellationSignal, @NonNull FontInfo[] fonts, int style) { 1342c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka Object family = newFamily(); 13508df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka SimpleArrayMap<Uri, ByteBuffer> bufferCache = new SimpleArrayMap<>(); 13608df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka 1372c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka for (final FontInfo font : fonts) { 13808df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka final Uri uri = font.getUri(); 13908df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka ByteBuffer buffer = bufferCache.get(uri); 14008df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka if (buffer == null) { 14108df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka buffer = TypefaceCompatUtil.mmap(context, cancellationSignal, uri); 14208df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka bufferCache.put(uri, buffer); 14308df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka } 14408df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka if (!addFontWeightStyle(family, buffer, font.getTtcIndex(), font.getWeight(), 14508df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka font.isItalic())) { 1462c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka return null; 1472c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka } 1482c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka } 149758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri final Typeface typeface = createFromFamiliesWithDefault(family); 150758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri return Typeface.create(typeface, style); 1512c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka } 1522c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka 1532c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka @Override 1542c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka public Typeface createFromFontFamilyFilesResourceEntry(Context context, 1552c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka FontFamilyFilesResourceEntry entry, Resources resources, int style) { 1562c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka Object family = newFamily(); 1572c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka for (final FontFileResourceEntry e : entry.getEntries()) { 1582c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka final ByteBuffer buffer = 1592c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka TypefaceCompatUtil.copyToDirectBuffer(context, resources, e.getResourceId()); 1602113e0613ddf90a83874ff9f13970899f1553bbbSeigo Nonaka if (buffer == null) { 1612113e0613ddf90a83874ff9f13970899f1553bbbSeigo Nonaka return null; 1622113e0613ddf90a83874ff9f13970899f1553bbbSeigo Nonaka } 163d017d547e411e03ac271ce36600afe2412f35a87Mihai Popa if (!addFontWeightStyle(family, buffer, e.getTtcIndex(), e.getWeight(), e.isItalic())) { 1642c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka return null; 1652c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka } 1662c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka } 1672c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka return createFromFamiliesWithDefault(family); 1682c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka } 1692c4cbf16a9705a4fcb22a8de5cd8795745b01aa4Seigo Nonaka} 170