blob: 3c55df624e1c766f78987ec32c7e8db49fa68dfe [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.support.v4.graphics;
import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Typeface;
import android.os.Build;
import android.os.CancellationSignal;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
import android.support.v4.content.res.FontResourcesParserCompat;
import android.support.v4.content.res.FontResourcesParserCompat.FamilyResourceEntry;
import android.support.v4.content.res.FontResourcesParserCompat.FontFamilyFilesResourceEntry;
import android.support.v4.content.res.FontResourcesParserCompat.ProviderResourceEntry;
import android.support.v4.content.res.ResourcesCompat;
import android.support.v4.provider.FontsContractCompat;
import android.support.v4.provider.FontsContractCompat.FontInfo;
import android.support.v4.util.LruCache;
/**
* Helper for accessing features in {@link Typeface}.
* @hide
*/
@RestrictTo(LIBRARY_GROUP)
public class TypefaceCompat {
private static final String TAG = "TypefaceCompat";
private static final TypefaceCompatImpl sTypefaceCompatImpl;
static {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
sTypefaceCompatImpl = new TypefaceCompatApi26Impl();
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
&& TypefaceCompatApi24Impl.isUsable()) {
sTypefaceCompatImpl = new TypefaceCompatApi24Impl();
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
sTypefaceCompatImpl = new TypefaceCompatApi21Impl();
} else {
sTypefaceCompatImpl = new TypefaceCompatBaseImpl();
}
}
/**
* Cache for Typeface objects dynamically loaded from assets.
*/
private static final LruCache<String, Typeface> sTypefaceCache = new LruCache<>(16);
interface TypefaceCompatImpl {
// Create Typeface from XML which root node is "font-family"
Typeface createFromFontFamilyFilesResourceEntry(
Context context, FontFamilyFilesResourceEntry entry, Resources resources,
int style);
Typeface createFromFontInfo(Context context,
@Nullable CancellationSignal cancellationSignal, @NonNull FontInfo[] fonts,
int style);
Typeface createFromResourcesFontFile(
Context context, Resources resources, int id, String path, int style);
}
private TypefaceCompat() {}
/**
* Find from internal cache.
*
* @return null if not found.
*/
@Nullable
public static Typeface findFromCache(@NonNull Resources resources, int id, int style) {
return sTypefaceCache.get(createResourceUid(resources, id, style));
}
/**
* Create a unique id for a given Resource and id.
*
* @param resources Resources instance
* @param id a resource id
* @param style style to be used for this resource, -1 if not available.
* @return Unique id for a given resource and id.
*/
private static String createResourceUid(final Resources resources, int id, int style) {
return resources.getResourcePackageName(id) + "-" + id + "-" + style;
}
/**
* Create Typeface from XML resource which root node is font-family.
*
* @return null if failed to create.
*/
@Nullable
public static Typeface createFromResourcesFamilyXml(
@NonNull Context context, @NonNull FamilyResourceEntry entry,
@NonNull Resources resources, int id, int style,
@Nullable ResourcesCompat.FontCallback fontCallback, @Nullable Handler handler,
boolean isRequestFromLayoutInflator) {
Typeface typeface;
if (entry instanceof ProviderResourceEntry) {
ProviderResourceEntry providerEntry = (ProviderResourceEntry) entry;
final boolean isBlocking = isRequestFromLayoutInflator
? providerEntry.getFetchStrategy()
== FontResourcesParserCompat.FETCH_STRATEGY_BLOCKING
: fontCallback == null;
final int timeout = isRequestFromLayoutInflator ? providerEntry.getTimeout()
: FontResourcesParserCompat.INFINITE_TIMEOUT_VALUE;
typeface = FontsContractCompat.getFontSync(context, providerEntry.getRequest(),
fontCallback, handler, isBlocking, timeout, style);
} else {
typeface = sTypefaceCompatImpl.createFromFontFamilyFilesResourceEntry(
context, (FontFamilyFilesResourceEntry) entry, resources, style);
if (fontCallback != null) {
if (typeface != null) {
fontCallback.callbackSuccessAsync(typeface, handler);
} else {
fontCallback.callbackFailAsync(
FontsContractCompat.FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR,
handler);
}
}
}
if (typeface != null) {
sTypefaceCache.put(createResourceUid(resources, id, style), typeface);
}
return typeface;
}
/**
* Used by Resources to load a font resource of type font file.
*/
@Nullable
public static Typeface createFromResourcesFontFile(
@NonNull Context context, @NonNull Resources resources, int id, String path,
int style) {
Typeface typeface = sTypefaceCompatImpl.createFromResourcesFontFile(
context, resources, id, path, style);
if (typeface != null) {
final String resourceUid = createResourceUid(resources, id, style);
sTypefaceCache.put(resourceUid, typeface);
}
return typeface;
}
/**
* Create a Typeface from a given FontInfo list and a map that matches them to ByteBuffers.
*/
@Nullable
public static Typeface createFromFontInfo(@NonNull Context context,
@Nullable CancellationSignal cancellationSignal, @NonNull FontInfo[] fonts, int style) {
return sTypefaceCompatImpl.createFromFontInfo(context, cancellationSignal, fonts, style);
}
}