FontsContract.java revision 54084b64b1860b652b1c50ba942b4cfc7fb28805
1b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri/*
2b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * Copyright (C) 2017 The Android Open Source Project
3b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri *
4b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * Licensed under the Apache License, Version 2.0 (the "License");
5b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * you may not use this file except in compliance with the License.
6b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * You may obtain a copy of the License at
7b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri *
8b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri *      http://www.apache.org/licenses/LICENSE-2.0
9b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri *
10b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * Unless required by applicable law or agreed to in writing, software
11b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * distributed under the License is distributed on an "AS IS" BASIS,
12b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * See the License for the specific language governing permissions and
14b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * limitations under the License.
15b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri */
16b0812a30499376e09e2deb5995e998c629f24985Clara Bayarripackage android.provider;
17b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
1869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport static android.graphics.fonts.FontVariationAxis.InvalidFormatException;
1969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport static java.lang.annotation.RetentionPolicy.SOURCE;
2069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
2169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport android.annotation.IntDef;
2269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport android.annotation.IntRange;
2369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport android.annotation.NonNull;
2469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport android.annotation.Nullable;
25b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.content.ContentResolver;
26b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.content.ContentUris;
27b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.content.Context;
283c4be77db95ea716889568bde853be082e764da9Clara Bayarriimport android.content.pm.PackageInfo;
2969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport android.content.pm.PackageManager.NameNotFoundException;
30b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.content.pm.PackageManager;
31b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.content.pm.ProviderInfo;
323c4be77db95ea716889568bde853be082e764da9Clara Bayarriimport android.content.pm.Signature;
33b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.database.Cursor;
343c4be77db95ea716889568bde853be082e764da9Clara Bayarriimport android.graphics.Typeface;
35b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.graphics.fonts.FontRequest;
3669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport android.graphics.fonts.FontVariationAxis;
37b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.net.Uri;
38b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.os.Bundle;
3969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport android.os.CancellationSignal;
40b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.os.Handler;
41b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.os.HandlerThread;
42b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.os.ParcelFileDescriptor;
43b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.os.Process;
44b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.os.ResultReceiver;
455a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonakaimport android.util.ArraySet;
46b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.util.Log;
47daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonakaimport android.util.LruCache;
48b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
49b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport com.android.internal.annotations.GuardedBy;
503c4be77db95ea716889568bde853be082e764da9Clara Bayarriimport com.android.internal.annotations.VisibleForTesting;
5169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport com.android.internal.util.Preconditions;
52b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
5369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport java.io.FileInputStream;
54b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport java.io.FileNotFoundException;
55bacf2352ab892724551431551ae973ae3b68db35Clara Bayarriimport java.io.IOException;
5669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport java.lang.annotation.Retention;
5769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport java.lang.annotation.RetentionPolicy;
5869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport java.nio.ByteBuffer;
5969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport java.nio.channels.FileChannel;
60b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport java.util.ArrayList;
61fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarriimport java.util.Arrays;
62fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarriimport java.util.Collections;
63fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarriimport java.util.Comparator;
6469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport java.util.HashMap;
653c4be77db95ea716889568bde853be082e764da9Clara Bayarriimport java.util.List;
6669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport java.util.Map;
675a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonakaimport java.util.Set;
68b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
69b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri/**
70b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * Utility class to deal with Font ContentProviders.
71b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri */
72b0812a30499376e09e2deb5995e998c629f24985Clara Bayarripublic class FontsContract {
73b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    private static final String TAG = "FontsContract";
74b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
75b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    /**
76b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     * Defines the constants used in a response from a Font Provider. The cursor returned from the
77b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     * query should have the ID column populated with the content uri ID for the resulting font.
78b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     * This should point to a real file or shared memory, as the client will mmap the given file
79b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     * descriptor. Pipes, sockets and other non-mmap-able file descriptors will fail to load in the
80b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     * client application.
81b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     */
82b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    public static final class Columns implements BaseColumns {
837fea2e264e2e793586bb999ee80897d488e62141Clara Bayarri
847fea2e264e2e793586bb999ee80897d488e62141Clara Bayarri        // Do not instantiate.
857fea2e264e2e793586bb999ee80897d488e62141Clara Bayarri        private Columns() {}
867fea2e264e2e793586bb999ee80897d488e62141Clara Bayarri
87b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        /**
88b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri         * Constant used to request data from a font provider. The cursor returned from the query
8943c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka         * may populate this column with a long for the font file ID. The client will request a file
9043c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka         * descriptor to "file/FILE_ID" with this ID immediately under the top-level content URI. If
9143c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka         * not present, the client will request a file descriptor to the top-level URI with the
9243c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka         * given base font ID. Note that several results may return the same file ID, e.g. for TTC
9343c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka         * files with different indices.
9443c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka         */
9543c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka        public static final String FILE_ID = "file_id";
9643c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka        /**
9743c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka         * Constant used to request data from a font provider. The cursor returned from the query
98b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri         * should have this column populated with an int for the ttc index for the resulting font.
99b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri         */
100b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        public static final String TTC_INDEX = "font_ttc_index";
101b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        /**
102b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri         * Constant used to request data from a font provider. The cursor returned from the query
103b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri         * may populate this column with the font variation settings String information for the
104b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri         * font.
105b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri         */
106b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        public static final String VARIATION_SETTINGS = "font_variation_settings";
107b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        /**
108bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * Constant used to request data from a font provider. The cursor returned from the query
109fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * should have this column populated with the int weight for the resulting font. This value
110fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * should be between 100 and 900. The most common values are 400 for regular weight and 700
111fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * for bold weight.
112fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         */
113fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka        public static final String WEIGHT = "font_weight";
114fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka        /**
115fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * Constant used to request data from a font provider. The cursor returned from the query
116fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * should have this column populated with the int italic for the resulting font. This should
117fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * be 0 for regular style and 1 for italic.
118fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         */
119fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka        public static final String ITALIC = "font_italic";
120fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka        /**
121fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * Constant used to request data from a font provider. The cursor returned from the query
122bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * should have this column populated to indicate the result status of the
123bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * query. This will be checked before any other data in the cursor. Possible values are
124bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * {@link #RESULT_CODE_OK}, {@link #RESULT_CODE_FONT_NOT_FOUND},
1255706a1b12dd891098fb7bf479623d42979171144Clara Bayarri         * {@link #RESULT_CODE_MALFORMED_QUERY} and {@link #RESULT_CODE_FONT_UNAVAILABLE} for system
1265706a1b12dd891098fb7bf479623d42979171144Clara Bayarri         * defined values. You may also define your own values in the 0x000010000..0xFFFF0000 range.
1275706a1b12dd891098fb7bf479623d42979171144Clara Bayarri         * If not present, {@link #RESULT_CODE_OK} will be assumed.
128bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         */
129bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        public static final String RESULT_CODE = "result_code";
130bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri
131bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        /**
132bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * Constant used to represent a result was retrieved successfully. The given fonts will be
133bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * attempted to retrieve immediately via
134bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * {@link android.content.ContentProvider#openFile(Uri, String)}. See {@link #RESULT_CODE}.
135bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         */
136bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        public static final int RESULT_CODE_OK = 0;
137bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        /**
138bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * Constant used to represent a result was not found. See {@link #RESULT_CODE}.
139bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         */
140bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        public static final int RESULT_CODE_FONT_NOT_FOUND = 1;
141bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        /**
142bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * Constant used to represent a result was found, but cannot be provided at this moment. Use
143bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * this to indicate, for example, that a font needs to be fetched from the network. See
144bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * {@link #RESULT_CODE}.
145bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         */
146bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        public static final int RESULT_CODE_FONT_UNAVAILABLE = 2;
147bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        /**
148bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * Constant used to represent that the query was not in a supported format by the provider.
149bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * See {@link #RESULT_CODE}.
150bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         */
151bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        public static final int RESULT_CODE_MALFORMED_QUERY = 3;
152b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    }
153b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
15454084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka    private static final Object sLock = new Object();
15554084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka    @GuardedBy("sLock")
15654084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka    private static Handler sHandler;
15754084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka    @GuardedBy("sLock")
15854084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka    private static HandlerThread sThread;
15954084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka    @GuardedBy("sLock")
16054084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka    private static Set<String> sInQueueSet;
161b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
16254084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka    private volatile static Context sContext;  // set once in setApplicationContextForResources
163b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
164daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka    private static final LruCache<String, Typeface> sTypefaceCache = new LruCache<>(16);
165daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka
16654084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka    private FontsContract() {
16754084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka    }
16854084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka
169b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    /** @hide */
17054084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka    public static void setApplicationContextForResources(Context context) {
17154084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka        sContext = context.getApplicationContext();
172b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    }
173b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
17469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    /**
17569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * Object represent a font entry in the family returned from {@link #fetchFonts}.
17669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     */
17769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    public static class FontInfo {
17869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        private final Uri mUri;
17969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        private final int mTtcIndex;
18069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        private final FontVariationAxis[] mAxes;
18169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        private final int mWeight;
18269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        private final boolean mItalic;
18369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        private final int mResultCode;
18469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
18569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /**
18669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * Creates a Font with all the information needed about a provided font.
18769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * @param uri A URI associated to the font file.
18869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * @param ttcIndex If providing a TTC_INDEX file, the index to point to. Otherwise, 0.
18969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * @param axes If providing a variation font, the settings for it. May be null.
19069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * @param weight An integer that indicates the font weight.
19169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * @param italic A boolean that indicates the font is italic style or not.
19269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * @param resultCode A boolean that indicates the font contents is ready.
19369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         */
19469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /** @hide */
19569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public FontInfo(@NonNull Uri uri, @IntRange(from = 0) int ttcIndex,
19669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                @Nullable FontVariationAxis[] axes, @IntRange(from = 1, to = 1000) int weight,
19769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                boolean italic, int resultCode) {
19869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            mUri = Preconditions.checkNotNull(uri);
19969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            mTtcIndex = ttcIndex;
20069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            mAxes = axes;
20169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            mWeight = weight;
20269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            mItalic = italic;
20369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            mResultCode = resultCode;
20469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
20569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
20669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /**
20769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * Returns a URI associated to this record.
20869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         */
20969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public @NonNull Uri getUri() {
21069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return mUri;
21169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
21269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
21369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /**
21469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * Returns the index to be used to access this font when accessing a TTC file.
21569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         */
21669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public @IntRange(from = 0) int getTtcIndex() {
21769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return mTtcIndex;
21869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
21969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
22069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /**
22169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * Returns the list of axes associated to this font.
22269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         */
22369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public @Nullable FontVariationAxis[] getAxes() {
22469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return mAxes;
22569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
22669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
22769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /**
22869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * Returns the weight value for this font.
22969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         */
23069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public @IntRange(from = 1, to = 1000) int getWeight() {
23169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return mWeight;
23269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
23369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
23469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /**
23569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * Returns whether this font is italic.
23669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         */
23769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public boolean isItalic() {
23869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return mItalic;
23969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
24069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
24169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /**
24269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * Returns result code.
24369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         *
24469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * {@link FontsContract.Columns#RESULT_CODE}
24569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         */
24669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public int getResultCode() {
24769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return mResultCode;
24869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
24969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    }
25069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
25169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    /**
25269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * Object returned from {@link #fetchFonts}.
25369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     */
25469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    public static class FontFamilyResult {
25569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /**
25669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * Constant represents that the font was successfully retrieved. Note that when this value
25769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * is set and {@link #getFonts} returns an empty array, it means there were no fonts
25869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * matching the given query.
25969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         */
26069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public static final int STATUS_OK = 0;
26169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
26269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /**
26369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * Constant represents that the given certificate was not matched with the provider's
26469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * signature. {@link #getFonts} returns null if this status was set.
26569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         */
26669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public static final int STATUS_WRONG_CERTIFICATES = 1;
26769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
26869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /**
26969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * Constant represents that the provider returns unexpected data. {@link #getFonts} returns
27069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * null if this status was set. For example, this value is set when the font provider
27169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * gives invalid format of variation settings.
27269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         */
27369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public static final int STATUS_UNEXPECTED_DATA_PROVIDED = 2;
27469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
275ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka        /**
276ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka         * Constant represents that the fetching font data was rejected by system. This happens if
277ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka         * the passed context is restricted.
278ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka         */
279ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka        public static final int STATUS_REJECTED = 3;
280ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka
28169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /** @hide */
28269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        @IntDef({STATUS_OK, STATUS_WRONG_CERTIFICATES, STATUS_UNEXPECTED_DATA_PROVIDED})
28369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        @Retention(RetentionPolicy.SOURCE)
28469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        @interface FontResultStatus {}
28569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
28669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        private final @FontResultStatus int mStatusCode;
28769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        private final FontInfo[] mFonts;
28869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
28969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /** @hide */
29069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public FontFamilyResult(@FontResultStatus int statusCode, @Nullable FontInfo[] fonts) {
29169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            mStatusCode = statusCode;
29269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            mFonts = fonts;
29369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
29469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
29569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public @FontResultStatus int getStatusCode() {
29669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return mStatusCode;
29769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
29869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
29969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public @NonNull FontInfo[] getFonts() {
30069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return mFonts;
30169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
3023c4be77db95ea716889568bde853be082e764da9Clara Bayarri    }
3033c4be77db95ea716889568bde853be082e764da9Clara Bayarri
30454084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka    private static final int THREAD_RENEWAL_THRESHOLD_MS = 10000;
30554084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka
306b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    // We use a background thread to post the content resolving work for all requests on. This
307b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    // thread should be quit/stopped after all requests are done.
30854084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka    // TODO: Factor out to other class. Consider to switch MessageQueue.IdleHandler.
30954084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka    private static final Runnable sReplaceDispatcherThreadRunnable = new Runnable() {
310b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        @Override
311b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        public void run() {
31254084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka            synchronized (sLock) {
31354084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka                if (sThread != null) {
31454084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka                    sThread.quitSafely();
31554084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka                    sThread = null;
31654084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka                    sHandler = null;
31754084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka                    sInQueueSet = null;
318b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                }
319b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            }
320b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        }
321b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    };
322b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
323bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri    /** @hide */
32454084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka    public static Typeface getFontOrWarmUpCache(FontRequest request) {
3255a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka        final String id = request.getIdentifier();
3265a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka        Typeface cachedTypeface = sTypefaceCache.get(id);
3275a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka        if (cachedTypeface != null) {
3285a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka            return cachedTypeface;
3295a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka        }
3305a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka
3315a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka        // Unfortunately the typeface is not available at this time, but requesting from the font
3325a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka        // provider takes too much time. For now, request the font data to ensure it is in the cache
3335a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka        // next time and return.
33454084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka        synchronized (sLock) {
33554084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka            if (sHandler == null) {
33654084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka                sThread = new HandlerThread("fonts", Process.THREAD_PRIORITY_BACKGROUND);
33754084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka                sThread.start();
33854084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka                sHandler = new Handler(sThread.getLooper());
33954084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka                sInQueueSet = new ArraySet<>();
340b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            }
34154084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka            if (sInQueueSet.contains(id)) {
3425a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka                return null;  // Already requested.
3435a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka            }
34454084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka            sInQueueSet.add(id);
34554084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka            sHandler.post(() -> {
34654084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka                synchronized (sLock) {
34754084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka                    sInQueueSet.remove(id);
34869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                }
34969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                try {
35054084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka                    FontFamilyResult result = fetchFonts(sContext, null, request);
3515a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka                    if (result.getStatusCode() == FontFamilyResult.STATUS_OK) {
35254084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka                        Typeface typeface = buildTypeface(sContext, null, result.getFonts());
3535a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka                        if (typeface != null) {
3545a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka                            sTypefaceCache.put(id, typeface);
35569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        }
35669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    }
3575a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka                } catch (NameNotFoundException e) {
3585a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka                    // Ignore.
35969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                }
360b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            });
36154084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka            sHandler.removeCallbacks(sReplaceDispatcherThreadRunnable);
36254084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka            sHandler.postDelayed(sReplaceDispatcherThreadRunnable, THREAD_RENEWAL_THRESHOLD_MS);
363b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        }
3645a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka        return null;
365b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    }
366b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
36769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    /**
3680b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     * Interface used to receive asynchronously fetched typefaces.
3690b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     */
3700b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka    public static class FontRequestCallback {
3710b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        /**
3720b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given
3730b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * provider was not found on the device.
3740b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         */
37554084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka        public static final int FAIL_REASON_PROVIDER_NOT_FOUND = -1;
3760b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        /**
3770b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given
3780b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * provider must be authenticated and the given certificates do not match its signature.
3790b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         */
38054084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka        public static final int FAIL_REASON_WRONG_CERTIFICATES = -2;
3810b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        /**
3820b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the font
3830b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * returned by the provider was not loaded properly.
3840b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         */
3850b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        public static final int FAIL_REASON_FONT_LOAD_ERROR = -3;
3860b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        /**
3870b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the font
3880b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * provider did not return any results for the given query.
3890b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         */
3900b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        public static final int FAIL_REASON_FONT_NOT_FOUND = Columns.RESULT_CODE_FONT_NOT_FOUND;
3910b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        /**
3920b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the font
3930b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * provider found the queried font, but it is currently unavailable.
3940b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         */
3950b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        public static final int FAIL_REASON_FONT_UNAVAILABLE = Columns.RESULT_CODE_FONT_UNAVAILABLE;
3960b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        /**
3970b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given
3980b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * query was not supported by the provider.
3990b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         */
4000b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        public static final int FAIL_REASON_MALFORMED_QUERY = Columns.RESULT_CODE_MALFORMED_QUERY;
4010b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
4020b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        /** @hide */
4030b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        @IntDef({ FAIL_REASON_PROVIDER_NOT_FOUND, FAIL_REASON_FONT_LOAD_ERROR,
4040b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                FAIL_REASON_FONT_NOT_FOUND, FAIL_REASON_FONT_UNAVAILABLE,
4050b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                FAIL_REASON_MALFORMED_QUERY })
4060b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        @Retention(RetentionPolicy.SOURCE)
4070b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        @interface FontRequestFailReason {}
4080b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
4090b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        public FontRequestCallback() {}
4100b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
4110b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        /**
4125a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka         * Called then a Typeface request done via {@link #requestFont} is complete. Note that this
4135a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka         * method will not be called if {@link #onTypefaceRequestFailed(int)} is called instead.
4140b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * @param typeface  The Typeface object retrieved.
4150b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         */
4160b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        public void onTypefaceRetrieved(Typeface typeface) {}
4170b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
4180b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        /**
4195a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka         * Called when a Typeface request done via {@link #requestFont}} fails.
4200b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * @param reason One of {@link #FAIL_REASON_PROVIDER_NOT_FOUND},
4210b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         *               {@link #FAIL_REASON_FONT_NOT_FOUND},
4220b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         *               {@link #FAIL_REASON_FONT_LOAD_ERROR},
4230b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         *               {@link #FAIL_REASON_FONT_UNAVAILABLE} or
4245706a1b12dd891098fb7bf479623d42979171144Clara Bayarri         *               {@link #FAIL_REASON_MALFORMED_QUERY} if returned by the system. May also be
4255706a1b12dd891098fb7bf479623d42979171144Clara Bayarri         *               a positive value greater than 0 defined by the font provider as an
4265706a1b12dd891098fb7bf479623d42979171144Clara Bayarri         *               additional error code. Refer to the provider's documentation for more
4275706a1b12dd891098fb7bf479623d42979171144Clara Bayarri         *               information on possible returned error codes.
4280b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         */
4290b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        public void onTypefaceRequestFailed(@FontRequestFailReason int reason) {}
4300b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka    }
4310b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
4320b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka    /**
4330b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     * Create a typeface object given a font request. The font will be asynchronously fetched,
4340b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     * therefore the result is delivered to the given callback. See {@link FontRequest}.
4350b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     * Only one of the methods in callback will be invoked, depending on whether the request
4360b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     * succeeds or fails. These calls will happen on the caller thread.
437daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka     *
438daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka     * Note that the result Typeface may be cached internally and the same instance will be returned
439daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka     * the next time you call this method with the same request. If you want to bypass this cache,
440daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka     * use {@link #fetchFonts} and {@link #buildTypeface} instead.
441daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka     *
4420b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     * @param context A context to be used for fetching from font provider.
4430b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     * @param request A {@link FontRequest} object that identifies the provider and query for the
4440b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     *                request. May not be null.
4450b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     * @param callback A callback that will be triggered when results are obtained. May not be null.
4460b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     * @param handler A handler to be processed the font fetching.
4470b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     */
4480b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka    public static void requestFont(@NonNull Context context, @NonNull FontRequest request,
4490b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            @NonNull FontRequestCallback callback, @NonNull Handler handler) {
4500b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
4510b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        final Handler callerThreadHandler = new Handler();
452daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka        final Typeface cachedTypeface = sTypefaceCache.get(request.getIdentifier());
453daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka        if (cachedTypeface != null) {
454daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka            callerThreadHandler.post(() -> callback.onTypefaceRetrieved(cachedTypeface));
455daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka            return;
456daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka        }
457daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka
4580b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        handler.post(() -> {
4590b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            FontFamilyResult result;
4600b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            try {
4610b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                result = fetchFonts(context, null /* cancellation signal */, request);
4620b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            } catch (NameNotFoundException e) {
4630b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
4640b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        FontRequestCallback.FAIL_REASON_PROVIDER_NOT_FOUND));
4650b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                return;
4660b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            }
4670b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
468daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka            // Same request might be dispatched during fetchFonts. Check the cache again.
469daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka            final Typeface anotherCachedTypeface = sTypefaceCache.get(request.getIdentifier());
470daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka            if (anotherCachedTypeface != null) {
471daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka                callerThreadHandler.post(() -> callback.onTypefaceRetrieved(anotherCachedTypeface));
472daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka                return;
473daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka            }
474daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka
4750b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            if (result.getStatusCode() != FontFamilyResult.STATUS_OK) {
4760b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                switch (result.getStatusCode()) {
4770b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                    case FontFamilyResult.STATUS_WRONG_CERTIFICATES:
4780b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
4790b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                                FontRequestCallback.FAIL_REASON_WRONG_CERTIFICATES));
4800b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        return;
4810b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                    case FontFamilyResult.STATUS_UNEXPECTED_DATA_PROVIDED:
4820b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
4830b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                                FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR));
4840b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        return;
4850b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                    default:
4860b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        // fetchFont returns unexpected status type. Fallback to load error.
4870b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
4880b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                                FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR));
4890b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        return;
4900b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                }
4910b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            }
4920b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
4930b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            final FontInfo[] fonts = result.getFonts();
4940b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            if (fonts == null || fonts.length == 0) {
4950b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
4960b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        FontRequestCallback.FAIL_REASON_FONT_NOT_FOUND));
4970b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                return;
4980b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            }
4990b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            for (final FontInfo font : fonts) {
5000b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                if (font.getResultCode() != Columns.RESULT_CODE_OK) {
5010b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                    // We proceed if all font entry is ready to use. Otherwise report the first
5020b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                    // error.
5030b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                    final int resultCode = font.getResultCode();
5040b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                    if (resultCode < 0) {
5050b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        // Negative values are reserved for internal errors. Fallback to load error.
5060b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
5070b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                                FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR));
5080b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                    } else {
5090b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
5100b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                                resultCode));
5110b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                    }
5120b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                    return;
5130b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                }
5140b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            }
5150b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
5160b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            final Typeface typeface = buildTypeface(context, null /* cancellation signal */, fonts);
5170b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            if (typeface == null) {
5180b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                // Something went wrong during reading font files. This happens if the given font
5190b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                // file is an unsupported font type.
5200b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
5210b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR));
5220b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                return;
5230b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            }
5240b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
525daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka            sTypefaceCache.put(request.getIdentifier(), typeface);
5260b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            callerThreadHandler.post(() -> callback.onTypefaceRetrieved(typeface));
5270b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        });
5280b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka    }
5290b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
5300b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka    /**
53169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * Fetch fonts given a font request.
53269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
53369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param context A {@link Context} to be used for fetching fonts.
53469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param cancellationSignal A signal to cancel the operation in progress, or null if none. If
53569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                           the operation is canceled, then {@link
53669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                           android.os.OperationCanceledException} will be thrown when the
53769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                           query is executed.
53869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param request A {@link FontRequest} object that identifies the provider and query for the
53969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                request.
54069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
54169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @return {@link FontFamilyResult}
54269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
54369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @throws NameNotFoundException If requested package or authority was not found in system.
54469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     */
54569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    public static @NonNull FontFamilyResult fetchFonts(
54669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            @NonNull Context context, @Nullable CancellationSignal cancellationSignal,
54769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            @NonNull FontRequest request) throws NameNotFoundException {
548ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka        if (context.isRestricted()) {
549ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka            // TODO: Should we allow if the peer process is system or myself?
550ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka            return new FontFamilyResult(FontFamilyResult.STATUS_REJECTED, null);
551ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka        }
55269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        ProviderInfo providerInfo = getProvider(context.getPackageManager(), request);
55369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        if (providerInfo == null) {
55469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return new FontFamilyResult(FontFamilyResult.STATUS_WRONG_CERTIFICATES, null);
55569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
55669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
55769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        try {
55869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            FontInfo[] fonts = getFontFromProvider(
55969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    context, request, providerInfo.authority, cancellationSignal);
56069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return new FontFamilyResult(FontFamilyResult.STATUS_OK, fonts);
56169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        } catch (InvalidFormatException e) {
56269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return new FontFamilyResult(FontFamilyResult.STATUS_UNEXPECTED_DATA_PROVIDED, null);
56369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
56469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    }
56569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
56669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    /**
56769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * Build a Typeface from an array of {@link FontInfo}. Results that are marked as not ready
56869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * will be skipped.
56969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
57069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param context A {@link Context} that will be used to fetch the font contents.
57169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param cancellationSignal A signal to cancel the operation in progress, or null if none. If
57269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                           the operation is canceled, then {@link
57369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                           android.os.OperationCanceledException} will be thrown.
57469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param fonts An array of {@link FontInfo} to be used to create a Typeface.
57569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param weight A weight value to be used for selecting a font from a font family.
57669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param italic {@code true} if this font is of italic style. This will be used for font
57769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *               selection from a font family.
57869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param fallbackFontName A fallback font name used if this method fails to create the
57969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                         Typeface. By passing {@code null}, this method returns {@code null}
58069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                         if typeface creation fails.
58169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @return A Typeface object. May return {@code null} if that is the value passed to {@code
58269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *         fallBackFontName}.
58369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     */
58469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    public static Typeface buildTypeface(@NonNull Context context,
58569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            @Nullable CancellationSignal cancellationSignal, @NonNull FontInfo[] fonts,
58669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            int weight, boolean italic, @Nullable String fallbackFontName) {
587ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka        if (context.isRestricted()) {
588ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka            // TODO: Should we allow if the peer process is system or myself?
589ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka            return null;
590ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka        }
59169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        final Map<Uri, ByteBuffer> uriBuffer =
59269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                prepareFontData(context, fonts, cancellationSignal);
5935b6347a6af668ba47b3fab14cefbe03cc440c3a4Seigo Nonaka        return new Typeface.Builder(fonts, uriBuffer)
5945b6347a6af668ba47b3fab14cefbe03cc440c3a4Seigo Nonaka            .setFallback(fallbackFontName)
59569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            .setWeight(weight)
59669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            .setItalic(italic)
59769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            .build();
59869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    }
59969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
60069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    /**
60169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * Build a Typeface from an array of {@link FontInfo}
60269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
60369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * Results that are marked as not ready will be skipped.
60469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
60569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param context A {@link Context} that will be used to fetch the font contents.
60669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param cancellationSignal A signal to cancel the operation in progress, or null if none. If
60769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                           the operation is canceled, then {@link
60869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                           android.os.OperationCanceledException} will be thrown.
60969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param fonts An array of {@link FontInfo} to be used to create a Typeface.
61069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @return A Typeface object. Returns null if typeface creation fails.
61169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     */
61269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    public static Typeface buildTypeface(@NonNull Context context,
61369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            @Nullable CancellationSignal cancellationSignal, @NonNull FontInfo[] fonts) {
614ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka        if (context.isRestricted()) {
615ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka            // TODO: Should we allow if the peer process is system or myself?
616ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka            return null;
617ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka        }
61869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        final Map<Uri, ByteBuffer> uriBuffer =
61969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                prepareFontData(context, fonts, cancellationSignal);
62069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        return new Typeface.Builder(fonts, uriBuffer).build();
62169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    }
62269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
62369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    /**
62469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * A helper function to create a mapping from {@link Uri} to {@link ByteBuffer}.
62569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
62669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * Skip if the file contents is not ready to be read.
62769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
62869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param context A {@link Context} to be used for resolving content URI in
62969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                {@link FontInfo}.
63069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param fonts An array of {@link FontInfo}.
63169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @return A map from {@link Uri} to {@link ByteBuffer}.
63269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     */
63369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    private static Map<Uri, ByteBuffer> prepareFontData(Context context, FontInfo[] fonts,
63469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            CancellationSignal cancellationSignal) {
63569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        final HashMap<Uri, ByteBuffer> out = new HashMap<>();
63669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        final ContentResolver resolver = context.getContentResolver();
63769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
63869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        for (FontInfo font : fonts) {
63969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            if (font.getResultCode() != Columns.RESULT_CODE_OK) {
64069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                continue;
64169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            }
64269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
64369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            final Uri uri = font.getUri();
64469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            if (out.containsKey(uri)) {
64569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                continue;
64669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            }
64769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
64869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            ByteBuffer buffer = null;
64969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            try (final ParcelFileDescriptor pfd =
65069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    resolver.openFileDescriptor(uri, "r", cancellationSignal);
65169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    final FileInputStream fis = new FileInputStream(pfd.getFileDescriptor())) {
65269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                final FileChannel fileChannel = fis.getChannel();
65369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                final long size = fileChannel.size();
65469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                buffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, size);
65569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            } catch (IOException e) {
65669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                // ignore
65769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            }
65869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
65969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            // TODO: try other approach?, e.g. read all contents instead of mmap.
66069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
66169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            out.put(uri, buffer);
66269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
66369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        return Collections.unmodifiableMap(out);
66469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    }
66569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
6663c4be77db95ea716889568bde853be082e764da9Clara Bayarri    /** @hide */
6673c4be77db95ea716889568bde853be082e764da9Clara Bayarri    @VisibleForTesting
66869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    public static @Nullable ProviderInfo getProvider(
66969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            PackageManager packageManager, FontRequest request) throws NameNotFoundException {
6703c4be77db95ea716889568bde853be082e764da9Clara Bayarri        String providerAuthority = request.getProviderAuthority();
67169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        ProviderInfo info = packageManager.resolveContentProvider(providerAuthority, 0);
6723c4be77db95ea716889568bde853be082e764da9Clara Bayarri        if (info == null) {
67369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            throw new NameNotFoundException("No package found for authority: " + providerAuthority);
6743c4be77db95ea716889568bde853be082e764da9Clara Bayarri        }
6753c4be77db95ea716889568bde853be082e764da9Clara Bayarri
6763c4be77db95ea716889568bde853be082e764da9Clara Bayarri        if (!info.packageName.equals(request.getProviderPackage())) {
67769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            throw new NameNotFoundException("Found content provider " + providerAuthority
67869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    + ", but package was not " + request.getProviderPackage());
6793c4be77db95ea716889568bde853be082e764da9Clara Bayarri        }
6803c4be77db95ea716889568bde853be082e764da9Clara Bayarri        // Trust system apps without signature checks
6813c4be77db95ea716889568bde853be082e764da9Clara Bayarri        if (info.applicationInfo.isSystemApp()) {
6823c4be77db95ea716889568bde853be082e764da9Clara Bayarri            return info;
6833c4be77db95ea716889568bde853be082e764da9Clara Bayarri        }
6843c4be77db95ea716889568bde853be082e764da9Clara Bayarri
685fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        List<byte[]> signatures;
68669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        PackageInfo packageInfo = packageManager.getPackageInfo(info.packageName,
68769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                PackageManager.GET_SIGNATURES);
68869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        signatures = convertToByteArrayList(packageInfo.signatures);
68969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        Collections.sort(signatures, sByteArrayComparator);
69069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
6913c4be77db95ea716889568bde853be082e764da9Clara Bayarri        List<List<byte[]>> requestCertificatesList = request.getCertificates();
6923c4be77db95ea716889568bde853be082e764da9Clara Bayarri        for (int i = 0; i < requestCertificatesList.size(); ++i) {
693fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            // Make a copy so we can sort it without modifying the incoming data.
694fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            List<byte[]> requestSignatures = new ArrayList<>(requestCertificatesList.get(i));
695fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            Collections.sort(requestSignatures, sByteArrayComparator);
696fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            if (equalsByteArrayList(signatures, requestSignatures)) {
6973c4be77db95ea716889568bde853be082e764da9Clara Bayarri                return info;
6983c4be77db95ea716889568bde853be082e764da9Clara Bayarri            }
6993c4be77db95ea716889568bde853be082e764da9Clara Bayarri        }
7003c4be77db95ea716889568bde853be082e764da9Clara Bayarri        return null;
7013c4be77db95ea716889568bde853be082e764da9Clara Bayarri    }
7023c4be77db95ea716889568bde853be082e764da9Clara Bayarri
703fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri    private static final Comparator<byte[]> sByteArrayComparator = (l, r) -> {
704fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        if (l.length != r.length) {
705fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            return l.length - r.length;
7063c4be77db95ea716889568bde853be082e764da9Clara Bayarri        }
707fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        for (int i = 0; i < l.length; ++i) {
708fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            if (l[i] != r[i]) {
709fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri                return l[i] - r[i];
710fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            }
711fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        }
712fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        return 0;
713fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri    };
714fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri
71569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    private static boolean equalsByteArrayList(
71669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            List<byte[]> signatures, List<byte[]> requestSignatures) {
717fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        if (signatures.size() != requestSignatures.size()) {
718fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            return false;
719fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        }
720fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        for (int i = 0; i < signatures.size(); ++i) {
721fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            if (!Arrays.equals(signatures.get(i), requestSignatures.get(i))) {
722fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri                return false;
723fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            }
724fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        }
725fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        return true;
7263c4be77db95ea716889568bde853be082e764da9Clara Bayarri    }
7273c4be77db95ea716889568bde853be082e764da9Clara Bayarri
72869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    private static List<byte[]> convertToByteArrayList(Signature[] signatures) {
729fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        List<byte[]> shas = new ArrayList<>();
730fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        for (int i = 0; i < signatures.length; ++i) {
731fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            shas.add(signatures[i].toByteArray());
732fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        }
7333c4be77db95ea716889568bde853be082e764da9Clara Bayarri        return shas;
7343c4be77db95ea716889568bde853be082e764da9Clara Bayarri    }
7353c4be77db95ea716889568bde853be082e764da9Clara Bayarri
7363c4be77db95ea716889568bde853be082e764da9Clara Bayarri    /** @hide */
7373c4be77db95ea716889568bde853be082e764da9Clara Bayarri    @VisibleForTesting
73869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    public static @NonNull FontInfo[] getFontFromProvider(
73969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            Context context, FontRequest request, String authority,
74069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            CancellationSignal cancellationSignal) throws InvalidFormatException {
74169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        ArrayList<FontInfo> result = new ArrayList<>();
74243c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka        final Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
7433c4be77db95ea716889568bde853be082e764da9Clara Bayarri                .authority(authority)
744b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                .build();
74543c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka        final Uri fileBaseUri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
74643c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                .authority(authority)
74743c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                .appendPath("file")
74843c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                .build();
74969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        try (Cursor cursor = context.getContentResolver().query(uri, new String[] { Columns._ID,
75043c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                        Columns.FILE_ID, Columns.TTC_INDEX, Columns.VARIATION_SETTINGS,
75154084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka                        Columns.WEIGHT, Columns.ITALIC, Columns.RESULT_CODE },
75269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                "query = ?", new String[] { request.getQuery() }, null, cancellationSignal);) {
753b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            // TODO: Should we restrict the amount of fonts that can be returned?
754b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            // TODO: Write documentation explaining that all results should be from the same family.
755b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            if (cursor != null && cursor.getCount() > 0) {
756bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                final int resultCodeColumnIndex = cursor.getColumnIndex(Columns.RESULT_CODE);
757b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                result = new ArrayList<>();
758bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                final int idColumnIndex = cursor.getColumnIndexOrThrow(Columns._ID);
75943c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                final int fileIdColumnIndex = cursor.getColumnIndex(Columns.FILE_ID);
760b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                final int ttcIndexColumnIndex = cursor.getColumnIndex(Columns.TTC_INDEX);
761b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                final int vsColumnIndex = cursor.getColumnIndex(Columns.VARIATION_SETTINGS);
762fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka                final int weightColumnIndex = cursor.getColumnIndex(Columns.WEIGHT);
763fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka                final int italicColumnIndex = cursor.getColumnIndex(Columns.ITALIC);
764b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                while (cursor.moveToNext()) {
76569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    int resultCode = resultCodeColumnIndex != -1
766bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                            ? cursor.getInt(resultCodeColumnIndex) : Columns.RESULT_CODE_OK;
76769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    final int ttcIndex = ttcIndexColumnIndex != -1
76869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                            ? cursor.getInt(ttcIndexColumnIndex) : 0;
76969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    final String variationSettings = vsColumnIndex != -1
77069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                            ? cursor.getString(vsColumnIndex) : null;
77169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
77243c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                    Uri fileUri;
77343c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                    if (fileIdColumnIndex == -1) {
77443c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                        long id = cursor.getLong(idColumnIndex);
77543c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                        fileUri = ContentUris.withAppendedId(uri, id);
77643c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                    } else {
77743c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                        long id = cursor.getLong(fileIdColumnIndex);
77843c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                        fileUri = ContentUris.withAppendedId(fileBaseUri, id);
77943c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                    }
78069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    int weight;
78169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    boolean italic;
78269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    if (weightColumnIndex != -1 && italicColumnIndex != -1) {
78369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        weight = cursor.getInt(weightColumnIndex);
78469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        italic = cursor.getInt(italicColumnIndex) == 1;
78569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    } else {
78669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        weight = Typeface.Builder.NORMAL_WEIGHT;
78769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        italic = false;
788b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                    }
78969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    FontVariationAxis[] axes =
79069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                            FontVariationAxis.fromFontVariationSettings(variationSettings);
79169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    result.add(new FontInfo(fileUri, ttcIndex, axes, weight, italic, resultCode));
792b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                }
793b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            }
794b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        }
79569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        return result.toArray(new FontInfo[0]);
796b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    }
797b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri}
798