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 androidx.core.graphics; 18 19import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP; 20 21import android.content.Context; 22import android.content.res.Resources; 23import android.graphics.Typeface; 24import android.os.Build; 25import android.os.CancellationSignal; 26import android.os.Handler; 27 28import androidx.annotation.NonNull; 29import androidx.annotation.Nullable; 30import androidx.annotation.RestrictTo; 31import androidx.collection.LruCache; 32import androidx.core.content.res.FontResourcesParserCompat; 33import androidx.core.content.res.FontResourcesParserCompat.FamilyResourceEntry; 34import androidx.core.content.res.FontResourcesParserCompat.FontFamilyFilesResourceEntry; 35import androidx.core.content.res.FontResourcesParserCompat.ProviderResourceEntry; 36import androidx.core.content.res.ResourcesCompat; 37import androidx.core.os.BuildCompat; 38import androidx.core.provider.FontsContractCompat; 39import androidx.core.provider.FontsContractCompat.FontInfo; 40/** 41 * Helper for accessing features in {@link Typeface}. 42 * @hide 43 */ 44@RestrictTo(LIBRARY_GROUP) 45public class TypefaceCompat { 46 private static final String TAG = "TypefaceCompat"; 47 48 private static final TypefaceCompatBaseImpl sTypefaceCompatImpl; 49 static { 50 if (BuildCompat.isAtLeastP()) { 51 sTypefaceCompatImpl = new TypefaceCompatApi28Impl(); 52 } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 53 sTypefaceCompatImpl = new TypefaceCompatApi26Impl(); 54 } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N 55 && TypefaceCompatApi24Impl.isUsable()) { 56 sTypefaceCompatImpl = new TypefaceCompatApi24Impl(); 57 } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 58 sTypefaceCompatImpl = new TypefaceCompatApi21Impl(); 59 } else { 60 sTypefaceCompatImpl = new TypefaceCompatBaseImpl(); 61 } 62 } 63 64 /** 65 * Cache for Typeface objects dynamically loaded from assets. 66 */ 67 private static final LruCache<String, Typeface> sTypefaceCache = new LruCache<>(16); 68 69 private TypefaceCompat() {} 70 71 /** 72 * Find from internal cache. 73 * 74 * @return null if not found. 75 */ 76 @Nullable 77 public static Typeface findFromCache(@NonNull Resources resources, int id, int style) { 78 return sTypefaceCache.get(createResourceUid(resources, id, style)); 79 } 80 81 /** 82 * Create a unique id for a given Resource and id. 83 * 84 * @param resources Resources instance 85 * @param id a resource id 86 * @param style style to be used for this resource, -1 if not available. 87 * @return Unique id for a given resource and id. 88 */ 89 private static String createResourceUid(final Resources resources, int id, int style) { 90 return resources.getResourcePackageName(id) + "-" + id + "-" + style; 91 } 92 93 /** 94 * Create Typeface from XML resource which root node is font-family. 95 * 96 * @return null if failed to create. 97 */ 98 @Nullable 99 public static Typeface createFromResourcesFamilyXml( 100 @NonNull Context context, @NonNull FamilyResourceEntry entry, 101 @NonNull Resources resources, int id, int style, 102 @Nullable ResourcesCompat.FontCallback fontCallback, @Nullable Handler handler, 103 boolean isRequestFromLayoutInflator) { 104 Typeface typeface; 105 if (entry instanceof ProviderResourceEntry) { 106 ProviderResourceEntry providerEntry = (ProviderResourceEntry) entry; 107 final boolean isBlocking = isRequestFromLayoutInflator 108 ? providerEntry.getFetchStrategy() 109 == FontResourcesParserCompat.FETCH_STRATEGY_BLOCKING 110 : fontCallback == null; 111 final int timeout = isRequestFromLayoutInflator ? providerEntry.getTimeout() 112 : FontResourcesParserCompat.INFINITE_TIMEOUT_VALUE; 113 typeface = FontsContractCompat.getFontSync(context, providerEntry.getRequest(), 114 fontCallback, handler, isBlocking, timeout, style); 115 } else { 116 typeface = sTypefaceCompatImpl.createFromFontFamilyFilesResourceEntry( 117 context, (FontFamilyFilesResourceEntry) entry, resources, style); 118 if (fontCallback != null) { 119 if (typeface != null) { 120 fontCallback.callbackSuccessAsync(typeface, handler); 121 } else { 122 fontCallback.callbackFailAsync( 123 FontsContractCompat.FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR, 124 handler); 125 } 126 } 127 } 128 if (typeface != null) { 129 sTypefaceCache.put(createResourceUid(resources, id, style), typeface); 130 } 131 return typeface; 132 } 133 134 /** 135 * Used by Resources to load a font resource of type font file. 136 */ 137 @Nullable 138 public static Typeface createFromResourcesFontFile( 139 @NonNull Context context, @NonNull Resources resources, int id, String path, 140 int style) { 141 Typeface typeface = sTypefaceCompatImpl.createFromResourcesFontFile( 142 context, resources, id, path, style); 143 if (typeface != null) { 144 final String resourceUid = createResourceUid(resources, id, style); 145 sTypefaceCache.put(resourceUid, typeface); 146 } 147 return typeface; 148 } 149 150 /** 151 * Create a Typeface from a given FontInfo list and a map that matches them to ByteBuffers. 152 */ 153 @Nullable 154 public static Typeface createFromFontInfo(@NonNull Context context, 155 @Nullable CancellationSignal cancellationSignal, @NonNull FontInfo[] fonts, int style) { 156 return sTypefaceCompatImpl.createFromFontInfo(context, cancellationSignal, fonts, style); 157 } 158} 159