FontsContract.java revision ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79
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;
36b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.graphics.fonts.FontResult;
3769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport android.graphics.fonts.FontVariationAxis;
38b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.net.Uri;
39b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.os.Bundle;
4069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport android.os.CancellationSignal;
41b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.os.Handler;
42b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.os.HandlerThread;
43b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.os.ParcelFileDescriptor;
44b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.os.Process;
45b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.os.ResultReceiver;
46b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.util.Log;
47b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
48b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport com.android.internal.annotations.GuardedBy;
493c4be77db95ea716889568bde853be082e764da9Clara Bayarriimport com.android.internal.annotations.VisibleForTesting;
5069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport com.android.internal.util.Preconditions;
51b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
5269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport java.io.FileInputStream;
53b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport java.io.FileNotFoundException;
54bacf2352ab892724551431551ae973ae3b68db35Clara Bayarriimport java.io.IOException;
5569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport java.lang.annotation.Retention;
5669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport java.lang.annotation.RetentionPolicy;
5769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport java.nio.ByteBuffer;
5869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport java.nio.channels.FileChannel;
59b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport java.util.ArrayList;
60fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarriimport java.util.Arrays;
61fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarriimport java.util.Collections;
62fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarriimport java.util.Comparator;
6369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport java.util.HashMap;
643c4be77db95ea716889568bde853be082e764da9Clara Bayarriimport java.util.List;
6569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport java.util.Map;
66b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
67b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri/**
68b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * Utility class to deal with Font ContentProviders.
69b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri */
70b0812a30499376e09e2deb5995e998c629f24985Clara Bayarripublic class FontsContract {
71b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    private static final String TAG = "FontsContract";
72b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
73b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    /**
74b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     * Defines the constants used in a response from a Font Provider. The cursor returned from the
75b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     * query should have the ID column populated with the content uri ID for the resulting font.
76b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     * This should point to a real file or shared memory, as the client will mmap the given file
77b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     * descriptor. Pipes, sockets and other non-mmap-able file descriptors will fail to load in the
78b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     * client application.
79b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     */
80b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    public static final class Columns implements BaseColumns {
81b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        /**
82b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri         * Constant used to request data from a font provider. The cursor returned from the query
8343c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka         * may populate this column with a long for the font file ID. The client will request a file
8443c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka         * descriptor to "file/FILE_ID" with this ID immediately under the top-level content URI. If
8543c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka         * not present, the client will request a file descriptor to the top-level URI with the
8643c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka         * given base font ID. Note that several results may return the same file ID, e.g. for TTC
8743c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka         * files with different indices.
8843c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka         */
8943c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka        public static final String FILE_ID = "file_id";
9043c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka        /**
9143c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka         * Constant used to request data from a font provider. The cursor returned from the query
92b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri         * should have this column populated with an int for the ttc index for the resulting font.
93b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri         */
94b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        public static final String TTC_INDEX = "font_ttc_index";
95b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        /**
96b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri         * Constant used to request data from a font provider. The cursor returned from the query
97b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri         * may populate this column with the font variation settings String information for the
98b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri         * font.
99b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri         */
100b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        public static final String VARIATION_SETTINGS = "font_variation_settings";
101b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        /**
102fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * DO NOT USE THIS COLUMN.
103fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * This column is kept for preventing demo apps.
104fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * TODO: Remove once nobody uses this column.
105fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * @hide
106fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * @removed
107b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri         */
108b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        public static final String STYLE = "font_style";
109bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        /**
110bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * Constant used to request data from a font provider. The cursor returned from the query
111fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * should have this column populated with the int weight for the resulting font. This value
112fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * should be between 100 and 900. The most common values are 400 for regular weight and 700
113fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * for bold weight.
114fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         */
115fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka        public static final String WEIGHT = "font_weight";
116fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka        /**
117fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * Constant used to request data from a font provider. The cursor returned from the query
118fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * should have this column populated with the int italic for the resulting font. This should
119fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * be 0 for regular style and 1 for italic.
120fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         */
121fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka        public static final String ITALIC = "font_italic";
122fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka        /**
123fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * Constant used to request data from a font provider. The cursor returned from the query
124bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * should have this column populated to indicate the result status of the
125bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * query. This will be checked before any other data in the cursor. Possible values are
126bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * {@link #RESULT_CODE_OK}, {@link #RESULT_CODE_FONT_NOT_FOUND},
127bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * {@link #RESULT_CODE_MALFORMED_QUERY} and {@link #RESULT_CODE_FONT_UNAVAILABLE}. If not
128bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * present, {@link #RESULT_CODE_OK} will be assumed.
129bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         */
130bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        public static final String RESULT_CODE = "result_code";
131bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri
132bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        /**
133bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * Constant used to represent a result was retrieved successfully. The given fonts will be
134bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * attempted to retrieve immediately via
135bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * {@link android.content.ContentProvider#openFile(Uri, String)}. See {@link #RESULT_CODE}.
136bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         */
137bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        public static final int RESULT_CODE_OK = 0;
138bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        /**
139bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * Constant used to represent a result was not found. See {@link #RESULT_CODE}.
140bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         */
141bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        public static final int RESULT_CODE_FONT_NOT_FOUND = 1;
142bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        /**
143bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * Constant used to represent a result was found, but cannot be provided at this moment. Use
144bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * this to indicate, for example, that a font needs to be fetched from the network. See
145bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * {@link #RESULT_CODE}.
146bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         */
147bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        public static final int RESULT_CODE_FONT_UNAVAILABLE = 2;
148bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        /**
149bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * Constant used to represent that the query was not in a supported format by the provider.
150bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * See {@link #RESULT_CODE}.
151bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         */
152bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        public static final int RESULT_CODE_MALFORMED_QUERY = 3;
153b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    }
154b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
155b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    /**
156b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     * Constant used to identify the List of {@link ParcelFileDescriptor} item in the Bundle
157b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     * returned to the ResultReceiver in getFont.
158b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     * @hide
159b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     */
160b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    public static final String PARCEL_FONT_RESULTS = "font_results";
161bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri    // Error codes internal to the system, which can not come from a provider. To keep the number
162bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri    // space open for new provider codes, these should all be negative numbers.
163b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    /** @hide */
164bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri    public static final int RESULT_CODE_PROVIDER_NOT_FOUND = -1;
165b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    /** @hide */
166bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri    public static final int RESULT_CODE_WRONG_CERTIFICATES = -2;
167bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri    // Note -3 is used by Typeface to indicate the font failed to load.
168b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
169b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    private static final int THREAD_RENEWAL_THRESHOLD_MS = 10000;
170b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
171b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    private final Context mContext;
172b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    private final PackageManager mPackageManager;
173b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    private final Object mLock = new Object();
174b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    @GuardedBy("mLock")
175b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    private Handler mHandler;
176b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    @GuardedBy("mLock")
177b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    private HandlerThread mThread;
178b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
179b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    /** @hide */
180ff221613ec1c328489a303491e1aa88850e4a273Clara Bayarri    public FontsContract(Context context) {
181ff221613ec1c328489a303491e1aa88850e4a273Clara Bayarri        mContext = context.getApplicationContext();
182b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        mPackageManager = mContext.getPackageManager();
183b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    }
184b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
18569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    /**
18669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * Object represent a font entry in the family returned from {@link #fetchFonts}.
18769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     */
18869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    public static class FontInfo {
18969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        private final Uri mUri;
19069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        private final int mTtcIndex;
19169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        private final FontVariationAxis[] mAxes;
19269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        private final int mWeight;
19369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        private final boolean mItalic;
19469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        private final int mResultCode;
19569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
19669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /**
19769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * Creates a Font with all the information needed about a provided font.
19869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * @param uri A URI associated to the font file.
19969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * @param ttcIndex If providing a TTC_INDEX file, the index to point to. Otherwise, 0.
20069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * @param axes If providing a variation font, the settings for it. May be null.
20169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * @param weight An integer that indicates the font weight.
20269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * @param italic A boolean that indicates the font is italic style or not.
20369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * @param resultCode A boolean that indicates the font contents is ready.
20469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         */
20569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /** @hide */
20669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public FontInfo(@NonNull Uri uri, @IntRange(from = 0) int ttcIndex,
20769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                @Nullable FontVariationAxis[] axes, @IntRange(from = 1, to = 1000) int weight,
20869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                boolean italic, int resultCode) {
20969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            mUri = Preconditions.checkNotNull(uri);
21069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            mTtcIndex = ttcIndex;
21169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            mAxes = axes;
21269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            mWeight = weight;
21369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            mItalic = italic;
21469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            mResultCode = resultCode;
21569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
21669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
21769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /**
21869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * Returns a URI associated to this record.
21969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         */
22069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public @NonNull Uri getUri() {
22169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return mUri;
22269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
22369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
22469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /**
22569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * Returns the index to be used to access this font when accessing a TTC file.
22669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         */
22769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public @IntRange(from = 0) int getTtcIndex() {
22869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return mTtcIndex;
22969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
23069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
23169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /**
23269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * Returns the list of axes associated to this font.
23369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         */
23469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public @Nullable FontVariationAxis[] getAxes() {
23569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return mAxes;
23669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
23769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
23869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /**
23969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * Returns the weight value for this font.
24069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         */
24169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public @IntRange(from = 1, to = 1000) int getWeight() {
24269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return mWeight;
24369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
24469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
24569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /**
24669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * Returns whether this font is italic.
24769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         */
24869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public boolean isItalic() {
24969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return mItalic;
25069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
25169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
25269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /**
25369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * Returns result code.
25469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         *
25569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * {@link FontsContract.Columns#RESULT_CODE}
25669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         */
25769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public int getResultCode() {
25869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return mResultCode;
25969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
26069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    }
26169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
26269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    /**
26369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * Object returned from {@link #fetchFonts}.
26469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     */
26569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    public static class FontFamilyResult {
26669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /**
26769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * Constant represents that the font was successfully retrieved. Note that when this value
26869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * is set and {@link #getFonts} returns an empty array, it means there were no fonts
26969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * matching the given query.
27069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         */
27169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public static final int STATUS_OK = 0;
27269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
27369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /**
27469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * Constant represents that the given certificate was not matched with the provider's
27569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * signature. {@link #getFonts} returns null if this status was set.
27669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         */
27769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public static final int STATUS_WRONG_CERTIFICATES = 1;
27869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
27969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /**
28069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * Constant represents that the provider returns unexpected data. {@link #getFonts} returns
28169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * null if this status was set. For example, this value is set when the font provider
28269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         * gives invalid format of variation settings.
28369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka         */
28469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public static final int STATUS_UNEXPECTED_DATA_PROVIDED = 2;
28569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
286ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka        /**
287ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka         * Constant represents that the fetching font data was rejected by system. This happens if
288ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka         * the passed context is restricted.
289ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka         */
290ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka        public static final int STATUS_REJECTED = 3;
291ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka
29269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /** @hide */
29369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        @IntDef({STATUS_OK, STATUS_WRONG_CERTIFICATES, STATUS_UNEXPECTED_DATA_PROVIDED})
29469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        @Retention(RetentionPolicy.SOURCE)
29569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        @interface FontResultStatus {}
29669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
29769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        private final @FontResultStatus int mStatusCode;
29869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        private final FontInfo[] mFonts;
29969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
30069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /** @hide */
30169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public FontFamilyResult(@FontResultStatus int statusCode, @Nullable FontInfo[] fonts) {
30269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            mStatusCode = statusCode;
30369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            mFonts = fonts;
30469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
30569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
30669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public @FontResultStatus int getStatusCode() {
30769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return mStatusCode;
30869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
30969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
31069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public @NonNull FontInfo[] getFonts() {
31169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return mFonts;
31269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
3133c4be77db95ea716889568bde853be082e764da9Clara Bayarri    }
3143c4be77db95ea716889568bde853be082e764da9Clara Bayarri
315b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    // We use a background thread to post the content resolving work for all requests on. This
316b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    // thread should be quit/stopped after all requests are done.
317b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    private final Runnable mReplaceDispatcherThreadRunnable = new Runnable() {
318b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        @Override
319b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        public void run() {
320b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            synchronized (mLock) {
321b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                if (mThread != null) {
322b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                    mThread.quitSafely();
323b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                    mThread = null;
324b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                    mHandler = null;
325b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                }
326b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            }
327b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        }
328b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    };
329b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
330bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri    /** @hide */
331b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    public void getFont(FontRequest request, ResultReceiver receiver) {
332b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        synchronized (mLock) {
333b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            if (mHandler == null) {
334b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                mThread = new HandlerThread("fonts", Process.THREAD_PRIORITY_BACKGROUND);
335b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                mThread.start();
336b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                mHandler = new Handler(mThread.getLooper());
337b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            }
338b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            mHandler.post(() -> {
33969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                ProviderInfo providerInfo;
34069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                try {
34169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    providerInfo = getProvider(mPackageManager, request);
34269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    if (providerInfo == null) {
34369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        receiver.send(RESULT_CODE_PROVIDER_NOT_FOUND, null);
34469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        return;
34569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    }
34669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                } catch (PackageManager.NameNotFoundException e) {
34769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    receiver.send(RESULT_CODE_PROVIDER_NOT_FOUND, null);
34869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    return;
34969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                }
35069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                FontInfo[] fonts;
35169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                try {
35269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    fonts = getFontFromProvider(mContext, request, providerInfo.authority,
35369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                            null /* cancellation signal */);
35469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                } catch (InvalidFormatException e) {
35569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    receiver.send(RESULT_CODE_PROVIDER_NOT_FOUND, null);
356b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                    return;
357b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                }
35869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
35969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                ArrayList<FontResult> result = new ArrayList<>();
36069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                int resultCode = -1;
36169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                for (FontInfo font : fonts) {
36269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    try {
36369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        resultCode = font.getResultCode();
36469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        if (resultCode != Columns.RESULT_CODE_OK) {
36569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                            if (resultCode < 0) {
36669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                                // Negative values are reserved for the internal errors.
36769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                                resultCode = Columns.RESULT_CODE_FONT_NOT_FOUND;
36869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                            }
36969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                            for (int i = 0; i < result.size(); ++i) {
37069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                                try {
37169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                                    result.get(i).getFileDescriptor().close();
37269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                                } catch (IOException e) {
37369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                                    // Ignore, as we are closing fds for cleanup.
37469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                                }
37569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                            }
37669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                            receiver.send(resultCode, null);
37769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                            return;
37869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        }
37969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        ParcelFileDescriptor pfd = mContext.getContentResolver().openFileDescriptor(
38069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                                font.getUri(), "r");
38169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        result.add(new FontResult(pfd, font.getTtcIndex(),
38269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                                FontVariationAxis.toFontVariationSettings(font.getAxes()),
38369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                                font.getWeight(), font.isItalic()));
38469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    } catch (FileNotFoundException e) {
38569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        Log.e(TAG, "FileNotFoundException raised when interacting with content "
38669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                                + "provider " + providerInfo.authority, e);
38769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    }
38869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                }
38969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                if (!result.isEmpty()) {
39069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    Bundle bundle = new Bundle();
39169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    bundle.putParcelableArrayList(PARCEL_FONT_RESULTS, result);
39269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    receiver.send(Columns.RESULT_CODE_OK, bundle);
39369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    return;
39469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                }
39569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                receiver.send(Columns.RESULT_CODE_FONT_NOT_FOUND, null);
396b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            });
397b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            mHandler.removeCallbacks(mReplaceDispatcherThreadRunnable);
398b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            mHandler.postDelayed(mReplaceDispatcherThreadRunnable, THREAD_RENEWAL_THRESHOLD_MS);
399b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        }
400b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    }
401b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
40269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    /**
4030b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     * Interface used to receive asynchronously fetched typefaces.
4040b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     */
4050b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka    public static class FontRequestCallback {
4060b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        /**
4070b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given
4080b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * provider was not found on the device.
4090b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         */
4100b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        public static final int FAIL_REASON_PROVIDER_NOT_FOUND = RESULT_CODE_PROVIDER_NOT_FOUND;
4110b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        /**
4120b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given
4130b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * provider must be authenticated and the given certificates do not match its signature.
4140b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         */
4150b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        public static final int FAIL_REASON_WRONG_CERTIFICATES = RESULT_CODE_WRONG_CERTIFICATES;
4160b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        /**
4170b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the font
4180b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * returned by the provider was not loaded properly.
4190b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         */
4200b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        public static final int FAIL_REASON_FONT_LOAD_ERROR = -3;
4210b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        /**
4220b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the font
4230b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * provider did not return any results for the given query.
4240b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         */
4250b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        public static final int FAIL_REASON_FONT_NOT_FOUND = Columns.RESULT_CODE_FONT_NOT_FOUND;
4260b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        /**
4270b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the font
4280b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * provider found the queried font, but it is currently unavailable.
4290b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         */
4300b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        public static final int FAIL_REASON_FONT_UNAVAILABLE = Columns.RESULT_CODE_FONT_UNAVAILABLE;
4310b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        /**
4320b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given
4330b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * query was not supported by the provider.
4340b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         */
4350b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        public static final int FAIL_REASON_MALFORMED_QUERY = Columns.RESULT_CODE_MALFORMED_QUERY;
4360b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
4370b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        /** @hide */
4380b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        @IntDef({ FAIL_REASON_PROVIDER_NOT_FOUND, FAIL_REASON_FONT_LOAD_ERROR,
4390b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                FAIL_REASON_FONT_NOT_FOUND, FAIL_REASON_FONT_UNAVAILABLE,
4400b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                FAIL_REASON_MALFORMED_QUERY })
4410b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        @Retention(RetentionPolicy.SOURCE)
4420b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        @interface FontRequestFailReason {}
4430b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
4440b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        public FontRequestCallback() {}
4450b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
4460b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        /**
4470b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * Called then a Typeface request done via {@link Typeface#create(FontRequest,
4480b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * FontRequestCallback)} is complete. Note that this method will not be called if
4490b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * {@link #onTypefaceRequestFailed(int)} is called instead.
4500b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * @param typeface  The Typeface object retrieved.
4510b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         */
4520b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        public void onTypefaceRetrieved(Typeface typeface) {}
4530b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
4540b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        /**
4550b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * Called when a Typeface request done via {@link Typeface#create(FontRequest,
4560b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * FontRequestCallback)} fails.
4570b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         * @param reason One of {@link #FAIL_REASON_PROVIDER_NOT_FOUND},
4580b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         *               {@link #FAIL_REASON_FONT_NOT_FOUND},
4590b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         *               {@link #FAIL_REASON_FONT_LOAD_ERROR},
4600b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         *               {@link #FAIL_REASON_FONT_UNAVAILABLE} or
4610b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         *               {@link #FAIL_REASON_MALFORMED_QUERY}.
4620b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka         */
4630b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        public void onTypefaceRequestFailed(@FontRequestFailReason int reason) {}
4640b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka    }
4650b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
4660b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka    /**
4670b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     * Create a typeface object given a font request. The font will be asynchronously fetched,
4680b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     * therefore the result is delivered to the given callback. See {@link FontRequest}.
4690b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     * Only one of the methods in callback will be invoked, depending on whether the request
4700b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     * succeeds or fails. These calls will happen on the caller thread.
4710b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     * @param context A context to be used for fetching from font provider.
4720b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     * @param request A {@link FontRequest} object that identifies the provider and query for the
4730b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     *                request. May not be null.
4740b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     * @param callback A callback that will be triggered when results are obtained. May not be null.
4750b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     * @param handler A handler to be processed the font fetching.
4760b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka     */
4770b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka    public static void requestFont(@NonNull Context context, @NonNull FontRequest request,
4780b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            @NonNull FontRequestCallback callback, @NonNull Handler handler) {
4790b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
4800b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        final Handler callerThreadHandler = new Handler();
4810b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        handler.post(() -> {
4820b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            // TODO: Cache the result.
4830b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            FontFamilyResult result;
4840b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            try {
4850b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                result = fetchFonts(context, null /* cancellation signal */, request);
4860b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            } catch (NameNotFoundException e) {
4870b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
4880b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        FontRequestCallback.FAIL_REASON_PROVIDER_NOT_FOUND));
4890b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                return;
4900b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            }
4910b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
4920b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            if (result.getStatusCode() != FontFamilyResult.STATUS_OK) {
4930b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                switch (result.getStatusCode()) {
4940b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                    case FontFamilyResult.STATUS_WRONG_CERTIFICATES:
4950b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
4960b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                                FontRequestCallback.FAIL_REASON_WRONG_CERTIFICATES));
4970b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        return;
4980b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                    case FontFamilyResult.STATUS_UNEXPECTED_DATA_PROVIDED:
4990b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
5000b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                                FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR));
5010b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        return;
5020b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                    default:
5030b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        // fetchFont returns unexpected status type. Fallback to load error.
5040b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
5050b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                                FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR));
5060b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        return;
5070b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                }
5080b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            }
5090b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
5100b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            final FontInfo[] fonts = result.getFonts();
5110b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            if (fonts == null || fonts.length == 0) {
5120b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
5130b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        FontRequestCallback.FAIL_REASON_FONT_NOT_FOUND));
5140b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                return;
5150b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            }
5160b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            for (final FontInfo font : fonts) {
5170b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                if (font.getResultCode() != Columns.RESULT_CODE_OK) {
5180b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                    // We proceed if all font entry is ready to use. Otherwise report the first
5190b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                    // error.
5200b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                    final int resultCode = font.getResultCode();
5210b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                    if (resultCode < 0) {
5220b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        // Negative values are reserved for internal errors. Fallback to load error.
5230b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
5240b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                                FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR));
5250b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                    } else {
5260b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
5270b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                                resultCode));
5280b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                    }
5290b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                    return;
5300b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                }
5310b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            }
5320b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
5330b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            final Typeface typeface = buildTypeface(context, null /* cancellation signal */, fonts);
5340b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            if (typeface == null) {
5350b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                // Something went wrong during reading font files. This happens if the given font
5360b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                // file is an unsupported font type.
5370b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
5380b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                        FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR));
5390b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka                return;
5400b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            }
5410b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
5420b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka            callerThreadHandler.post(() -> callback.onTypefaceRetrieved(typeface));
5430b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka        });
5440b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka    }
5450b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka
5460b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka    /**
54769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * Fetch fonts given a font request.
54869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
54969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param context A {@link Context} to be used for fetching fonts.
55069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param cancellationSignal A signal to cancel the operation in progress, or null if none. If
55169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                           the operation is canceled, then {@link
55269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                           android.os.OperationCanceledException} will be thrown when the
55369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                           query is executed.
55469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param request A {@link FontRequest} object that identifies the provider and query for the
55569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                request.
55669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
55769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @return {@link FontFamilyResult}
55869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
55969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @throws NameNotFoundException If requested package or authority was not found in system.
56069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     */
56169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    public static @NonNull FontFamilyResult fetchFonts(
56269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            @NonNull Context context, @Nullable CancellationSignal cancellationSignal,
56369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            @NonNull FontRequest request) throws NameNotFoundException {
564ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka        if (context.isRestricted()) {
565ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka            // TODO: Should we allow if the peer process is system or myself?
566ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka            return new FontFamilyResult(FontFamilyResult.STATUS_REJECTED, null);
567ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka        }
56869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        ProviderInfo providerInfo = getProvider(context.getPackageManager(), request);
56969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        if (providerInfo == null) {
57069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return new FontFamilyResult(FontFamilyResult.STATUS_WRONG_CERTIFICATES, null);
57169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
57269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
57369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        try {
57469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            FontInfo[] fonts = getFontFromProvider(
57569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    context, request, providerInfo.authority, cancellationSignal);
57669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return new FontFamilyResult(FontFamilyResult.STATUS_OK, fonts);
57769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        } catch (InvalidFormatException e) {
57869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return new FontFamilyResult(FontFamilyResult.STATUS_UNEXPECTED_DATA_PROVIDED, null);
57969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
58069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    }
58169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
58269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    /**
58369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * Build a Typeface from an array of {@link FontInfo}. Results that are marked as not ready
58469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * will be skipped.
58569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
58669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param context A {@link Context} that will be used to fetch the font contents.
58769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param cancellationSignal A signal to cancel the operation in progress, or null if none. If
58869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                           the operation is canceled, then {@link
58969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                           android.os.OperationCanceledException} will be thrown.
59069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param fonts An array of {@link FontInfo} to be used to create a Typeface.
59169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param weight A weight value to be used for selecting a font from a font family.
59269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param italic {@code true} if this font is of italic style. This will be used for font
59369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *               selection from a font family.
59469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param fallbackFontName A fallback font name used if this method fails to create the
59569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                         Typeface. By passing {@code null}, this method returns {@code null}
59669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                         if typeface creation fails.
59769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @return A Typeface object. May return {@code null} if that is the value passed to {@code
59869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *         fallBackFontName}.
59969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     */
60069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    public static Typeface buildTypeface(@NonNull Context context,
60169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            @Nullable CancellationSignal cancellationSignal, @NonNull FontInfo[] fonts,
60269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            int weight, boolean italic, @Nullable String fallbackFontName) {
603ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka        if (context.isRestricted()) {
604ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka            // TODO: Should we allow if the peer process is system or myself?
605ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka            return null;
606ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka        }
60769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        final Map<Uri, ByteBuffer> uriBuffer =
60869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                prepareFontData(context, fonts, cancellationSignal);
6095b6347a6af668ba47b3fab14cefbe03cc440c3a4Seigo Nonaka        return new Typeface.Builder(fonts, uriBuffer)
6105b6347a6af668ba47b3fab14cefbe03cc440c3a4Seigo Nonaka            .setFallback(fallbackFontName)
61169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            .setWeight(weight)
61269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            .setItalic(italic)
61369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            .build();
61469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    }
61569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
61669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    /**
61769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * Build a Typeface from an array of {@link FontInfo}
61869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
61969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * Results that are marked as not ready will be skipped.
62069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
62169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param context A {@link Context} that will be used to fetch the font contents.
62269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param cancellationSignal A signal to cancel the operation in progress, or null if none. If
62369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                           the operation is canceled, then {@link
62469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                           android.os.OperationCanceledException} will be thrown.
62569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param fonts An array of {@link FontInfo} to be used to create a Typeface.
62669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @return A Typeface object. Returns null if typeface creation fails.
62769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     */
62869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    public static Typeface buildTypeface(@NonNull Context context,
62969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            @Nullable CancellationSignal cancellationSignal, @NonNull FontInfo[] fonts) {
630ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka        if (context.isRestricted()) {
631ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka            // TODO: Should we allow if the peer process is system or myself?
632ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka            return null;
633ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka        }
63469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        final Map<Uri, ByteBuffer> uriBuffer =
63569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                prepareFontData(context, fonts, cancellationSignal);
63669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        return new Typeface.Builder(fonts, uriBuffer).build();
63769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    }
63869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
63969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    /**
64069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * A helper function to create a mapping from {@link Uri} to {@link ByteBuffer}.
64169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
64269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * Skip if the file contents is not ready to be read.
64369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
64469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param context A {@link Context} to be used for resolving content URI in
64569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                {@link FontInfo}.
64669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param fonts An array of {@link FontInfo}.
64769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @return A map from {@link Uri} to {@link ByteBuffer}.
64869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     */
64969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    private static Map<Uri, ByteBuffer> prepareFontData(Context context, FontInfo[] fonts,
65069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            CancellationSignal cancellationSignal) {
65169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        final HashMap<Uri, ByteBuffer> out = new HashMap<>();
65269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        final ContentResolver resolver = context.getContentResolver();
65369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
65469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        for (FontInfo font : fonts) {
65569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            if (font.getResultCode() != Columns.RESULT_CODE_OK) {
65669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                continue;
65769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            }
65869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
65969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            final Uri uri = font.getUri();
66069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            if (out.containsKey(uri)) {
66169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                continue;
66269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            }
66369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
66469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            ByteBuffer buffer = null;
66569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            try (final ParcelFileDescriptor pfd =
66669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    resolver.openFileDescriptor(uri, "r", cancellationSignal);
66769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    final FileInputStream fis = new FileInputStream(pfd.getFileDescriptor())) {
66869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                final FileChannel fileChannel = fis.getChannel();
66969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                final long size = fileChannel.size();
67069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                buffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, size);
67169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            } catch (IOException e) {
67269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                // ignore
67369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            }
67469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
67569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            // TODO: try other approach?, e.g. read all contents instead of mmap.
67669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
67769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            out.put(uri, buffer);
67869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
67969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        return Collections.unmodifiableMap(out);
68069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    }
68169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
6823c4be77db95ea716889568bde853be082e764da9Clara Bayarri    /** @hide */
6833c4be77db95ea716889568bde853be082e764da9Clara Bayarri    @VisibleForTesting
68469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    public static @Nullable ProviderInfo getProvider(
68569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            PackageManager packageManager, FontRequest request) throws NameNotFoundException {
6863c4be77db95ea716889568bde853be082e764da9Clara Bayarri        String providerAuthority = request.getProviderAuthority();
68769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        ProviderInfo info = packageManager.resolveContentProvider(providerAuthority, 0);
6883c4be77db95ea716889568bde853be082e764da9Clara Bayarri        if (info == null) {
68969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            throw new NameNotFoundException("No package found for authority: " + providerAuthority);
6903c4be77db95ea716889568bde853be082e764da9Clara Bayarri        }
6913c4be77db95ea716889568bde853be082e764da9Clara Bayarri
6923c4be77db95ea716889568bde853be082e764da9Clara Bayarri        if (!info.packageName.equals(request.getProviderPackage())) {
69369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            throw new NameNotFoundException("Found content provider " + providerAuthority
69469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    + ", but package was not " + request.getProviderPackage());
6953c4be77db95ea716889568bde853be082e764da9Clara Bayarri        }
6963c4be77db95ea716889568bde853be082e764da9Clara Bayarri        // Trust system apps without signature checks
6973c4be77db95ea716889568bde853be082e764da9Clara Bayarri        if (info.applicationInfo.isSystemApp()) {
6983c4be77db95ea716889568bde853be082e764da9Clara Bayarri            return info;
6993c4be77db95ea716889568bde853be082e764da9Clara Bayarri        }
7003c4be77db95ea716889568bde853be082e764da9Clara Bayarri
701fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        List<byte[]> signatures;
70269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        PackageInfo packageInfo = packageManager.getPackageInfo(info.packageName,
70369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                PackageManager.GET_SIGNATURES);
70469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        signatures = convertToByteArrayList(packageInfo.signatures);
70569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        Collections.sort(signatures, sByteArrayComparator);
70669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
7073c4be77db95ea716889568bde853be082e764da9Clara Bayarri        List<List<byte[]>> requestCertificatesList = request.getCertificates();
7083c4be77db95ea716889568bde853be082e764da9Clara Bayarri        for (int i = 0; i < requestCertificatesList.size(); ++i) {
709fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            // Make a copy so we can sort it without modifying the incoming data.
710fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            List<byte[]> requestSignatures = new ArrayList<>(requestCertificatesList.get(i));
711fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            Collections.sort(requestSignatures, sByteArrayComparator);
712fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            if (equalsByteArrayList(signatures, requestSignatures)) {
7133c4be77db95ea716889568bde853be082e764da9Clara Bayarri                return info;
7143c4be77db95ea716889568bde853be082e764da9Clara Bayarri            }
7153c4be77db95ea716889568bde853be082e764da9Clara Bayarri        }
7163c4be77db95ea716889568bde853be082e764da9Clara Bayarri        return null;
7173c4be77db95ea716889568bde853be082e764da9Clara Bayarri    }
7183c4be77db95ea716889568bde853be082e764da9Clara Bayarri
719fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri    private static final Comparator<byte[]> sByteArrayComparator = (l, r) -> {
720fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        if (l.length != r.length) {
721fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            return l.length - r.length;
7223c4be77db95ea716889568bde853be082e764da9Clara Bayarri        }
723fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        for (int i = 0; i < l.length; ++i) {
724fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            if (l[i] != r[i]) {
725fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri                return l[i] - r[i];
726fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            }
727fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        }
728fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        return 0;
729fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri    };
730fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri
73169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    private static boolean equalsByteArrayList(
73269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            List<byte[]> signatures, List<byte[]> requestSignatures) {
733fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        if (signatures.size() != requestSignatures.size()) {
734fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            return false;
735fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        }
736fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        for (int i = 0; i < signatures.size(); ++i) {
737fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            if (!Arrays.equals(signatures.get(i), requestSignatures.get(i))) {
738fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri                return false;
739fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            }
740fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        }
741fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        return true;
7423c4be77db95ea716889568bde853be082e764da9Clara Bayarri    }
7433c4be77db95ea716889568bde853be082e764da9Clara Bayarri
74469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    private static List<byte[]> convertToByteArrayList(Signature[] signatures) {
745fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        List<byte[]> shas = new ArrayList<>();
746fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        for (int i = 0; i < signatures.length; ++i) {
747fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            shas.add(signatures[i].toByteArray());
748fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        }
7493c4be77db95ea716889568bde853be082e764da9Clara Bayarri        return shas;
7503c4be77db95ea716889568bde853be082e764da9Clara Bayarri    }
7513c4be77db95ea716889568bde853be082e764da9Clara Bayarri
7523c4be77db95ea716889568bde853be082e764da9Clara Bayarri    /** @hide */
7533c4be77db95ea716889568bde853be082e764da9Clara Bayarri    @VisibleForTesting
75469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    public static @NonNull FontInfo[] getFontFromProvider(
75569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            Context context, FontRequest request, String authority,
75669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            CancellationSignal cancellationSignal) throws InvalidFormatException {
75769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        ArrayList<FontInfo> result = new ArrayList<>();
75843c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka        final Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
7593c4be77db95ea716889568bde853be082e764da9Clara Bayarri                .authority(authority)
760b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                .build();
76143c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka        final Uri fileBaseUri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
76243c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                .authority(authority)
76343c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                .appendPath("file")
76443c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                .build();
76569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        try (Cursor cursor = context.getContentResolver().query(uri, new String[] { Columns._ID,
76643c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                        Columns.FILE_ID, Columns.TTC_INDEX, Columns.VARIATION_SETTINGS,
76743c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                        Columns.STYLE, Columns.WEIGHT, Columns.ITALIC, Columns.RESULT_CODE },
76869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                "query = ?", new String[] { request.getQuery() }, null, cancellationSignal);) {
769b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            // TODO: Should we restrict the amount of fonts that can be returned?
770b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            // TODO: Write documentation explaining that all results should be from the same family.
771b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            if (cursor != null && cursor.getCount() > 0) {
772bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                final int resultCodeColumnIndex = cursor.getColumnIndex(Columns.RESULT_CODE);
773b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                result = new ArrayList<>();
774bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                final int idColumnIndex = cursor.getColumnIndexOrThrow(Columns._ID);
77543c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                final int fileIdColumnIndex = cursor.getColumnIndex(Columns.FILE_ID);
776b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                final int ttcIndexColumnIndex = cursor.getColumnIndex(Columns.TTC_INDEX);
777b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                final int vsColumnIndex = cursor.getColumnIndex(Columns.VARIATION_SETTINGS);
778fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka                final int weightColumnIndex = cursor.getColumnIndex(Columns.WEIGHT);
779fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka                final int italicColumnIndex = cursor.getColumnIndex(Columns.ITALIC);
780b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                final int styleColumnIndex = cursor.getColumnIndex(Columns.STYLE);
781b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                while (cursor.moveToNext()) {
78269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    int resultCode = resultCodeColumnIndex != -1
783bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                            ? cursor.getInt(resultCodeColumnIndex) : Columns.RESULT_CODE_OK;
78469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    final int ttcIndex = ttcIndexColumnIndex != -1
78569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                            ? cursor.getInt(ttcIndexColumnIndex) : 0;
78669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    final String variationSettings = vsColumnIndex != -1
78769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                            ? cursor.getString(vsColumnIndex) : null;
78869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
78943c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                    Uri fileUri;
79043c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                    if (fileIdColumnIndex == -1) {
79143c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                        long id = cursor.getLong(idColumnIndex);
79243c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                        fileUri = ContentUris.withAppendedId(uri, id);
79343c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                    } else {
79443c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                        long id = cursor.getLong(fileIdColumnIndex);
79543c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                        fileUri = ContentUris.withAppendedId(fileBaseUri, id);
79643c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                    }
79769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    // TODO: Stop using STYLE column and enforce WEIGHT/ITALIC column.
79869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    int weight;
79969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    boolean italic;
80069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    if (weightColumnIndex != -1 && italicColumnIndex != -1) {
80169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        weight = cursor.getInt(weightColumnIndex);
80269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        italic = cursor.getInt(italicColumnIndex) == 1;
80369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    } else if (styleColumnIndex != -1) {
80469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        final int style = cursor.getInt(styleColumnIndex);
80569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        weight = (style & Typeface.BOLD) != 0 ?
80669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                                Typeface.Builder.BOLD_WEIGHT : Typeface.Builder.NORMAL_WEIGHT;
80769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        italic = (style & Typeface.ITALIC) != 0;
80869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    } else {
80969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        weight = Typeface.Builder.NORMAL_WEIGHT;
81069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        italic = false;
811b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                    }
81269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    FontVariationAxis[] axes =
81369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                            FontVariationAxis.fromFontVariationSettings(variationSettings);
81469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    result.add(new FontInfo(fileUri, ttcIndex, axes, weight, italic, resultCode));
815b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                }
816b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            }
817b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        }
81869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        return result.toArray(new FontInfo[0]);
819b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    }
820b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri}
821