108df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka/*
208df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka * Copyright (C) 2017 The Android Open Source Project
308df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka *
408df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka * Licensed under the Apache License, Version 2.0 (the "License");
508df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka * you may not use this file except in compliance with the License.
608df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka * You may obtain a copy of the License at
708df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka *
808df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka *      http://www.apache.org/licenses/LICENSE-2.0
908df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka *
1008df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka * Unless required by applicable law or agreed to in writing, software
1108df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka * distributed under the License is distributed on an "AS IS" BASIS,
1208df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1308df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka * See the License for the specific language governing permissions and
1408df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka * limitations under the License.
1508df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka */
1608df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka
17ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.core.graphics;
1808df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka
19ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
2008df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka
2108df2afeec46f363ef5f17146750bdf011412e56Seigo Nonakaimport android.content.ContentResolver;
2208df2afeec46f363ef5f17146750bdf011412e56Seigo Nonakaimport android.content.Context;
2308df2afeec46f363ef5f17146750bdf011412e56Seigo Nonakaimport android.graphics.Typeface;
2408df2afeec46f363ef5f17146750bdf011412e56Seigo Nonakaimport android.os.CancellationSignal;
2508df2afeec46f363ef5f17146750bdf011412e56Seigo Nonakaimport android.os.ParcelFileDescriptor;
269dede51868bbbe16aadcd65e04860bea8ea50e05Aurimas Liutikasimport android.system.ErrnoException;
279dede51868bbbe16aadcd65e04860bea8ea50e05Aurimas Liutikasimport android.system.Os;
289dede51868bbbe16aadcd65e04860bea8ea50e05Aurimas Liutikasimport android.system.OsConstants;
299dede51868bbbe16aadcd65e04860bea8ea50e05Aurimas Liutikas
30ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.NonNull;
31ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.RequiresApi;
32ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.RestrictTo;
33ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.core.provider.FontsContractCompat.FontInfo;
3408df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka
3508df2afeec46f363ef5f17146750bdf011412e56Seigo Nonakaimport java.io.File;
3608df2afeec46f363ef5f17146750bdf011412e56Seigo Nonakaimport java.io.FileInputStream;
3708df2afeec46f363ef5f17146750bdf011412e56Seigo Nonakaimport java.io.IOException;
3808df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka
3908df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka
4008df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka/**
4108df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka * Implementation of the Typeface compat methods for API 21 and above.
4208df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka * @hide
4308df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka */
4408df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka@RestrictTo(LIBRARY_GROUP)
4508df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka@RequiresApi(21)
4608df2afeec46f363ef5f17146750bdf011412e56Seigo Nonakaclass TypefaceCompatApi21Impl extends TypefaceCompatBaseImpl {
4708df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka    private static final String TAG = "TypefaceCompatApi21Impl";
4808df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka
4908df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka    private File getFile(ParcelFileDescriptor fd) {
5008df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka        try {
5108df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka            final String path = Os.readlink("/proc/self/fd/" + fd.getFd());
5208df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka            // Check if the symbolic link points the regular file.
5308df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka            if (OsConstants.S_ISREG(Os.stat(path).st_mode)) {
5408df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka                return new File(path);
5508df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka            } else {
5608df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka                return null;
5708df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka            }
5808df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka        } catch (ErrnoException e) {
5908df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka            return null;  // Mostly permission error.
6008df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka        }
6108df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka    }
6208df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka
6308df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka    @Override
6408df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka    public Typeface createFromFontInfo(Context context, CancellationSignal cancellationSignal,
6508df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka            @NonNull FontInfo[] fonts, int style) {
6608df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka        if (fonts.length < 1) {
6708df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka            return null;
6808df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka        }
6908df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka        final FontInfo bestFont = findBestInfo(fonts, style);
7008df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka        final ContentResolver resolver = context.getContentResolver();
7108df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka        try (ParcelFileDescriptor pfd =
7208df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka                     resolver.openFileDescriptor(bestFont.getUri(), "r", cancellationSignal)) {
7308df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka            final File file = getFile(pfd);
7408df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka            if (file == null || !file.canRead()) {
7508df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka                // Unable to use the real file for creating Typeface. Fallback to copying
7608df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka                // implementation.
7708df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka                try (FileInputStream fis = new FileInputStream(pfd.getFileDescriptor())) {
7808df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka                    return super.createFromInputStream(context, fis);
7908df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka                }
8008df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka            }
8108df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka            return Typeface.createFromFile(file);
8208df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka        } catch (IOException e) {
8308df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka            return null;
8408df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka        }
8508df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka    }
8608df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka}
87