10b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka/*
20b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka * Copyright (C) 2017 The Android Open Source Project
30b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka *
40b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka * Licensed under the Apache License, Version 2.0 (the "License");
50b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka * you may not use this file except in compliance with the License.
60b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka * You may obtain a copy of the License at
70b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka *
80b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka *      http://www.apache.org/licenses/LICENSE-2.0
90b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka *
100b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka * Unless required by applicable law or agreed to in writing, software
110b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka * distributed under the License is distributed on an "AS IS" BASIS,
120b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka * See the License for the specific language governing permissions and
140b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka * limitations under the License.
150b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka */
160b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
17ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.core.provider;
180b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
19ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
200b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
21b34c816d06018c63f61ed13d24d8301244800e01Clara Bayarriimport android.annotation.SuppressLint;
220b03693667d95d2202dfbb24866665ff061acce1Seigo Nonakaimport android.content.ContentResolver;
230b03693667d95d2202dfbb24866665ff061acce1Seigo Nonakaimport android.content.ContentUris;
240b03693667d95d2202dfbb24866665ff061acce1Seigo Nonakaimport android.content.Context;
250b03693667d95d2202dfbb24866665ff061acce1Seigo Nonakaimport android.content.pm.PackageInfo;
260b03693667d95d2202dfbb24866665ff061acce1Seigo Nonakaimport android.content.pm.PackageManager;
270b03693667d95d2202dfbb24866665ff061acce1Seigo Nonakaimport android.content.pm.ProviderInfo;
280b03693667d95d2202dfbb24866665ff061acce1Seigo Nonakaimport android.content.pm.Signature;
290b03693667d95d2202dfbb24866665ff061acce1Seigo Nonakaimport android.content.res.Resources;
300b03693667d95d2202dfbb24866665ff061acce1Seigo Nonakaimport android.database.Cursor;
310b03693667d95d2202dfbb24866665ff061acce1Seigo Nonakaimport android.graphics.Typeface;
320b03693667d95d2202dfbb24866665ff061acce1Seigo Nonakaimport android.net.Uri;
330b03693667d95d2202dfbb24866665ff061acce1Seigo Nonakaimport android.os.Build;
340b03693667d95d2202dfbb24866665ff061acce1Seigo Nonakaimport android.os.CancellationSignal;
350b03693667d95d2202dfbb24866665ff061acce1Seigo Nonakaimport android.os.Handler;
360b03693667d95d2202dfbb24866665ff061acce1Seigo Nonakaimport android.os.ParcelFileDescriptor;
37fc857452283b38dfbac9ca023a77a8cf8b8c5599Seigo Nonakaimport android.os.Process;
380b03693667d95d2202dfbb24866665ff061acce1Seigo Nonakaimport android.provider.BaseColumns;
399dede51868bbbe16aadcd65e04860bea8ea50e05Aurimas Liutikas
40ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.GuardedBy;
41ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.IntDef;
42ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.IntRange;
43ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.NonNull;
44ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.Nullable;
45ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.RequiresApi;
46ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.RestrictTo;
47ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.VisibleForTesting;
489dede51868bbbe16aadcd65e04860bea8ea50e05Aurimas Liutikasimport androidx.collection.LruCache;
499dede51868bbbe16aadcd65e04860bea8ea50e05Aurimas Liutikasimport androidx.collection.SimpleArrayMap;
50ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.core.content.res.FontResourcesParserCompat;
51ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.core.content.res.ResourcesCompat;
52ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.core.graphics.TypefaceCompat;
53ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.core.graphics.TypefaceCompatUtil;
54ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.core.provider.SelfDestructiveThread.ReplyCallback;
55ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.core.util.Preconditions;
560b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
570b03693667d95d2202dfbb24866665ff061acce1Seigo Nonakaimport java.lang.annotation.Retention;
580b03693667d95d2202dfbb24866665ff061acce1Seigo Nonakaimport java.lang.annotation.RetentionPolicy;
5911e831738feba2bb6c5338358812a373bda9991aClara Bayarriimport java.nio.ByteBuffer;
600b03693667d95d2202dfbb24866665ff061acce1Seigo Nonakaimport java.util.ArrayList;
610b03693667d95d2202dfbb24866665ff061acce1Seigo Nonakaimport java.util.Arrays;
620b03693667d95d2202dfbb24866665ff061acce1Seigo Nonakaimport java.util.Collections;
630b03693667d95d2202dfbb24866665ff061acce1Seigo Nonakaimport java.util.Comparator;
6411e831738feba2bb6c5338358812a373bda9991aClara Bayarriimport java.util.HashMap;
650b03693667d95d2202dfbb24866665ff061acce1Seigo Nonakaimport java.util.List;
6611e831738feba2bb6c5338358812a373bda9991aClara Bayarriimport java.util.Map;
67fc857452283b38dfbac9ca023a77a8cf8b8c5599Seigo Nonakaimport java.util.concurrent.Callable;
680b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
690b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka/**
700b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka * Utility class to deal with Font ContentProviders.
710b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka */
720b03693667d95d2202dfbb24866665ff061acce1Seigo Nonakapublic class FontsContractCompat {
730b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    private static final String TAG = "FontsContractCompat";
740b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
750b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    private FontsContractCompat() { }
760b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
770b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    /**
780b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     * Defines the constants used in a response from a Font Provider. The cursor returned from the
790b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     * query should have the ID column populated with the content uri ID for the resulting font.
800b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     * This should point to a real file or shared memory, as the client will mmap the given file
810b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     * descriptor. Pipes, sockets and other non-mmap-able file descriptors will fail to load in the
820b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     * client application.
830b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     */
840b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    public static final class Columns implements BaseColumns {
850b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        /**
860b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * Constant used to request data from a font provider. The cursor returned from the query
870b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * may populate this column with a long for the font file ID. The client will request a file
880b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * descriptor to "file/FILE_ID" with this ID immediately under the top-level content URI. If
890b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * not present, the client will request a file descriptor to the top-level URI with the
900b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * given base font ID. Note that several results may return the same file ID, e.g. for TTC
910b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * files with different indices.
920b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         */
930b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public static final String FILE_ID = "file_id";
940b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        /**
950b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * Constant used to request data from a font provider. The cursor returned from the query
960b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * should have this column populated with an int for the ttc index for the resulting font.
970b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         */
980b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public static final String TTC_INDEX = android.provider.FontsContract.Columns.TTC_INDEX;
990b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        /**
1000b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * Constant used to request data from a font provider. The cursor returned from the query
1010b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * may populate this column with the font variation settings String information for the
1020b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * font.
1030b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         */
1040b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public static final String VARIATION_SETTINGS =
1050b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                android.provider.FontsContract.Columns.VARIATION_SETTINGS;
1060b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        /**
1070b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * Constant used to request data from a font provider. The cursor returned from the query
1080b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * should have this column populated with the int weight for the resulting font. This value
1090b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * should be between 100 and 900. The most common values are 400 for regular weight and 700
1100b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * for bold weight.
1110b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         */
1120b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public static final String WEIGHT = android.provider.FontsContract.Columns.WEIGHT;
1130b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        /**
1140b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * Constant used to request data from a font provider. The cursor returned from the query
1150b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * should have this column populated with the int italic for the resulting font. This should
1160b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * be 0 for regular style and 1 for italic.
1170b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         */
1180b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public static final String ITALIC = android.provider.FontsContract.Columns.ITALIC;
1190b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        /**
1200b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * Constant used to request data from a font provider. The cursor returned from the query
1210b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * should have this column populated to indicate the result status of the
1220b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * query. This will be checked before any other data in the cursor. Possible values are
1230b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * {@link #RESULT_CODE_OK}, {@link #RESULT_CODE_FONT_NOT_FOUND},
1240b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * {@link #RESULT_CODE_MALFORMED_QUERY} and {@link #RESULT_CODE_FONT_UNAVAILABLE}. If not
1250b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * present, {@link #RESULT_CODE_OK} will be assumed.
1260b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         */
1270b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public static final String RESULT_CODE = android.provider.FontsContract.Columns.RESULT_CODE;
1280b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
1290b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        /**
1300b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * Constant used to represent a result was retrieved successfully. The given fonts will be
1310b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * attempted to retrieve immediately via
1320b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * {@link android.content.ContentProvider#openFile(Uri, String)}. See {@link #RESULT_CODE}.
1330b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         */
1340b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public static final int RESULT_CODE_OK =
1350b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                android.provider.FontsContract.Columns.RESULT_CODE_OK;
1360b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        /**
1370b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * Constant used to represent a result was not found. See {@link #RESULT_CODE}.
1380b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         */
1390b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public static final int RESULT_CODE_FONT_NOT_FOUND =
1400b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                android.provider.FontsContract.Columns.RESULT_CODE_FONT_NOT_FOUND;
1410b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        /**
1420b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * Constant used to represent a result was found, but cannot be provided at this moment. Use
1430b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * this to indicate, for example, that a font needs to be fetched from the network. See
1440b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * {@link #RESULT_CODE}.
1450b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         */
1460b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public static final int RESULT_CODE_FONT_UNAVAILABLE =
1470b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                android.provider.FontsContract.Columns.RESULT_CODE_FONT_UNAVAILABLE;
1480b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        /**
1490b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * Constant used to represent that the query was not in a supported format by the provider.
1500b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * See {@link #RESULT_CODE}.
1510b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         */
1520b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public static final int RESULT_CODE_MALFORMED_QUERY =
1530b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                android.provider.FontsContract.Columns.RESULT_CODE_MALFORMED_QUERY;
1540b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    }
1550b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
1560b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    /**
1570b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     * Constant used to identify the List of {@link ParcelFileDescriptor} item in the Bundle
1580b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     * returned to the ResultReceiver in getFont.
1590b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     * @hide
1600b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     */
1610b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    @RestrictTo(LIBRARY_GROUP)
1620b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    public static final String PARCEL_FONT_RESULTS = "font_results";
1630b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
1640b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    // Error codes internal to the system, which can not come from a provider. To keep the number
1650b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    // space open for new provider codes, these should all be negative numbers.
1660b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    /** @hide */
1670b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    @RestrictTo(LIBRARY_GROUP)
168758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri    /* package */ static final int RESULT_CODE_PROVIDER_NOT_FOUND = -1;
1690b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    /** @hide */
1700b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    @RestrictTo(LIBRARY_GROUP)
171758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri    /* package */ static final int RESULT_CODE_WRONG_CERTIFICATES = -2;
172758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri    // Note -3 is used by FontRequestCallback to indicate the font failed to load.
1730b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
1748eeb6c6cdd4bdcb6807cd8152e1e36b4883a8fa5Jake Wharton    static final LruCache<String, Typeface> sTypefaceCache = new LruCache<>(16);
175fc857452283b38dfbac9ca023a77a8cf8b8c5599Seigo Nonaka
176fc857452283b38dfbac9ca023a77a8cf8b8c5599Seigo Nonaka    private static final int BACKGROUND_THREAD_KEEP_ALIVE_DURATION_MS = 10000;
177fc857452283b38dfbac9ca023a77a8cf8b8c5599Seigo Nonaka    private static final SelfDestructiveThread sBackgroundThread =
178fc857452283b38dfbac9ca023a77a8cf8b8c5599Seigo Nonaka            new SelfDestructiveThread("fonts", Process.THREAD_PRIORITY_BACKGROUND,
179fc857452283b38dfbac9ca023a77a8cf8b8c5599Seigo Nonaka                    BACKGROUND_THREAD_KEEP_ALIVE_DURATION_MS);
180fc857452283b38dfbac9ca023a77a8cf8b8c5599Seigo Nonaka
181758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri    @NonNull
1828eeb6c6cdd4bdcb6807cd8152e1e36b4883a8fa5Jake Wharton    static TypefaceResult getFontInternal(final Context context, final FontRequest request,
18308df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka            int style) {
1842afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka        FontFamilyResult result;
1852afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka        try {
1862afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka            result = fetchFonts(context, null /* CancellationSignal */, request);
1872afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka        } catch (PackageManager.NameNotFoundException e) {
188758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri            return new TypefaceResult(null, FontRequestCallback.FAIL_REASON_PROVIDER_NOT_FOUND);
1892afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka        }
1902afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka        if (result.getStatusCode() == FontFamilyResult.STATUS_OK) {
191758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri            final Typeface typeface = TypefaceCompat.createFromFontInfo(
192758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                    context, null /* CancellationSignal */, result.getFonts(), style);
193758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri            return new TypefaceResult(typeface, typeface != null
194758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                    ? FontRequestCallback.RESULT_OK
195758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                    : FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR);
1962afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka        }
197758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri        int resultCode = result.getStatusCode() == FontFamilyResult.STATUS_WRONG_CERTIFICATES
198758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                ? FontRequestCallback.FAIL_REASON_WRONG_CERTIFICATES
199758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                : FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR;
200758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri        return new TypefaceResult(null, resultCode);
2012afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka    }
2022afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka
2038eeb6c6cdd4bdcb6807cd8152e1e36b4883a8fa5Jake Wharton    static final Object sLock = new Object();
2042afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka    @GuardedBy("sLock")
2058eeb6c6cdd4bdcb6807cd8152e1e36b4883a8fa5Jake Wharton    static final SimpleArrayMap<String, ArrayList<ReplyCallback<TypefaceResult>>>
2062afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka            sPendingReplies = new SimpleArrayMap<>();
2072afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka
208758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri    private static final class TypefaceResult {
209758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri        final Typeface mTypeface;
210758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri        @FontRequestCallback.FontRequestFailReason final int mResult;
211758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri
212758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri        TypefaceResult(@Nullable Typeface typeface,
213758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                @FontRequestCallback.FontRequestFailReason int result) {
214758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri            mTypeface = typeface;
215758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri            mResult = result;
216758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri        }
217758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri    }
218758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri
219758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri    /**
220758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri     * Used for tests, should not be used otherwise.
221758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri     * @hide
222758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri     **/
223758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri    @RestrictTo(LIBRARY_GROUP)
224c05db2551709fb74903cce69f3e4b9f553e607afJake Wharton    public static void resetCache() {
225758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri        sTypefaceCache.evictAll();
226758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri    }
227758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri
228fc857452283b38dfbac9ca023a77a8cf8b8c5599Seigo Nonaka    /** @hide */
229fc857452283b38dfbac9ca023a77a8cf8b8c5599Seigo Nonaka    @RestrictTo(LIBRARY_GROUP)
2302afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka    public static Typeface getFontSync(final Context context, final FontRequest request,
231758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri            final @Nullable ResourcesCompat.FontCallback fontCallback,
232758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri            final @Nullable Handler handler, boolean isBlockingFetch, int timeout,
233c0eb63876d2618a3560bc7d0c06d80f70e3ebce6Seigo Nonaka            final int style) {
23408df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka        final String id = request.getIdentifier() + "-" + style;
235fc857452283b38dfbac9ca023a77a8cf8b8c5599Seigo Nonaka        Typeface cached = sTypefaceCache.get(id);
236fc857452283b38dfbac9ca023a77a8cf8b8c5599Seigo Nonaka        if (cached != null) {
237758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri            if (fontCallback != null) {
238758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                fontCallback.onFontRetrieved(cached);
239758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri            }
240fc857452283b38dfbac9ca023a77a8cf8b8c5599Seigo Nonaka            return cached;
241fc857452283b38dfbac9ca023a77a8cf8b8c5599Seigo Nonaka        }
242fc857452283b38dfbac9ca023a77a8cf8b8c5599Seigo Nonaka
2432afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka        if (isBlockingFetch && timeout == FontResourcesParserCompat.INFINITE_TIMEOUT_VALUE) {
2442afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka            // Wait forever. No need to post to the thread.
245758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri            TypefaceResult typefaceResult = getFontInternal(context, request, style);
246758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri            if (fontCallback != null) {
247758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                if (typefaceResult.mResult == FontFamilyResult.STATUS_OK) {
248758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                    fontCallback.callbackSuccessAsync(typefaceResult.mTypeface, handler);
249758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                } else {
250758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                    fontCallback.callbackFailAsync(typefaceResult.mResult, handler);
251758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                }
252758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri            }
253758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri            return typefaceResult.mTypeface;
2542afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka        }
2552afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka
256758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri        final Callable<TypefaceResult> fetcher = new Callable<TypefaceResult>() {
2572afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka            @Override
258758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri            public TypefaceResult call() throws Exception {
259758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                TypefaceResult typeface = getFontInternal(context, request, style);
260758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                if (typeface.mTypeface != null) {
261758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                    sTypefaceCache.put(id, typeface.mTypeface);
2622afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka                }
2632afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka                return typeface;
2642afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka            }
2652afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka        };
2662afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka
2672afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka        if (isBlockingFetch) {
2682afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka            try {
269758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                return sBackgroundThread.postAndWait(fetcher, timeout).mTypeface;
2702afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka            } catch (InterruptedException e) {
2712afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka                return null;
2722afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka            }
2732afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka        } else {
274758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri            final ReplyCallback<TypefaceResult> reply = fontCallback == null ? null
275758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                    : new ReplyCallback<TypefaceResult>() {
276758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                        @Override
277758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                        public void onReply(final TypefaceResult typeface) {
278b130e7d5297cca645f8747b7055a1f3e3c608755Clara Bayarri                            if (typeface == null) {
279b130e7d5297cca645f8747b7055a1f3e3c608755Clara Bayarri                                fontCallback.callbackFailAsync(
280b130e7d5297cca645f8747b7055a1f3e3c608755Clara Bayarri                                        FontRequestCallback.FAIL_REASON_FONT_NOT_FOUND, handler);
281b130e7d5297cca645f8747b7055a1f3e3c608755Clara Bayarri                            } else if (typeface.mResult == FontFamilyResult.STATUS_OK) {
282758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                                fontCallback.callbackSuccessAsync(typeface.mTypeface, handler);
283758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                            } else {
284758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                                fontCallback.callbackFailAsync(typeface.mResult, handler);
285758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                            }
286758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                        }
287758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                    };
2882afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka
2892afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka            synchronized (sLock) {
2902afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka                if (sPendingReplies.containsKey(id)) {
2912afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka                    // Already requested. Do not request the same provider again and insert the
2922afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka                    // reply to the queue instead.
293758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                    if (reply != null) {
294758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                        sPendingReplies.get(id).add(reply);
295758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                    }
296fc857452283b38dfbac9ca023a77a8cf8b8c5599Seigo Nonaka                    return null;
297fc857452283b38dfbac9ca023a77a8cf8b8c5599Seigo Nonaka                }
298758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                if (reply != null) {
299758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                    ArrayList<ReplyCallback<TypefaceResult>> pendingReplies = new ArrayList<>();
300758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                    pendingReplies.add(reply);
301758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                    sPendingReplies.put(id, pendingReplies);
302758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                }
3032afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka            }
304758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri            sBackgroundThread.postAndReply(fetcher, new ReplyCallback<TypefaceResult>() {
3052afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka                @Override
306758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                public void onReply(final TypefaceResult typeface) {
307758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                    final ArrayList<ReplyCallback<TypefaceResult>> replies;
3082afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka                    synchronized (sLock) {
3092afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka                        replies = sPendingReplies.get(id);
3101f11788de2c6be7af5790e4d6fbc4b8a8d7a5b26Seigo Nonaka                        if (replies == null) {
3111f11788de2c6be7af5790e4d6fbc4b8a8d7a5b26Seigo Nonaka                            return;  // Nobody requested replies. Do nothing.
3121f11788de2c6be7af5790e4d6fbc4b8a8d7a5b26Seigo Nonaka                        }
3132afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka                        sPendingReplies.remove(id);
3142afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka                    }
3152afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka                    for (int i = 0; i < replies.size(); ++i) {
3162afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka                        replies.get(i).onReply(typeface);
3172afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka                    }
318758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                }
3192afabd060e15342c0ba622cb08f5be61a328e566Seigo Nonaka            });
320fc857452283b38dfbac9ca023a77a8cf8b8c5599Seigo Nonaka            return null;
321fc857452283b38dfbac9ca023a77a8cf8b8c5599Seigo Nonaka        }
322fc857452283b38dfbac9ca023a77a8cf8b8c5599Seigo Nonaka    }
323fc857452283b38dfbac9ca023a77a8cf8b8c5599Seigo Nonaka
3240b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    /**
3250b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     * Object represent a font entry in the family returned from {@link #fetchFonts}.
3260b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     */
3270b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    public static class FontInfo {
3280b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        private final Uri mUri;
3290b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        private final int mTtcIndex;
3300b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        private final int mWeight;
3310b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        private final boolean mItalic;
3320b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        private final int mResultCode;
3330b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
3340b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        /**
3350b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * Creates a Font with all the information needed about a provided font.
3360b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * @param uri A URI associated to the font file.
3370b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * @param ttcIndex If providing a TTC_INDEX file, the index to point to. Otherwise, 0.
3380b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * @param weight An integer that indicates the font weight.
3390b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * @param italic A boolean that indicates the font is italic style or not.
3400b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * @param resultCode A boolean that indicates the font contents is ready.
341758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri         *
342758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri         * @hide
3430b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         */
3440b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        @RestrictTo(LIBRARY_GROUP)
3450b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public FontInfo(@NonNull Uri uri, @IntRange(from = 0) int ttcIndex,
3460b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                @IntRange(from = 1, to = 1000) int weight,
3470b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                boolean italic, int resultCode) {
3480b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            mUri = Preconditions.checkNotNull(uri);
3490b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            mTtcIndex = ttcIndex;
3500b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            mWeight = weight;
3510b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            mItalic = italic;
3520b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            mResultCode = resultCode;
3530b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        }
3540b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
3550b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        /**
3560b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * Returns a URI associated to this record.
3570b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         */
3580b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public @NonNull Uri getUri() {
3590b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            return mUri;
3600b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        }
3610b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
3620b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        /**
3630b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * Returns the index to be used to access this font when accessing a TTC file.
3640b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         */
3650b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public @IntRange(from = 0) int getTtcIndex() {
3660b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            return mTtcIndex;
3670b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        }
3680b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
3690b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        /**
3700b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * Returns the weight value for this font.
3710b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         */
3720b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public @IntRange(from = 1, to = 1000) int getWeight() {
3730b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            return mWeight;
3740b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        }
3750b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
3760b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        /**
3770b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * Returns whether this font is italic.
3780b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         */
3790b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public boolean isItalic() {
3800b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            return mItalic;
3810b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        }
3820b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
3830b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        /**
3840b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * Returns result code.
3850b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         *
3860b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * {@link FontsContractCompat.Columns#RESULT_CODE}
3870b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         */
3880b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public int getResultCode() {
3890b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            return mResultCode;
3900b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        }
3910b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    }
3920b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
3930b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    /**
3940b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     * Object returned from {@link #fetchFonts}.
3950b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     */
3960b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    public static class FontFamilyResult {
3970b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        /**
3980b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * Constant represents that the font was successfully retrieved. Note that when this value
3990b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * is set and {@link #getFonts} returns an empty array, it means there were no fonts
4000b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * matching the given query.
4010b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         */
4020b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public static final int STATUS_OK = 0;
4030b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
4040b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        /**
4050b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * Constant represents that the given certificate was not matched with the provider's
4060b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * signature. {@link #getFonts} returns null if this status was set.
4070b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         */
4080b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public static final int STATUS_WRONG_CERTIFICATES = 1;
4090b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
4100b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        /**
4110b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * Constant represents that the provider returns unexpected data. {@link #getFonts} returns
4120b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * null if this status was set. For example, this value is set when the font provider
4130b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * gives invalid format of variation settings.
4140b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         */
4150b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public static final int STATUS_UNEXPECTED_DATA_PROVIDED = 2;
4160b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
4170b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        /** @hide */
4180b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        @RestrictTo(LIBRARY_GROUP)
4190b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        @IntDef({STATUS_OK, STATUS_WRONG_CERTIFICATES, STATUS_UNEXPECTED_DATA_PROVIDED})
4200b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        @Retention(RetentionPolicy.SOURCE)
4210b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        @interface FontResultStatus {}
4220b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
4230b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        private final @FontResultStatus int mStatusCode;
4240b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        private final FontInfo[] mFonts;
4250b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
4260b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        /** @hide */
4270b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        @RestrictTo(LIBRARY_GROUP)
4280b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public FontFamilyResult(@FontResultStatus int statusCode, @Nullable FontInfo[] fonts) {
4290b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            mStatusCode = statusCode;
4300b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            mFonts = fonts;
4310b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        }
4320b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
4330b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public @FontResultStatus int getStatusCode() {
4340b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            return mStatusCode;
4350b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        }
4360b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
4370b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public FontInfo[] getFonts() {
4380b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            return mFonts;
4390b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        }
4400b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    }
4410b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
4420b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    /**
4430b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     * Interface used to receive asynchronously fetched typefaces.
4440b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     */
4450b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    public static class FontRequestCallback {
446758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri        /** @hide */
447758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri        @RestrictTo(LIBRARY_GROUP)
448758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri        public static final int RESULT_OK = Columns.RESULT_CODE_OK;
4490b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        /**
4500b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given
4510b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * provider was not found on the device.
4520b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         */
4530b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public static final int FAIL_REASON_PROVIDER_NOT_FOUND = RESULT_CODE_PROVIDER_NOT_FOUND;
4540b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        /**
4550b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given
4560b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * provider must be authenticated and the given certificates do not match its signature.
4570b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         */
4580b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public static final int FAIL_REASON_WRONG_CERTIFICATES = RESULT_CODE_WRONG_CERTIFICATES;
4590b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        /**
4600b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the font
4610b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * returned by the provider was not loaded properly.
4620b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         */
4630b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public static final int FAIL_REASON_FONT_LOAD_ERROR = -3;
4640b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        /**
465758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri         * Constant that signals that the font was not loaded due to security issues. This usually
466758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri         * means the font was attempted to load on a restricted context.
467758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri         */
468758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri        public static final int FAIL_REASON_SECURITY_VIOLATION = -4;
469758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri        /**
4700b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the font
4710b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * provider did not return any results for the given query.
4720b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         */
4730b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public static final int FAIL_REASON_FONT_NOT_FOUND = Columns.RESULT_CODE_FONT_NOT_FOUND;
4740b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        /**
4750b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the font
4760b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * provider found the queried font, but it is currently unavailable.
4770b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         */
4780b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public static final int FAIL_REASON_FONT_UNAVAILABLE = Columns.RESULT_CODE_FONT_UNAVAILABLE;
4790b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        /**
4800b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given
4810b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * query was not supported by the provider.
4820b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         */
4830b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public static final int FAIL_REASON_MALFORMED_QUERY = Columns.RESULT_CODE_MALFORMED_QUERY;
4840b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
4850b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        /** @hide */
4860b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        @RestrictTo(LIBRARY_GROUP)
4870b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        @IntDef({ FAIL_REASON_PROVIDER_NOT_FOUND, FAIL_REASON_FONT_LOAD_ERROR,
4880b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                FAIL_REASON_FONT_NOT_FOUND, FAIL_REASON_FONT_UNAVAILABLE,
489758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                FAIL_REASON_MALFORMED_QUERY, FAIL_REASON_WRONG_CERTIFICATES,
490758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri                FAIL_REASON_SECURITY_VIOLATION, RESULT_OK })
4910b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        @Retention(RetentionPolicy.SOURCE)
492758621d23659e4b0da3b2ad00a84a5624efb1be8Clara Bayarri        public @interface FontRequestFailReason {}
4930b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
4940b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public FontRequestCallback() {}
4950b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
4960b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        /**
4970b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * Called then a Typeface request done via {@link #requestFont(Context, FontRequest,
4980b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * FontRequestCallback, Handler)} is complete. Note that this method will not be called if
4990b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * {@link #onTypefaceRequestFailed(int)} is called instead.
5000b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * @param typeface  The Typeface object retrieved.
5010b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         */
5020b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public void onTypefaceRetrieved(Typeface typeface) {}
5030b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
5040b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        /**
5050b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * Called when a Typeface request done via {@link #requestFont(Context, FontRequest,
5060b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * FontRequestCallback, Handler)} fails.
5070b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         * @param reason May be one of {@link #FAIL_REASON_PROVIDER_NOT_FOUND},
5080b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         *               {@link #FAIL_REASON_FONT_NOT_FOUND},
5090b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         *               {@link #FAIL_REASON_FONT_LOAD_ERROR},
5100b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         *               {@link #FAIL_REASON_FONT_UNAVAILABLE},
5110b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         *               {@link #FAIL_REASON_MALFORMED_QUERY} or
5120b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         *               {@link #FAIL_REASON_WRONG_CERTIFICATES}, or a provider defined positive
5130b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         *               code number.
5140b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka         */
5150b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public void onTypefaceRequestFailed(@FontRequestFailReason int reason) {}
5160b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    }
5170b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
5180b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    /**
5190b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     * Create a typeface object given a font request. The font will be asynchronously fetched,
5200b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     * therefore the result is delivered to the given callback. See {@link FontRequest}.
5210b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     * Only one of the methods in callback will be invoked, depending on whether the request
5220b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     * succeeds or fails. These calls will happen on the caller thread.
5230b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     * @param context A context to be used for fetching from font provider.
5240b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     * @param request A {@link FontRequest} object that identifies the provider and query for the
5250b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     *                request. May not be null.
5260b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     * @param callback A callback that will be triggered when results are obtained. May not be null.
5270b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     * @param handler A handler to be processed the font fetching.
5280b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     */
5290b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    public static void requestFont(final @NonNull Context context,
5300b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            final @NonNull FontRequest request, final @NonNull FontRequestCallback callback,
5310b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            final @NonNull Handler handler) {
5320b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        final Handler callerThreadHandler = new Handler();
5330b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        handler.post(new Runnable() {
5340b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            @Override
5350b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            public void run() {
5360b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                // TODO: Cache the result.
5370b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                FontFamilyResult result;
5380b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                try {
5390b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    result = fetchFonts(context, null /* cancellation signal */, request);
5400b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                } catch (PackageManager.NameNotFoundException e) {
5410b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    callerThreadHandler.post(new Runnable() {
5420b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                        @Override
5430b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                        public void run() {
5440b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                            callback.onTypefaceRequestFailed(
5450b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                                    FontRequestCallback.FAIL_REASON_PROVIDER_NOT_FOUND);
5460b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                        }
5470b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    });
5480b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    return;
5490b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                }
5500b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
5510b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                if (result.getStatusCode() != FontFamilyResult.STATUS_OK) {
5520b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    switch (result.getStatusCode()) {
5530b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                        case FontFamilyResult.STATUS_WRONG_CERTIFICATES:
5540b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                            callerThreadHandler.post(new Runnable() {
5550b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                                @Override
5560b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                                public void run() {
5570b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                                    callback.onTypefaceRequestFailed(
5580b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                                            FontRequestCallback.FAIL_REASON_WRONG_CERTIFICATES);
5590b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                                }
5600b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                            });
5610b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                            return;
5620b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                        case FontFamilyResult.STATUS_UNEXPECTED_DATA_PROVIDED:
5630b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                            callerThreadHandler.post(new Runnable() {
5640b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                                @Override
5650b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                                public void run() {
5660b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                                    callback.onTypefaceRequestFailed(
5670b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                                            FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR);
5680b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                                }
5690b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                            });
5700b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                            return;
5710b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                        default:
5720b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                            // fetchFont returns unexpected status type. Fallback to load error.
5730b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                            callerThreadHandler.post(new Runnable() {
5740b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                                @Override
5750b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                                public void run() {
5760b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                                    callback.onTypefaceRequestFailed(
5770b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                                            FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR);
5780b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                                }
5790b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                            });
5800b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                            return;
5810b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    }
5820b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                }
5830b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
5840b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                final FontInfo[] fonts = result.getFonts();
5850b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                if (fonts == null || fonts.length == 0) {
5860b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    callerThreadHandler.post(new Runnable() {
5870b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                        @Override
5880b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                        public void run() {
5890b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                            callback.onTypefaceRequestFailed(
5900b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                                    FontRequestCallback.FAIL_REASON_FONT_NOT_FOUND);
5910b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                        }
5920b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    });
5930b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    return;
5940b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                }
5950b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                for (final FontInfo font : fonts) {
5960b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    if (font.getResultCode() != Columns.RESULT_CODE_OK) {
5970b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                        // We proceed if all font entry is ready to use. Otherwise report the first
5980b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                        // error.
5990b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                        final int resultCode = font.getResultCode();
6000b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                        if (resultCode < 0) {
6010b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                            // Negative values are reserved for internal errors. Fallback to load
6020b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                            // error.
6030b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                            callerThreadHandler.post(new Runnable() {
6040b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                                @Override
6050b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                                public void run() {
6060b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                                    callback.onTypefaceRequestFailed(
6070b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                                            FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR);
6080b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                                }
6090b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                            });
6100b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                        } else {
6110b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                            callerThreadHandler.post(new Runnable() {
6120b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                                @Override
6130b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                                public void run() {
6140b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                                    callback.onTypefaceRequestFailed(resultCode);
6150b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                                }
6160b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                            });
6170b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                        }
6180b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                        return;
6190b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    }
6200b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                }
6210b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
6220b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                final Typeface typeface = buildTypeface(context, null /* cancellation signal */,
6230b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                        fonts);
6240b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                if (typeface == null) {
6250b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    // Something went wrong during reading font files. This happens if the given
6260b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    // font file is an unsupported font type.
6270b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    callerThreadHandler.post(new Runnable() {
6280b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                        @Override
6290b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                        public void run() {
6300b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                            callback.onTypefaceRequestFailed(
6310b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                                    FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR);
6320b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                        }
6330b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    });
6340b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    return;
6350b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                }
6360b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
6370b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                callerThreadHandler.post(new Runnable() {
6380b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    @Override
6390b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    public void run() {
6400b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                        callback.onTypefaceRetrieved(typeface);
6410b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    }
6420b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                });
6430b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            }
6440b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        });
6450b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    }
6460b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
6470b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    /**
6480b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     * Build a Typeface from an array of {@link FontInfo}
6490b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     *
6500b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     * Results that are marked as not ready will be skipped.
6510b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     *
6520b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     * @param context A {@link Context} that will be used to fetch the font contents.
6530b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     * @param cancellationSignal A signal to cancel the operation in progress, or null if none. If
6540b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     *                           the operation is canceled, then {@link
6550b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     *                           android.os.OperationCanceledException} will be thrown.
6560b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     * @param fonts An array of {@link FontInfo} to be used to create a Typeface.
6570b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     * @return A Typeface object. Returns null if typeface creation fails.
6580b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     */
6590a3498a4fe976baa759b1b5f27a7c8ebdeb07f4cJake Wharton    @Nullable
6600b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    public static Typeface buildTypeface(@NonNull Context context,
6610b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            @Nullable CancellationSignal cancellationSignal, @NonNull FontInfo[] fonts) {
66208df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka        return TypefaceCompat.createFromFontInfo(context, cancellationSignal, fonts,
66308df2afeec46f363ef5f17146750bdf011412e56Seigo Nonaka                Typeface.NORMAL);
6640b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    }
6650b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
6660b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    /**
66711e831738feba2bb6c5338358812a373bda9991aClara Bayarri     * A helper function to create a mapping from {@link Uri} to {@link ByteBuffer}.
66811e831738feba2bb6c5338358812a373bda9991aClara Bayarri     *
66911e831738feba2bb6c5338358812a373bda9991aClara Bayarri     * Skip if the file contents is not ready to be read.
67011e831738feba2bb6c5338358812a373bda9991aClara Bayarri     *
67111e831738feba2bb6c5338358812a373bda9991aClara Bayarri     * @param context A {@link Context} to be used for resolving content URI in
67211e831738feba2bb6c5338358812a373bda9991aClara Bayarri     *                {@link FontInfo}.
67311e831738feba2bb6c5338358812a373bda9991aClara Bayarri     * @param fonts An array of {@link FontInfo}.
67411e831738feba2bb6c5338358812a373bda9991aClara Bayarri     * @return A map from {@link Uri} to {@link ByteBuffer}.
67511e831738feba2bb6c5338358812a373bda9991aClara Bayarri     * @hide
67611e831738feba2bb6c5338358812a373bda9991aClara Bayarri     */
67711e831738feba2bb6c5338358812a373bda9991aClara Bayarri    @RestrictTo(LIBRARY_GROUP)
67811e831738feba2bb6c5338358812a373bda9991aClara Bayarri    @RequiresApi(19)
67911e831738feba2bb6c5338358812a373bda9991aClara Bayarri    public static Map<Uri, ByteBuffer> prepareFontData(Context context, FontInfo[] fonts,
68011e831738feba2bb6c5338358812a373bda9991aClara Bayarri            CancellationSignal cancellationSignal) {
68111e831738feba2bb6c5338358812a373bda9991aClara Bayarri        final HashMap<Uri, ByteBuffer> out = new HashMap<>();
68211e831738feba2bb6c5338358812a373bda9991aClara Bayarri
68311e831738feba2bb6c5338358812a373bda9991aClara Bayarri        for (FontInfo font : fonts) {
68411e831738feba2bb6c5338358812a373bda9991aClara Bayarri            if (font.getResultCode() != Columns.RESULT_CODE_OK) {
68511e831738feba2bb6c5338358812a373bda9991aClara Bayarri                continue;
68611e831738feba2bb6c5338358812a373bda9991aClara Bayarri            }
68711e831738feba2bb6c5338358812a373bda9991aClara Bayarri
68811e831738feba2bb6c5338358812a373bda9991aClara Bayarri            final Uri uri = font.getUri();
68911e831738feba2bb6c5338358812a373bda9991aClara Bayarri            if (out.containsKey(uri)) {
69011e831738feba2bb6c5338358812a373bda9991aClara Bayarri                continue;
69111e831738feba2bb6c5338358812a373bda9991aClara Bayarri            }
69211e831738feba2bb6c5338358812a373bda9991aClara Bayarri
69311e831738feba2bb6c5338358812a373bda9991aClara Bayarri            ByteBuffer buffer = TypefaceCompatUtil.mmap(context, cancellationSignal, uri);
69411e831738feba2bb6c5338358812a373bda9991aClara Bayarri            out.put(uri, buffer);
69511e831738feba2bb6c5338358812a373bda9991aClara Bayarri        }
69611e831738feba2bb6c5338358812a373bda9991aClara Bayarri        return Collections.unmodifiableMap(out);
69711e831738feba2bb6c5338358812a373bda9991aClara Bayarri    }
69811e831738feba2bb6c5338358812a373bda9991aClara Bayarri
69911e831738feba2bb6c5338358812a373bda9991aClara Bayarri    /**
7000b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     * Fetch fonts given a font request.
7010b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     *
7020b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     * @param context A {@link Context} to be used for fetching fonts.
7030b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     * @param cancellationSignal A signal to cancel the operation in progress, or null if none. If
7040b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     *                           the operation is canceled, then {@link
7050b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     *                           android.os.OperationCanceledException} will be thrown when the
7060b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     *                           query is executed.
7070b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     * @param request A {@link FontRequest} object that identifies the provider and query for the
7080b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     *                request.
7090b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     *
7100b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     * @return {@link FontFamilyResult}
7110b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     *
7120b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     * @throws PackageManager.NameNotFoundException If requested package or authority was not found
7130b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     *      in the system.
7140b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka     */
7150b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    @NonNull
7160b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    public static FontFamilyResult fetchFonts(@NonNull Context context,
7170b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            @Nullable CancellationSignal cancellationSignal, @NonNull FontRequest request)
7180b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            throws PackageManager.NameNotFoundException {
7190b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        ProviderInfo providerInfo = getProvider(
7200b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                context.getPackageManager(), request, context.getResources());
7210b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        if (providerInfo == null) {
7220b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            return new FontFamilyResult(FontFamilyResult.STATUS_WRONG_CERTIFICATES, null);
7230b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
7240b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        }
7250b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        FontInfo[] fonts = getFontFromProvider(
7260b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                context, request, providerInfo.authority, cancellationSignal);
7270b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        return new FontFamilyResult(FontFamilyResult.STATUS_OK, fonts);
7280b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    }
7290b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
7300b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    /** @hide */
7310b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    @VisibleForTesting
7320b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    @RestrictTo(LIBRARY_GROUP)
7330b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    public static @Nullable ProviderInfo getProvider(@NonNull PackageManager packageManager,
7340b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            @NonNull FontRequest request, @Nullable Resources resources)
7350b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            throws PackageManager.NameNotFoundException {
7360b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        String providerAuthority = request.getProviderAuthority();
7370b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        ProviderInfo info = packageManager.resolveContentProvider(providerAuthority, 0);
7380b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        if (info == null) {
7390b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            throw new PackageManager.NameNotFoundException("No package found for authority: "
7400b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    + providerAuthority);
7410b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        }
7420b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
7430b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        if (!info.packageName.equals(request.getProviderPackage())) {
7440b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            throw new PackageManager.NameNotFoundException("Found content provider "
7450b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    + providerAuthority
7460b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    + ", but package was not " + request.getProviderPackage());
7470b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        }
7480b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
7490b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        List<byte[]> signatures;
750b34c816d06018c63f61ed13d24d8301244800e01Clara Bayarri        // We correctly check all signatures returned, as advised in the lint error.
751b34c816d06018c63f61ed13d24d8301244800e01Clara Bayarri        @SuppressLint("PackageManagerGetSignatures")
7520b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        PackageInfo packageInfo = packageManager.getPackageInfo(info.packageName,
7530b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                PackageManager.GET_SIGNATURES);
7540b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        signatures = convertToByteArrayList(packageInfo.signatures);
7550b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        Collections.sort(signatures, sByteArrayComparator);
7560b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        List<List<byte[]>> requestCertificatesList = getCertificates(request, resources);
7570b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        for (int i = 0; i < requestCertificatesList.size(); ++i) {
7580b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            // Make a copy so we can sort it without modifying the incoming data.
7590b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            List<byte[]> requestSignatures = new ArrayList<>(requestCertificatesList.get(i));
7600b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            Collections.sort(requestSignatures, sByteArrayComparator);
7610b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            if (equalsByteArrayList(signatures, requestSignatures)) {
7620b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                return info;
7630b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            }
7640b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        }
7650b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        return null;
7660b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    }
7670b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
7680b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    private static List<List<byte[]>> getCertificates(FontRequest request, Resources resources) {
7690b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        if (request.getCertificates() != null) {
7700b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            return request.getCertificates();
7710b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        }
7720b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        int resourceId = request.getCertificatesArrayResId();
7730b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        return FontResourcesParserCompat.readCerts(resources, resourceId);
7740b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    }
7750b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
7760b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    private static final Comparator<byte[]> sByteArrayComparator = new Comparator<byte[]>() {
7770b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        @Override
7780b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        public int compare(byte[] l, byte[] r) {
7790b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            if (l.length != r.length) {
7800b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                return l.length - r.length;
7810b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            }
7820b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            for (int i = 0; i < l.length; ++i) {
7830b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                if (l[i] != r[i]) {
7840b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    return l[i] - r[i];
7850b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                }
7860b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            }
7870b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            return 0;
7880b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        }
7890b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    };
7900b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
7910b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    private static boolean equalsByteArrayList(List<byte[]> signatures,
7920b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            List<byte[]> requestSignatures) {
7930b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        if (signatures.size() != requestSignatures.size()) {
7940b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            return false;
7950b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        }
7960b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        for (int i = 0; i < signatures.size(); ++i) {
7970b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            if (!Arrays.equals(signatures.get(i), requestSignatures.get(i))) {
7980b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                return false;
7990b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            }
8000b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        }
8010b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        return true;
8020b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    }
8030b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
8040b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    private static List<byte[]> convertToByteArrayList(Signature[] signatures) {
8050b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        List<byte[]> shas = new ArrayList<>();
8060b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        for (int i = 0; i < signatures.length; ++i) {
8070b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            shas.add(signatures[i].toByteArray());
8080b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        }
8090b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        return shas;
8100b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    }
8110b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
8120b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    @VisibleForTesting
8130b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    @NonNull
8140b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    static FontInfo[] getFontFromProvider(Context context, FontRequest request, String authority,
8150b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            CancellationSignal cancellationSignal) {
8160b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        ArrayList<FontInfo> result = new ArrayList<>();
8170b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        final Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
8180b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                .authority(authority)
8190b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                .build();
8200b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        final Uri fileBaseUri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
8210b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                .authority(authority)
8220b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                .appendPath("file")
8230b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                .build();
8240b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        Cursor cursor = null;
8250b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        try {
8260b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            if (Build.VERSION.SDK_INT > 16) {
8270b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                cursor = context.getContentResolver().query(uri, new String[] {
8280b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                        Columns._ID, Columns.FILE_ID, Columns.TTC_INDEX,
8290b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                        Columns.VARIATION_SETTINGS, Columns.WEIGHT, Columns.ITALIC,
8300b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                        Columns.RESULT_CODE },
8310b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                "query = ?", new String[] { request.getQuery() }, null, cancellationSignal);
8320b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            } else {
8330b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                // No cancellation signal.
8340b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                cursor = context.getContentResolver().query(uri, new String[] {
8350b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                        Columns._ID, Columns.FILE_ID, Columns.TTC_INDEX,
8360b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                        Columns.VARIATION_SETTINGS, Columns.WEIGHT, Columns.ITALIC,
8370b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                        Columns.RESULT_CODE },
8380b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                "query = ?", new String[] { request.getQuery() }, null);
8390b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            }
8400b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            if (cursor != null && cursor.getCount() > 0) {
8410b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                final int resultCodeColumnIndex = cursor.getColumnIndex(Columns.RESULT_CODE);
8420b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                result = new ArrayList<>();
8430b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                final int idColumnIndex = cursor.getColumnIndex(Columns._ID);
8440b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                final int fileIdColumnIndex = cursor.getColumnIndex(Columns.FILE_ID);
8450b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                final int ttcIndexColumnIndex = cursor.getColumnIndex(Columns.TTC_INDEX);
8460b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                final int weightColumnIndex = cursor.getColumnIndex(Columns.WEIGHT);
8470b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                final int italicColumnIndex = cursor.getColumnIndex(Columns.ITALIC);
8480b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                while (cursor.moveToNext()) {
8490b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    int resultCode = resultCodeColumnIndex != -1
8500b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                            ? cursor.getInt(resultCodeColumnIndex) : Columns.RESULT_CODE_OK;
8510b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    final int ttcIndex = ttcIndexColumnIndex != -1
8520b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                            ? cursor.getInt(ttcIndexColumnIndex) : 0;
8530b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    Uri fileUri;
8540b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    if (fileIdColumnIndex == -1) {
8550b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                        long id = cursor.getLong(idColumnIndex);
8560b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                        fileUri = ContentUris.withAppendedId(uri, id);
8570b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    } else {
8580b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                        long id = cursor.getLong(fileIdColumnIndex);
8590b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                        fileUri = ContentUris.withAppendedId(fileBaseUri, id);
8600b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    }
8610b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka
8620b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    int weight = weightColumnIndex != -1 ? cursor.getInt(weightColumnIndex) : 400;
8630b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    boolean italic = italicColumnIndex != -1 && cursor.getInt(italicColumnIndex)
8640b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                            == 1;
8650b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                    result.add(new FontInfo(fileUri, ttcIndex, weight, italic, resultCode));
8660b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                }
8670b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            }
8680b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        } finally {
8690b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            if (cursor != null) {
8700b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka                cursor.close();
8710b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka            }
8720b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        }
8730b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka        return result.toArray(new FontInfo[0]);
8740b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka    }
8750b03693667d95d2202dfbb24866665ff061acce1Seigo Nonaka}
876