TypefaceCompatApi21Impl.java

/*
 * 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 androidx.core.graphics;

import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;

import android.content.ContentResolver;
import android.content.Context;
import android.graphics.Typeface;
import android.os.CancellationSignal;
import android.os.ParcelFileDescriptor;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import androidx.core.provider.FontsContractCompat.FontInfo;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;


/**
 * Implementation of the Typeface compat methods for API 21 and above.
 * @hide
 */
@RestrictTo(LIBRARY_GROUP)
@RequiresApi(21)
class TypefaceCompatApi21Impl extends TypefaceCompatBaseImpl {
    private static final String TAG = "TypefaceCompatApi21Impl";

    private File getFile(ParcelFileDescriptor fd) {
        try {
            final String path = Os.readlink("/proc/self/fd/" + fd.getFd());
            // Check if the symbolic link points the regular file.
            if (OsConstants.S_ISREG(Os.stat(path).st_mode)) {
                return new File(path);
            } else {
                return null;
            }
        } catch (ErrnoException e) {
            return null;  // Mostly permission error.
        }
    }

    @Override
    public Typeface createFromFontInfo(Context context, CancellationSignal cancellationSignal,
            @NonNull FontInfo[] fonts, int style) {
        if (fonts.length < 1) {
            return null;
        }
        final FontInfo bestFont = findBestInfo(fonts, style);
        final ContentResolver resolver = context.getContentResolver();
        try (ParcelFileDescriptor pfd =
                     resolver.openFileDescriptor(bestFont.getUri(), "r", cancellationSignal)) {
            final File file = getFile(pfd);
            if (file == null || !file.canRead()) {
                // Unable to use the real file for creating Typeface. Fallback to copying
                // implementation.
                try (FileInputStream fis = new FileInputStream(pfd.getFileDescriptor())) {
                    return super.createFromInputStream(context, fis);
                }
            }
            return Typeface.createFromFile(file);
        } catch (IOException e) {
            return null;
        }
    }
}