FontsContract.java revision d9de8be233d18ccc881cb647a5de2b32ff3e737c
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;
68d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonakaimport java.util.concurrent.TimeUnit;
69d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonakaimport java.util.concurrent.locks.Condition;
70d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonakaimport java.util.concurrent.locks.Lock;
71d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonakaimport java.util.concurrent.locks.ReentrantLock;
72d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonakaimport java.util.concurrent.atomic.AtomicBoolean;
73d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonakaimport java.util.concurrent.atomic.AtomicReference;
74b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
75b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri/**
76b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * Utility class to deal with Font ContentProviders.
77b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri */
78b0812a30499376e09e2deb5995e998c629f24985Clara Bayarripublic class FontsContract {
79b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    private static final String TAG = "FontsContract";
80b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
81b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    /**
82b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     * Defines the constants used in a response from a Font Provider. The cursor returned from the
83b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     * query should have the ID column populated with the content uri ID for the resulting font.
84b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     * This should point to a real file or shared memory, as the client will mmap the given file
85b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     * descriptor. Pipes, sockets and other non-mmap-able file descriptors will fail to load in the
86b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     * client application.
87b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     */
88b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    public static final class Columns implements BaseColumns {
897fea2e264e2e793586bb999ee80897d488e62141Clara Bayarri
907fea2e264e2e793586bb999ee80897d488e62141Clara Bayarri        // Do not instantiate.
917fea2e264e2e793586bb999ee80897d488e62141Clara Bayarri        private Columns() {}
927fea2e264e2e793586bb999ee80897d488e62141Clara Bayarri
93b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        /**
94b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri         * Constant used to request data from a font provider. The cursor returned from the query
9543c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka         * may populate this column with a long for the font file ID. The client will request a file
9643c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka         * descriptor to "file/FILE_ID" with this ID immediately under the top-level content URI. If
9743c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka         * not present, the client will request a file descriptor to the top-level URI with the
9843c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka         * given base font ID. Note that several results may return the same file ID, e.g. for TTC
9943c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka         * files with different indices.
10043c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka         */
10143c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka        public static final String FILE_ID = "file_id";
10243c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka        /**
10343c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka         * Constant used to request data from a font provider. The cursor returned from the query
104b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri         * should have this column populated with an int for the ttc index for the resulting font.
105b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri         */
106b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        public static final String TTC_INDEX = "font_ttc_index";
107b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        /**
108b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri         * Constant used to request data from a font provider. The cursor returned from the query
109b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri         * may populate this column with the font variation settings String information for the
110b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri         * font.
111b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri         */
112b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        public static final String VARIATION_SETTINGS = "font_variation_settings";
113b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        /**
114bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * Constant used to request data from a font provider. The cursor returned from the query
115fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * should have this column populated with the int weight for the resulting font. This value
116fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * should be between 100 and 900. The most common values are 400 for regular weight and 700
117fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * for bold weight.
118fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         */
119fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka        public static final String WEIGHT = "font_weight";
120fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka        /**
121fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * Constant used to request data from a font provider. The cursor returned from the query
122fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * should have this column populated with the int italic for the resulting font. This should
123fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * be 0 for regular style and 1 for italic.
124fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         */
125fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka        public static final String ITALIC = "font_italic";
126fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka        /**
127fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * Constant used to request data from a font provider. The cursor returned from the query
128bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * should have this column populated to indicate the result status of the
129bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * query. This will be checked before any other data in the cursor. Possible values are
130bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * {@link #RESULT_CODE_OK}, {@link #RESULT_CODE_FONT_NOT_FOUND},
1315706a1b12dd891098fb7bf479623d42979171144Clara Bayarri         * {@link #RESULT_CODE_MALFORMED_QUERY} and {@link #RESULT_CODE_FONT_UNAVAILABLE} for system
1325706a1b12dd891098fb7bf479623d42979171144Clara Bayarri         * defined values. You may also define your own values in the 0x000010000..0xFFFF0000 range.
1335706a1b12dd891098fb7bf479623d42979171144Clara Bayarri         * If not present, {@link #RESULT_CODE_OK} will be assumed.
134bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         */
135bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        public static final String RESULT_CODE = "result_code";
136bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri
137bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        /**
138bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * Constant used to represent a result was retrieved successfully. The given fonts will be
139bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * attempted to retrieve immediately via
140bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * {@link android.content.ContentProvider#openFile(Uri, String)}. See {@link #RESULT_CODE}.
141bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         */
142bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        public static final int RESULT_CODE_OK = 0;
143bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        /**
144bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * Constant used to represent a result was not found. See {@link #RESULT_CODE}.
145bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         */
146bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        public static final int RESULT_CODE_FONT_NOT_FOUND = 1;
147bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        /**
148bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * Constant used to represent a result was found, but cannot be provided at this moment. Use
149bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * this to indicate, for example, that a font needs to be fetched from the network. See
150bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * {@link #RESULT_CODE}.
151bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         */
152bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        public static final int RESULT_CODE_FONT_UNAVAILABLE = 2;
153bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        /**
154bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * Constant used to represent that the query was not in a supported format by the provider.
155bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * See {@link #RESULT_CODE}.
156bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         */
157bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        public static final int RESULT_CODE_MALFORMED_QUERY = 3;
158b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    }
159b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
16054084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka    private static final Object sLock = new Object();
16154084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka    @GuardedBy("sLock")
16254084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka    private static Handler sHandler;
16354084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka    @GuardedBy("sLock")
16454084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka    private static HandlerThread sThread;
16554084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka    @GuardedBy("sLock")
16654084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka    private static Set<String> sInQueueSet;
167b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
16854084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka    private volatile static Context sContext;  // set once in setApplicationContextForResources
169b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
170daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka    private static final LruCache<String, Typeface> sTypefaceCache = new LruCache<>(16);
171daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka
17254084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka    private FontsContract() {
17354084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka    }
17454084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka
175b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    /** @hide */
17654084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka    public static void setApplicationContextForResources(Context context) {
17754084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka        sContext = context.getApplicationContext();
178b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    }
179b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
18069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    /**
18169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * Object represent a font entry in the family returned from {@link #fetchFonts}.
18269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     */
18369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    public static class FontInfo {
18469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        private final Uri mUri;
18569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        private final int mTtcIndex;
18669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        private final FontVariationAxis[] mAxes;
18769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        private final int mWeight;
18869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        private final boolean mItalic;
18969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        private final int mResultCode;
19069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
19169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /**
19269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * Creates a Font with all the information needed about a provided font.
19369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * @param uri A URI associated to the font file.
19469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * @param ttcIndex If providing a TTC_INDEX file, the index to point to. Otherwise, 0.
19569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * @param axes If providing a variation font, the settings for it. May be null.
19669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * @param weight An integer that indicates the font weight.
19769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * @param italic A boolean that indicates the font is italic style or not.
19869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * @param resultCode A boolean that indicates the font contents is ready.
19969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         */
20069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /** @hide */
20169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public FontInfo(@NonNull Uri uri, @IntRange(from = 0) int ttcIndex,
20269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                @Nullable FontVariationAxis[] axes, @IntRange(from = 1, to = 1000) int weight,
20369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                boolean italic, int resultCode) {
20469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            mUri = Preconditions.checkNotNull(uri);
20569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            mTtcIndex = ttcIndex;
20669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            mAxes = axes;
20769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            mWeight = weight;
20869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            mItalic = italic;
20969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            mResultCode = resultCode;
21069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
21169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
21269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /**
21369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * Returns a URI associated to this record.
21469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         */
21569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public @NonNull Uri getUri() {
21669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return mUri;
21769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
21869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
21969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /**
22069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * Returns the index to be used to access this font when accessing a TTC file.
22169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         */
22269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public @IntRange(from = 0) int getTtcIndex() {
22369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return mTtcIndex;
22469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
22569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
22669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /**
22769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * Returns the list of axes associated to this font.
22869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         */
22969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public @Nullable FontVariationAxis[] getAxes() {
23069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return mAxes;
23169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
23269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
23369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /**
23469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * Returns the weight value for this font.
23569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         */
23669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public @IntRange(from = 1, to = 1000) int getWeight() {
23769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return mWeight;
23869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
23969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
24069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /**
24169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * Returns whether this font is italic.
24269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         */
24369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public boolean isItalic() {
24469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return mItalic;
24569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
24669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
24769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /**
24869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * Returns result code.
24969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         *
25069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * {@link FontsContract.Columns#RESULT_CODE}
25169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         */
25269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public int getResultCode() {
25369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return mResultCode;
25469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
25569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    }
25669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
25769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    /**
25869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * Object returned from {@link #fetchFonts}.
25969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     */
26069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    public static class FontFamilyResult {
26169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /**
26269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * Constant represents that the font was successfully retrieved. Note that when this value
26369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * is set and {@link #getFonts} returns an empty array, it means there were no fonts
26469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * matching the given query.
26569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         */
26669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public static final int STATUS_OK = 0;
26769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
26869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /**
26969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * Constant represents that the given certificate was not matched with the provider's
27069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * signature. {@link #getFonts} returns null if this status was set.
27169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         */
27269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public static final int STATUS_WRONG_CERTIFICATES = 1;
27369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
27469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /**
27569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * Constant represents that the provider returns unexpected data. {@link #getFonts} returns
27669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * null if this status was set. For example, this value is set when the font provider
27769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * gives invalid format of variation settings.
27869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         */
27969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public static final int STATUS_UNEXPECTED_DATA_PROVIDED = 2;
28069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
281ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka        /**
282ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka         * Constant represents that the fetching font data was rejected by system. This happens if
283ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka         * the passed context is restricted.
284ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka         */
285ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka        public static final int STATUS_REJECTED = 3;
286ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka
28769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /** @hide */
28869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        @IntDef({STATUS_OK, STATUS_WRONG_CERTIFICATES, STATUS_UNEXPECTED_DATA_PROVIDED})
28969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        @Retention(RetentionPolicy.SOURCE)
29069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        @interface FontResultStatus {}
29169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
29269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        private final @FontResultStatus int mStatusCode;
29369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        private final FontInfo[] mFonts;
29469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
29569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /** @hide */
29669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public FontFamilyResult(@FontResultStatus int statusCode, @Nullable FontInfo[] fonts) {
29769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            mStatusCode = statusCode;
29869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            mFonts = fonts;
29969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
30069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
30169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public @FontResultStatus int getStatusCode() {
30269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return mStatusCode;
30369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
30469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
30569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public @NonNull FontInfo[] getFonts() {
30669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return mFonts;
30769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
3083c4be77db95ea716889568bde853be082e764da9Clara Bayarri    }
3093c4be77db95ea716889568bde853be082e764da9Clara Bayarri
31054084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka    private static final int THREAD_RENEWAL_THRESHOLD_MS = 10000;
31154084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka
312d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka    private static final long SYNC_FONT_FETCH_TIMEOUT_MS = 500;
313d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka
314b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    // We use a background thread to post the content resolving work for all requests on. This
315b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    // thread should be quit/stopped after all requests are done.
31654084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka    // TODO: Factor out to other class. Consider to switch MessageQueue.IdleHandler.
31754084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka    private static final Runnable sReplaceDispatcherThreadRunnable = new Runnable() {
318b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        @Override
319b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        public void run() {
32054084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka            synchronized (sLock) {
32154084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka                if (sThread != null) {
32254084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka                    sThread.quitSafely();
32354084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka                    sThread = null;
32454084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka                    sHandler = null;
325b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                }
326b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            }
327b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        }
328b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    };
329b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
330bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri    /** @hide */
331d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka    public static Typeface getFontSync(FontRequest request) {
3325a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka        final String id = request.getIdentifier();
3335a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka        Typeface cachedTypeface = sTypefaceCache.get(id);
3345a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka        if (cachedTypeface != null) {
3355a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka            return cachedTypeface;
3365a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka        }
3375a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka
3385a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka        // Unfortunately the typeface is not available at this time, but requesting from the font
3395a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka        // provider takes too much time. For now, request the font data to ensure it is in the cache
3405a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka        // next time and return.
34154084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka        synchronized (sLock) {
34254084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka            if (sHandler == null) {
34354084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka                sThread = new HandlerThread("fonts", Process.THREAD_PRIORITY_BACKGROUND);
34454084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka                sThread.start();
34554084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka                sHandler = new Handler(sThread.getLooper());
3465a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka            }
347d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka            final Lock lock = new ReentrantLock();
348d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka            final Condition cond = lock.newCondition();
349d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka            final AtomicReference<Typeface> holder = new AtomicReference<>();
350d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka            final AtomicBoolean waiting = new AtomicBoolean(true);
351d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka            final AtomicBoolean timeout = new AtomicBoolean(false);
352d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka
35354084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka            sHandler.post(() -> {
35469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                try {
35554084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka                    FontFamilyResult result = fetchFonts(sContext, null, request);
3565a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka                    if (result.getStatusCode() == FontFamilyResult.STATUS_OK) {
35754084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka                        Typeface typeface = buildTypeface(sContext, null, result.getFonts());
3585a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka                        if (typeface != null) {
3595a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka                            sTypefaceCache.put(id, typeface);
36069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        }
361d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                        holder.set(typeface);
36269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    }
3635a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka                } catch (NameNotFoundException e) {
3645a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka                    // Ignore.
36569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                }
366d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                lock.lock();
367d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                try {
368d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                    if (!timeout.get()) {
369d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                      waiting.set(false);
370d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                      cond.signal();
371d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                    }
372d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                } finally {
373d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                    lock.unlock();
374d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                }
375b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            });
37654084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka            sHandler.removeCallbacks(sReplaceDispatcherThreadRunnable);
37754084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka            sHandler.postDelayed(sReplaceDispatcherThreadRunnable, THREAD_RENEWAL_THRESHOLD_MS);
378d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka
379d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka            long remaining = TimeUnit.MILLISECONDS.toNanos(SYNC_FONT_FETCH_TIMEOUT_MS);
380d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka            lock.lock();
381d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka            try {
382d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                if (!waiting.get()) {
383d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                    return holder.get();
384d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                }
385d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                for (;;) {
386d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                    try {
387d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                        remaining = cond.awaitNanos(remaining);
388d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                    } catch (InterruptedException e) {
389d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                        // do nothing.
390d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                    }
391d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                    if (!waiting.get()) {
392d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                        return holder.get();
393d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                    }
394d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                    if (remaining <= 0) {
395d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                        timeout.set(true);
396d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                        Log.w(TAG, "Remote font fetch timed out: " +
397d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                                request.getProviderAuthority() + "/" + request.getQuery());
398d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                        return null;
399d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                    }
400d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                }
401d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka            } finally {
402d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                lock.unlock();
403d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka            }
404b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        }
405b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    }
406b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
40769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    /**
4080b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     * Interface used to receive asynchronously fetched typefaces.
4090b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     */
4100b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka    public static class FontRequestCallback {
4110b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        /**
4120b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given
4130b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * provider was not found on the device.
4140b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         */
41554084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka        public static final int FAIL_REASON_PROVIDER_NOT_FOUND = -1;
4160b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        /**
4170b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given
4180b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * provider must be authenticated and the given certificates do not match its signature.
4190b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         */
42054084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka        public static final int FAIL_REASON_WRONG_CERTIFICATES = -2;
4210b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        /**
4220b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the font
4230b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * returned by the provider was not loaded properly.
4240b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         */
4250b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        public static final int FAIL_REASON_FONT_LOAD_ERROR = -3;
4260b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        /**
4270b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the font
4280b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * provider did not return any results for the given query.
4290b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         */
4300b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        public static final int FAIL_REASON_FONT_NOT_FOUND = Columns.RESULT_CODE_FONT_NOT_FOUND;
4310b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        /**
4320b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the font
4330b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * provider found the queried font, but it is currently unavailable.
4340b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         */
4350b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        public static final int FAIL_REASON_FONT_UNAVAILABLE = Columns.RESULT_CODE_FONT_UNAVAILABLE;
4360b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        /**
4370b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given
4380b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * query was not supported by the provider.
4390b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         */
4400b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        public static final int FAIL_REASON_MALFORMED_QUERY = Columns.RESULT_CODE_MALFORMED_QUERY;
4410b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
4420b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        /** @hide */
4430b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        @IntDef({ FAIL_REASON_PROVIDER_NOT_FOUND, FAIL_REASON_FONT_LOAD_ERROR,
4440b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                FAIL_REASON_FONT_NOT_FOUND, FAIL_REASON_FONT_UNAVAILABLE,
4450b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                FAIL_REASON_MALFORMED_QUERY })
4460b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        @Retention(RetentionPolicy.SOURCE)
4470b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        @interface FontRequestFailReason {}
4480b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
4490b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        public FontRequestCallback() {}
4500b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
4510b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        /**
4525a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka         * Called then a Typeface request done via {@link #requestFont} is complete. Note that this
4535a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka         * method will not be called if {@link #onTypefaceRequestFailed(int)} is called instead.
4540b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * @param typeface  The Typeface object retrieved.
4550b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         */
4560b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        public void onTypefaceRetrieved(Typeface typeface) {}
4570b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
4580b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        /**
4595a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka         * Called when a Typeface request done via {@link #requestFont}} fails.
4600b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * @param reason One of {@link #FAIL_REASON_PROVIDER_NOT_FOUND},
4610b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         *               {@link #FAIL_REASON_FONT_NOT_FOUND},
4620b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         *               {@link #FAIL_REASON_FONT_LOAD_ERROR},
4630b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         *               {@link #FAIL_REASON_FONT_UNAVAILABLE} or
4645706a1b12dd891098fb7bf479623d42979171144Clara Bayarri         *               {@link #FAIL_REASON_MALFORMED_QUERY} if returned by the system. May also be
4655706a1b12dd891098fb7bf479623d42979171144Clara Bayarri         *               a positive value greater than 0 defined by the font provider as an
4665706a1b12dd891098fb7bf479623d42979171144Clara Bayarri         *               additional error code. Refer to the provider's documentation for more
4675706a1b12dd891098fb7bf479623d42979171144Clara Bayarri         *               information on possible returned error codes.
4680b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         */
4690b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        public void onTypefaceRequestFailed(@FontRequestFailReason int reason) {}
4700b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka    }
4710b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
4720b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka    /**
4730b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     * Create a typeface object given a font request. The font will be asynchronously fetched,
4740b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     * therefore the result is delivered to the given callback. See {@link FontRequest}.
4750b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     * Only one of the methods in callback will be invoked, depending on whether the request
4760b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     * succeeds or fails. These calls will happen on the caller thread.
477daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka     *
478daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka     * Note that the result Typeface may be cached internally and the same instance will be returned
479daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka     * the next time you call this method with the same request. If you want to bypass this cache,
480daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka     * use {@link #fetchFonts} and {@link #buildTypeface} instead.
481daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka     *
4820b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     * @param context A context to be used for fetching from font provider.
4830b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     * @param request A {@link FontRequest} object that identifies the provider and query for the
4840b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     *                request. May not be null.
4850b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     * @param callback A callback that will be triggered when results are obtained. May not be null.
4860b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     * @param handler A handler to be processed the font fetching.
4870b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     */
4880b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka    public static void requestFont(@NonNull Context context, @NonNull FontRequest request,
4890b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            @NonNull FontRequestCallback callback, @NonNull Handler handler) {
4900b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
4910b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        final Handler callerThreadHandler = new Handler();
492daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka        final Typeface cachedTypeface = sTypefaceCache.get(request.getIdentifier());
493daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka        if (cachedTypeface != null) {
494daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka            callerThreadHandler.post(() -> callback.onTypefaceRetrieved(cachedTypeface));
495daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka            return;
496daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka        }
497daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka
4980b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        handler.post(() -> {
4990b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            FontFamilyResult result;
5000b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            try {
5010b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                result = fetchFonts(context, null /* cancellation signal */, request);
5020b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            } catch (NameNotFoundException e) {
5030b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
5040b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        FontRequestCallback.FAIL_REASON_PROVIDER_NOT_FOUND));
5050b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                return;
5060b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            }
5070b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
508daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka            // Same request might be dispatched during fetchFonts. Check the cache again.
509daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka            final Typeface anotherCachedTypeface = sTypefaceCache.get(request.getIdentifier());
510daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka            if (anotherCachedTypeface != null) {
511daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka                callerThreadHandler.post(() -> callback.onTypefaceRetrieved(anotherCachedTypeface));
512daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka                return;
513daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka            }
514daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka
5150b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            if (result.getStatusCode() != FontFamilyResult.STATUS_OK) {
5160b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                switch (result.getStatusCode()) {
5170b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                    case FontFamilyResult.STATUS_WRONG_CERTIFICATES:
5180b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
5190b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                                FontRequestCallback.FAIL_REASON_WRONG_CERTIFICATES));
5200b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        return;
5210b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                    case FontFamilyResult.STATUS_UNEXPECTED_DATA_PROVIDED:
5220b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
5230b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                                FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR));
5240b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        return;
5250b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                    default:
5260b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        // fetchFont returns unexpected status type. Fallback to load error.
5270b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
5280b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                                FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR));
5290b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        return;
5300b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                }
5310b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            }
5320b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
5330b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            final FontInfo[] fonts = result.getFonts();
5340b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            if (fonts == null || fonts.length == 0) {
5350b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
5360b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        FontRequestCallback.FAIL_REASON_FONT_NOT_FOUND));
5370b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                return;
5380b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            }
5390b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            for (final FontInfo font : fonts) {
5400b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                if (font.getResultCode() != Columns.RESULT_CODE_OK) {
5410b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                    // We proceed if all font entry is ready to use. Otherwise report the first
5420b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                    // error.
5430b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                    final int resultCode = font.getResultCode();
5440b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                    if (resultCode < 0) {
5450b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        // Negative values are reserved for internal errors. Fallback to load error.
5460b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
5470b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                                FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR));
5480b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                    } else {
5490b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
5500b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                                resultCode));
5510b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                    }
5520b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                    return;
5530b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                }
5540b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            }
5550b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
5560b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            final Typeface typeface = buildTypeface(context, null /* cancellation signal */, fonts);
5570b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            if (typeface == null) {
5580b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                // Something went wrong during reading font files. This happens if the given font
5590b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                // file is an unsupported font type.
5600b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
5610b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR));
5620b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                return;
5630b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            }
5640b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
565daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka            sTypefaceCache.put(request.getIdentifier(), typeface);
5660b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            callerThreadHandler.post(() -> callback.onTypefaceRetrieved(typeface));
5670b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        });
5680b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka    }
5690b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
5700b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka    /**
57169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * Fetch fonts given a font request.
57269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
57369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param context A {@link Context} to be used for fetching fonts.
57469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param cancellationSignal A signal to cancel the operation in progress, or null if none. If
57569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                           the operation is canceled, then {@link
57669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                           android.os.OperationCanceledException} will be thrown when the
57769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                           query is executed.
57869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param request A {@link FontRequest} object that identifies the provider and query for the
57969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                request.
58069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
58169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @return {@link FontFamilyResult}
58269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
58369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @throws NameNotFoundException If requested package or authority was not found in system.
58469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     */
58569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    public static @NonNull FontFamilyResult fetchFonts(
58669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            @NonNull Context context, @Nullable CancellationSignal cancellationSignal,
58769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            @NonNull FontRequest request) throws NameNotFoundException {
588ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka        if (context.isRestricted()) {
589ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka            // TODO: Should we allow if the peer process is system or myself?
590ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka            return new FontFamilyResult(FontFamilyResult.STATUS_REJECTED, null);
591ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka        }
59269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        ProviderInfo providerInfo = getProvider(context.getPackageManager(), request);
59369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        if (providerInfo == null) {
59469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return new FontFamilyResult(FontFamilyResult.STATUS_WRONG_CERTIFICATES, null);
59569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
59669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
59769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        try {
59869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            FontInfo[] fonts = getFontFromProvider(
59969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    context, request, providerInfo.authority, cancellationSignal);
60069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return new FontFamilyResult(FontFamilyResult.STATUS_OK, fonts);
60169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        } catch (InvalidFormatException e) {
60269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return new FontFamilyResult(FontFamilyResult.STATUS_UNEXPECTED_DATA_PROVIDED, null);
60369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
60469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    }
60569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
60669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    /**
60769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * Build a Typeface from an array of {@link FontInfo}. Results that are marked as not ready
60869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * will be skipped.
60969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
61069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param context A {@link Context} that will be used to fetch the font contents.
61169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param cancellationSignal A signal to cancel the operation in progress, or null if none. If
61269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                           the operation is canceled, then {@link
61369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                           android.os.OperationCanceledException} will be thrown.
61469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param fonts An array of {@link FontInfo} to be used to create a Typeface.
61569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param weight A weight value to be used for selecting a font from a font family.
61669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param italic {@code true} if this font is of italic style. This will be used for font
61769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *               selection from a font family.
61869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param fallbackFontName A fallback font name used if this method fails to create the
61969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                         Typeface. By passing {@code null}, this method returns {@code null}
62069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                         if typeface creation fails.
62169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @return A Typeface object. May return {@code null} if that is the value passed to {@code
62269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *         fallBackFontName}.
62369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     */
62469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    public static Typeface buildTypeface(@NonNull Context context,
62569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            @Nullable CancellationSignal cancellationSignal, @NonNull FontInfo[] fonts,
62669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            int weight, boolean italic, @Nullable String fallbackFontName) {
627ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka        if (context.isRestricted()) {
628ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka            // TODO: Should we allow if the peer process is system or myself?
629ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka            return null;
630ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka        }
63169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        final Map<Uri, ByteBuffer> uriBuffer =
63269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                prepareFontData(context, fonts, cancellationSignal);
633d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka        if (uriBuffer.isEmpty()) {
634d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka            return null;
635d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka        }
6365b6347a6af668ba47b3fab14cefbe03cc440c3a4Seigo Nonaka        return new Typeface.Builder(fonts, uriBuffer)
6375b6347a6af668ba47b3fab14cefbe03cc440c3a4Seigo Nonaka            .setFallback(fallbackFontName)
63869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            .setWeight(weight)
63969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            .setItalic(italic)
64069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            .build();
64169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    }
64269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
64369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    /**
64469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * Build a Typeface from an array of {@link FontInfo}
64569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
64669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * Results that are marked as not ready will be skipped.
64769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
64869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param context A {@link Context} that will be used to fetch the font contents.
64969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param cancellationSignal A signal to cancel the operation in progress, or null if none. If
65069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                           the operation is canceled, then {@link
65169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                           android.os.OperationCanceledException} will be thrown.
65269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param fonts An array of {@link FontInfo} to be used to create a Typeface.
65369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @return A Typeface object. Returns null if typeface creation fails.
65469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     */
65569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    public static Typeface buildTypeface(@NonNull Context context,
65669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            @Nullable CancellationSignal cancellationSignal, @NonNull FontInfo[] fonts) {
657ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka        if (context.isRestricted()) {
658ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka            // TODO: Should we allow if the peer process is system or myself?
659ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka            return null;
660ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka        }
66169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        final Map<Uri, ByteBuffer> uriBuffer =
66269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                prepareFontData(context, fonts, cancellationSignal);
663d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka        if (uriBuffer.isEmpty()) {
664d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka            return null;
665d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka        }
66669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        return new Typeface.Builder(fonts, uriBuffer).build();
66769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    }
66869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
66969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    /**
67069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * A helper function to create a mapping from {@link Uri} to {@link ByteBuffer}.
67169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
67269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * Skip if the file contents is not ready to be read.
67369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
67469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param context A {@link Context} to be used for resolving content URI in
67569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                {@link FontInfo}.
67669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param fonts An array of {@link FontInfo}.
67769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @return A map from {@link Uri} to {@link ByteBuffer}.
67869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     */
67969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    private static Map<Uri, ByteBuffer> prepareFontData(Context context, FontInfo[] fonts,
68069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            CancellationSignal cancellationSignal) {
68169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        final HashMap<Uri, ByteBuffer> out = new HashMap<>();
68269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        final ContentResolver resolver = context.getContentResolver();
68369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
68469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        for (FontInfo font : fonts) {
68569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            if (font.getResultCode() != Columns.RESULT_CODE_OK) {
68669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                continue;
68769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            }
68869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
68969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            final Uri uri = font.getUri();
69069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            if (out.containsKey(uri)) {
69169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                continue;
69269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            }
69369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
69469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            ByteBuffer buffer = null;
69569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            try (final ParcelFileDescriptor pfd =
696d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                    resolver.openFileDescriptor(uri, "r", cancellationSignal)) {
697d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                if (pfd != null) {
698d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                    try (final FileInputStream fis =
699d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                            new FileInputStream(pfd.getFileDescriptor())) {
700d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                        final FileChannel fileChannel = fis.getChannel();
701d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                        final long size = fileChannel.size();
702d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                        buffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, size);
703d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                    } catch (IOException e) {
704d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                        // ignore
705d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                    }
706d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka                }
70769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            } catch (IOException e) {
70869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                // ignore
70969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            }
71069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
71169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            // TODO: try other approach?, e.g. read all contents instead of mmap.
71269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
71369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            out.put(uri, buffer);
71469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
71569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        return Collections.unmodifiableMap(out);
71669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    }
71769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
7183c4be77db95ea716889568bde853be082e764da9Clara Bayarri    /** @hide */
7193c4be77db95ea716889568bde853be082e764da9Clara Bayarri    @VisibleForTesting
72069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    public static @Nullable ProviderInfo getProvider(
72169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            PackageManager packageManager, FontRequest request) throws NameNotFoundException {
7223c4be77db95ea716889568bde853be082e764da9Clara Bayarri        String providerAuthority = request.getProviderAuthority();
72369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        ProviderInfo info = packageManager.resolveContentProvider(providerAuthority, 0);
7243c4be77db95ea716889568bde853be082e764da9Clara Bayarri        if (info == null) {
72569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            throw new NameNotFoundException("No package found for authority: " + providerAuthority);
7263c4be77db95ea716889568bde853be082e764da9Clara Bayarri        }
7273c4be77db95ea716889568bde853be082e764da9Clara Bayarri
7283c4be77db95ea716889568bde853be082e764da9Clara Bayarri        if (!info.packageName.equals(request.getProviderPackage())) {
72969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            throw new NameNotFoundException("Found content provider " + providerAuthority
73069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    + ", but package was not " + request.getProviderPackage());
7313c4be77db95ea716889568bde853be082e764da9Clara Bayarri        }
7323c4be77db95ea716889568bde853be082e764da9Clara Bayarri        // Trust system apps without signature checks
7333c4be77db95ea716889568bde853be082e764da9Clara Bayarri        if (info.applicationInfo.isSystemApp()) {
7343c4be77db95ea716889568bde853be082e764da9Clara Bayarri            return info;
7353c4be77db95ea716889568bde853be082e764da9Clara Bayarri        }
7363c4be77db95ea716889568bde853be082e764da9Clara Bayarri
737fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        List<byte[]> signatures;
73869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        PackageInfo packageInfo = packageManager.getPackageInfo(info.packageName,
73969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                PackageManager.GET_SIGNATURES);
74069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        signatures = convertToByteArrayList(packageInfo.signatures);
74169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        Collections.sort(signatures, sByteArrayComparator);
74269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
7433c4be77db95ea716889568bde853be082e764da9Clara Bayarri        List<List<byte[]>> requestCertificatesList = request.getCertificates();
7443c4be77db95ea716889568bde853be082e764da9Clara Bayarri        for (int i = 0; i < requestCertificatesList.size(); ++i) {
745fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            // Make a copy so we can sort it without modifying the incoming data.
746fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            List<byte[]> requestSignatures = new ArrayList<>(requestCertificatesList.get(i));
747fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            Collections.sort(requestSignatures, sByteArrayComparator);
748fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            if (equalsByteArrayList(signatures, requestSignatures)) {
7493c4be77db95ea716889568bde853be082e764da9Clara Bayarri                return info;
7503c4be77db95ea716889568bde853be082e764da9Clara Bayarri            }
7513c4be77db95ea716889568bde853be082e764da9Clara Bayarri        }
7523c4be77db95ea716889568bde853be082e764da9Clara Bayarri        return null;
7533c4be77db95ea716889568bde853be082e764da9Clara Bayarri    }
7543c4be77db95ea716889568bde853be082e764da9Clara Bayarri
755fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri    private static final Comparator<byte[]> sByteArrayComparator = (l, r) -> {
756fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        if (l.length != r.length) {
757fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            return l.length - r.length;
7583c4be77db95ea716889568bde853be082e764da9Clara Bayarri        }
759fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        for (int i = 0; i < l.length; ++i) {
760fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            if (l[i] != r[i]) {
761fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri                return l[i] - r[i];
762fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            }
763fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        }
764fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        return 0;
765fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri    };
766fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri
76769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    private static boolean equalsByteArrayList(
76869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            List<byte[]> signatures, List<byte[]> requestSignatures) {
769fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        if (signatures.size() != requestSignatures.size()) {
770fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            return false;
771fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        }
772fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        for (int i = 0; i < signatures.size(); ++i) {
773fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            if (!Arrays.equals(signatures.get(i), requestSignatures.get(i))) {
774fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri                return false;
775fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            }
776fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        }
777fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        return true;
7783c4be77db95ea716889568bde853be082e764da9Clara Bayarri    }
7793c4be77db95ea716889568bde853be082e764da9Clara Bayarri
78069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    private static List<byte[]> convertToByteArrayList(Signature[] signatures) {
781fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        List<byte[]> shas = new ArrayList<>();
782fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        for (int i = 0; i < signatures.length; ++i) {
783fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            shas.add(signatures[i].toByteArray());
784fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        }
7853c4be77db95ea716889568bde853be082e764da9Clara Bayarri        return shas;
7863c4be77db95ea716889568bde853be082e764da9Clara Bayarri    }
7873c4be77db95ea716889568bde853be082e764da9Clara Bayarri
7883c4be77db95ea716889568bde853be082e764da9Clara Bayarri    /** @hide */
7893c4be77db95ea716889568bde853be082e764da9Clara Bayarri    @VisibleForTesting
79069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    public static @NonNull FontInfo[] getFontFromProvider(
79169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            Context context, FontRequest request, String authority,
79269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            CancellationSignal cancellationSignal) throws InvalidFormatException {
79369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        ArrayList<FontInfo> result = new ArrayList<>();
79443c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka        final Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
7953c4be77db95ea716889568bde853be082e764da9Clara Bayarri                .authority(authority)
796b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                .build();
79743c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka        final Uri fileBaseUri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
79843c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                .authority(authority)
79943c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                .appendPath("file")
80043c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                .build();
80169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        try (Cursor cursor = context.getContentResolver().query(uri, new String[] { Columns._ID,
80243c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                        Columns.FILE_ID, Columns.TTC_INDEX, Columns.VARIATION_SETTINGS,
80354084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka                        Columns.WEIGHT, Columns.ITALIC, Columns.RESULT_CODE },
80469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                "query = ?", new String[] { request.getQuery() }, null, cancellationSignal);) {
805b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            // TODO: Should we restrict the amount of fonts that can be returned?
806b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            // TODO: Write documentation explaining that all results should be from the same family.
807b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            if (cursor != null && cursor.getCount() > 0) {
808bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                final int resultCodeColumnIndex = cursor.getColumnIndex(Columns.RESULT_CODE);
809b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                result = new ArrayList<>();
810bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                final int idColumnIndex = cursor.getColumnIndexOrThrow(Columns._ID);
81143c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                final int fileIdColumnIndex = cursor.getColumnIndex(Columns.FILE_ID);
812b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                final int ttcIndexColumnIndex = cursor.getColumnIndex(Columns.TTC_INDEX);
813b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                final int vsColumnIndex = cursor.getColumnIndex(Columns.VARIATION_SETTINGS);
814fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka                final int weightColumnIndex = cursor.getColumnIndex(Columns.WEIGHT);
815fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka                final int italicColumnIndex = cursor.getColumnIndex(Columns.ITALIC);
816b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                while (cursor.moveToNext()) {
81769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    int resultCode = resultCodeColumnIndex != -1
818bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                            ? cursor.getInt(resultCodeColumnIndex) : Columns.RESULT_CODE_OK;
81969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    final int ttcIndex = ttcIndexColumnIndex != -1
82069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                            ? cursor.getInt(ttcIndexColumnIndex) : 0;
82169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    final String variationSettings = vsColumnIndex != -1
82269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                            ? cursor.getString(vsColumnIndex) : null;
82369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
82443c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                    Uri fileUri;
82543c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                    if (fileIdColumnIndex == -1) {
82643c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                        long id = cursor.getLong(idColumnIndex);
82743c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                        fileUri = ContentUris.withAppendedId(uri, id);
82843c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                    } else {
82943c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                        long id = cursor.getLong(fileIdColumnIndex);
83043c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                        fileUri = ContentUris.withAppendedId(fileBaseUri, id);
83143c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                    }
83269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    int weight;
83369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    boolean italic;
83469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    if (weightColumnIndex != -1 && italicColumnIndex != -1) {
83569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        weight = cursor.getInt(weightColumnIndex);
83669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        italic = cursor.getInt(italicColumnIndex) == 1;
83769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    } else {
83869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        weight = Typeface.Builder.NORMAL_WEIGHT;
83969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        italic = false;
840b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                    }
84169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    FontVariationAxis[] axes =
84269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                            FontVariationAxis.fromFontVariationSettings(variationSettings);
84369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    result.add(new FontInfo(fileUri, ttcIndex, axes, weight, italic, resultCode));
844b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                }
845b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            }
846b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        }
84769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        return result.toArray(new FontInfo[0]);
848b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    }
849b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri}
850