FontsContract.java revision 69754bf66dae9d047d5a0ff2c71820aa35b9cc70
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
28669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /** @hide */
28769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        @IntDef({STATUS_OK, STATUS_WRONG_CERTIFICATES, STATUS_UNEXPECTED_DATA_PROVIDED})
28869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        @Retention(RetentionPolicy.SOURCE)
28969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        @interface FontResultStatus {}
29069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
29169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        private final @FontResultStatus int mStatusCode;
29269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        private final FontInfo[] mFonts;
29369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
29469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        /** @hide */
29569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public FontFamilyResult(@FontResultStatus int statusCode, @Nullable FontInfo[] fonts) {
29669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            mStatusCode = statusCode;
29769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            mFonts = fonts;
29869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
29969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
30069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public @FontResultStatus int getStatusCode() {
30169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return mStatusCode;
30269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
30369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
30469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        public @NonNull FontInfo[] getFonts() {
30569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return mFonts;
30669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
3073c4be77db95ea716889568bde853be082e764da9Clara Bayarri    }
3083c4be77db95ea716889568bde853be082e764da9Clara Bayarri
309b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    // We use a background thread to post the content resolving work for all requests on. This
310b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    // thread should be quit/stopped after all requests are done.
311b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    private final Runnable mReplaceDispatcherThreadRunnable = new Runnable() {
312b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        @Override
313b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        public void run() {
314b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            synchronized (mLock) {
315b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                if (mThread != null) {
316b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                    mThread.quitSafely();
317b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                    mThread = null;
318b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                    mHandler = null;
319b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                }
320b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            }
321b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        }
322b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    };
323b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
324bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri    /** @hide */
325b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    public void getFont(FontRequest request, ResultReceiver receiver) {
326b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        synchronized (mLock) {
327b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            if (mHandler == null) {
328b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                mThread = new HandlerThread("fonts", Process.THREAD_PRIORITY_BACKGROUND);
329b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                mThread.start();
330b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                mHandler = new Handler(mThread.getLooper());
331b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            }
332b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            mHandler.post(() -> {
33369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                ProviderInfo providerInfo;
33469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                try {
33569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    providerInfo = getProvider(mPackageManager, request);
33669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    if (providerInfo == null) {
33769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        receiver.send(RESULT_CODE_PROVIDER_NOT_FOUND, null);
33869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        return;
33969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    }
34069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                } catch (PackageManager.NameNotFoundException e) {
34169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    receiver.send(RESULT_CODE_PROVIDER_NOT_FOUND, null);
34269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    return;
34369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                }
34469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                FontInfo[] fonts;
34569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                try {
34669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    fonts = getFontFromProvider(mContext, request, providerInfo.authority,
34769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                            null /* cancellation signal */);
34869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                } catch (InvalidFormatException e) {
34969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    receiver.send(RESULT_CODE_PROVIDER_NOT_FOUND, null);
350b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                    return;
351b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                }
35269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
35369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                ArrayList<FontResult> result = new ArrayList<>();
35469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                int resultCode = -1;
35569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                for (FontInfo font : fonts) {
35669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    try {
35769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        resultCode = font.getResultCode();
35869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        if (resultCode != Columns.RESULT_CODE_OK) {
35969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                            if (resultCode < 0) {
36069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                                // Negative values are reserved for the internal errors.
36169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                                resultCode = Columns.RESULT_CODE_FONT_NOT_FOUND;
36269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                            }
36369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                            for (int i = 0; i < result.size(); ++i) {
36469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                                try {
36569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                                    result.get(i).getFileDescriptor().close();
36669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                                } catch (IOException e) {
36769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                                    // Ignore, as we are closing fds for cleanup.
36869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                                }
36969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                            }
37069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                            receiver.send(resultCode, null);
37169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                            return;
37269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        }
37369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        ParcelFileDescriptor pfd = mContext.getContentResolver().openFileDescriptor(
37469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                                font.getUri(), "r");
37569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        result.add(new FontResult(pfd, font.getTtcIndex(),
37669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                                FontVariationAxis.toFontVariationSettings(font.getAxes()),
37769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                                font.getWeight(), font.isItalic()));
37869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    } catch (FileNotFoundException e) {
37969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        Log.e(TAG, "FileNotFoundException raised when interacting with content "
38069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                                + "provider " + providerInfo.authority, e);
38169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    }
38269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                }
38369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                if (!result.isEmpty()) {
38469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    Bundle bundle = new Bundle();
38569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    bundle.putParcelableArrayList(PARCEL_FONT_RESULTS, result);
38669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    receiver.send(Columns.RESULT_CODE_OK, bundle);
38769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    return;
38869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                }
38969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                receiver.send(Columns.RESULT_CODE_FONT_NOT_FOUND, null);
390b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            });
391b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            mHandler.removeCallbacks(mReplaceDispatcherThreadRunnable);
392b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            mHandler.postDelayed(mReplaceDispatcherThreadRunnable, THREAD_RENEWAL_THRESHOLD_MS);
393b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        }
394b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    }
395b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
39669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    /**
39769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * Fetch fonts given a font request.
39869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
39969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param context A {@link Context} to be used for fetching fonts.
40069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param cancellationSignal A signal to cancel the operation in progress, or null if none. If
40169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                           the operation is canceled, then {@link
40269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                           android.os.OperationCanceledException} will be thrown when the
40369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                           query is executed.
40469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param request A {@link FontRequest} object that identifies the provider and query for the
40569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                request.
40669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
40769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @return {@link FontFamilyResult}
40869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
40969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @throws NameNotFoundException If requested package or authority was not found in system.
41069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     */
41169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    public static @NonNull FontFamilyResult fetchFonts(
41269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            @NonNull Context context, @Nullable CancellationSignal cancellationSignal,
41369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            @NonNull FontRequest request) throws NameNotFoundException {
41469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        ProviderInfo providerInfo = getProvider(context.getPackageManager(), request);
41569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        if (providerInfo == null) {
41669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return new FontFamilyResult(FontFamilyResult.STATUS_WRONG_CERTIFICATES, null);
41769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
41869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
41969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        try {
42069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            FontInfo[] fonts = getFontFromProvider(
42169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    context, request, providerInfo.authority, cancellationSignal);
42269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return new FontFamilyResult(FontFamilyResult.STATUS_OK, fonts);
42369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        } catch (InvalidFormatException e) {
42469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            return new FontFamilyResult(FontFamilyResult.STATUS_UNEXPECTED_DATA_PROVIDED, null);
42569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
42669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    }
42769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
42869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    /**
42969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * Build a Typeface from an array of {@link FontInfo}. Results that are marked as not ready
43069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * will be skipped.
43169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
43269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param context A {@link Context} that will be used to fetch the font contents.
43369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param cancellationSignal A signal to cancel the operation in progress, or null if none. If
43469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                           the operation is canceled, then {@link
43569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                           android.os.OperationCanceledException} will be thrown.
43669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param fonts An array of {@link FontInfo} to be used to create a Typeface.
43769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param weight A weight value to be used for selecting a font from a font family.
43869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param italic {@code true} if this font is of italic style. This will be used for font
43969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *               selection from a font family.
44069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param fallbackFontName A fallback font name used if this method fails to create the
44169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                         Typeface. By passing {@code null}, this method returns {@code null}
44269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                         if typeface creation fails.
44369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @return A Typeface object. May return {@code null} if that is the value passed to {@code
44469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *         fallBackFontName}.
44569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     */
44669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    public static Typeface buildTypeface(@NonNull Context context,
44769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            @Nullable CancellationSignal cancellationSignal, @NonNull FontInfo[] fonts,
44869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            int weight, boolean italic, @Nullable String fallbackFontName) {
44969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        final Map<Uri, ByteBuffer> uriBuffer =
45069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                prepareFontData(context, fonts, cancellationSignal);
45169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        Typeface typeface = new Typeface.Builder(fonts, uriBuffer)
45269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            .setWeight(weight)
45369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            .setItalic(italic)
45469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            .build();
45569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        // TODO: Use Typeface fallback instead.
45669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        if (typeface == null) {
45769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            typeface = Typeface.create(fallbackFontName, Typeface.NORMAL);
45869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
45969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        return typeface;
46069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    }
46169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
46269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    /**
46369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * Build a Typeface from an array of {@link FontInfo}
46469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
46569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * Results that are marked as not ready will be skipped.
46669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
46769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param context A {@link Context} that will be used to fetch the font contents.
46869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param cancellationSignal A signal to cancel the operation in progress, or null if none. If
46969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                           the operation is canceled, then {@link
47069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                           android.os.OperationCanceledException} will be thrown.
47169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param fonts An array of {@link FontInfo} to be used to create a Typeface.
47269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @return A Typeface object. Returns null if typeface creation fails.
47369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     */
47469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    public static Typeface buildTypeface(@NonNull Context context,
47569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            @Nullable CancellationSignal cancellationSignal, @NonNull FontInfo[] fonts) {
47669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        final Map<Uri, ByteBuffer> uriBuffer =
47769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                prepareFontData(context, fonts, cancellationSignal);
47869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        return new Typeface.Builder(fonts, uriBuffer).build();
47969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    }
48069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
48169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    /**
48269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * A helper function to create a mapping from {@link Uri} to {@link ByteBuffer}.
48369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
48469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * Skip if the file contents is not ready to be read.
48569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *
48669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param context A {@link Context} to be used for resolving content URI in
48769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     *                {@link FontInfo}.
48869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @param fonts An array of {@link FontInfo}.
48969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     * @return A map from {@link Uri} to {@link ByteBuffer}.
49069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka     */
49169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    private static Map<Uri, ByteBuffer> prepareFontData(Context context, FontInfo[] fonts,
49269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            CancellationSignal cancellationSignal) {
49369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        final HashMap<Uri, ByteBuffer> out = new HashMap<>();
49469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        final ContentResolver resolver = context.getContentResolver();
49569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
49669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        for (FontInfo font : fonts) {
49769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            if (font.getResultCode() != Columns.RESULT_CODE_OK) {
49869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                continue;
49969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            }
50069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
50169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            final Uri uri = font.getUri();
50269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            if (out.containsKey(uri)) {
50369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                continue;
50469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            }
50569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
50669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            ByteBuffer buffer = null;
50769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            try (final ParcelFileDescriptor pfd =
50869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    resolver.openFileDescriptor(uri, "r", cancellationSignal);
50969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    final FileInputStream fis = new FileInputStream(pfd.getFileDescriptor())) {
51069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                final FileChannel fileChannel = fis.getChannel();
51169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                final long size = fileChannel.size();
51269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                buffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, size);
51369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            } catch (IOException e) {
51469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                // ignore
51569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            }
51669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
51769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            // TODO: try other approach?, e.g. read all contents instead of mmap.
51869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
51969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            out.put(uri, buffer);
52069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        }
52169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        return Collections.unmodifiableMap(out);
52269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    }
52369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
5243c4be77db95ea716889568bde853be082e764da9Clara Bayarri    /** @hide */
5253c4be77db95ea716889568bde853be082e764da9Clara Bayarri    @VisibleForTesting
52669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    public static @Nullable ProviderInfo getProvider(
52769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            PackageManager packageManager, FontRequest request) throws NameNotFoundException {
5283c4be77db95ea716889568bde853be082e764da9Clara Bayarri        String providerAuthority = request.getProviderAuthority();
52969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        ProviderInfo info = packageManager.resolveContentProvider(providerAuthority, 0);
5303c4be77db95ea716889568bde853be082e764da9Clara Bayarri        if (info == null) {
53169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            throw new NameNotFoundException("No package found for authority: " + providerAuthority);
5323c4be77db95ea716889568bde853be082e764da9Clara Bayarri        }
5333c4be77db95ea716889568bde853be082e764da9Clara Bayarri
5343c4be77db95ea716889568bde853be082e764da9Clara Bayarri        if (!info.packageName.equals(request.getProviderPackage())) {
53569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            throw new NameNotFoundException("Found content provider " + providerAuthority
53669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    + ", but package was not " + request.getProviderPackage());
5373c4be77db95ea716889568bde853be082e764da9Clara Bayarri        }
5383c4be77db95ea716889568bde853be082e764da9Clara Bayarri        // Trust system apps without signature checks
5393c4be77db95ea716889568bde853be082e764da9Clara Bayarri        if (info.applicationInfo.isSystemApp()) {
5403c4be77db95ea716889568bde853be082e764da9Clara Bayarri            return info;
5413c4be77db95ea716889568bde853be082e764da9Clara Bayarri        }
5423c4be77db95ea716889568bde853be082e764da9Clara Bayarri
543fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        List<byte[]> signatures;
54469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        PackageInfo packageInfo = packageManager.getPackageInfo(info.packageName,
54569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                PackageManager.GET_SIGNATURES);
54669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        signatures = convertToByteArrayList(packageInfo.signatures);
54769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        Collections.sort(signatures, sByteArrayComparator);
54869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
5493c4be77db95ea716889568bde853be082e764da9Clara Bayarri        List<List<byte[]>> requestCertificatesList = request.getCertificates();
5503c4be77db95ea716889568bde853be082e764da9Clara Bayarri        for (int i = 0; i < requestCertificatesList.size(); ++i) {
551fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            // Make a copy so we can sort it without modifying the incoming data.
552fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            List<byte[]> requestSignatures = new ArrayList<>(requestCertificatesList.get(i));
553fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            Collections.sort(requestSignatures, sByteArrayComparator);
554fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            if (equalsByteArrayList(signatures, requestSignatures)) {
5553c4be77db95ea716889568bde853be082e764da9Clara Bayarri                return info;
5563c4be77db95ea716889568bde853be082e764da9Clara Bayarri            }
5573c4be77db95ea716889568bde853be082e764da9Clara Bayarri        }
5583c4be77db95ea716889568bde853be082e764da9Clara Bayarri        return null;
5593c4be77db95ea716889568bde853be082e764da9Clara Bayarri    }
5603c4be77db95ea716889568bde853be082e764da9Clara Bayarri
561fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri    private static final Comparator<byte[]> sByteArrayComparator = (l, r) -> {
562fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        if (l.length != r.length) {
563fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            return l.length - r.length;
5643c4be77db95ea716889568bde853be082e764da9Clara Bayarri        }
565fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        for (int i = 0; i < l.length; ++i) {
566fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            if (l[i] != r[i]) {
567fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri                return l[i] - r[i];
568fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            }
569fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        }
570fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        return 0;
571fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri    };
572fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri
57369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    private static boolean equalsByteArrayList(
57469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            List<byte[]> signatures, List<byte[]> requestSignatures) {
575fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        if (signatures.size() != requestSignatures.size()) {
576fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            return false;
577fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        }
578fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        for (int i = 0; i < signatures.size(); ++i) {
579fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            if (!Arrays.equals(signatures.get(i), requestSignatures.get(i))) {
580fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri                return false;
581fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            }
582fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        }
583fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        return true;
5843c4be77db95ea716889568bde853be082e764da9Clara Bayarri    }
5853c4be77db95ea716889568bde853be082e764da9Clara Bayarri
58669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    private static List<byte[]> convertToByteArrayList(Signature[] signatures) {
587fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        List<byte[]> shas = new ArrayList<>();
588fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        for (int i = 0; i < signatures.length; ++i) {
589fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            shas.add(signatures[i].toByteArray());
590fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        }
5913c4be77db95ea716889568bde853be082e764da9Clara Bayarri        return shas;
5923c4be77db95ea716889568bde853be082e764da9Clara Bayarri    }
5933c4be77db95ea716889568bde853be082e764da9Clara Bayarri
5943c4be77db95ea716889568bde853be082e764da9Clara Bayarri    /** @hide */
5953c4be77db95ea716889568bde853be082e764da9Clara Bayarri    @VisibleForTesting
59669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka    public static @NonNull FontInfo[] getFontFromProvider(
59769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            Context context, FontRequest request, String authority,
59869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka            CancellationSignal cancellationSignal) throws InvalidFormatException {
59969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        ArrayList<FontInfo> result = new ArrayList<>();
60043c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka        final Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
6013c4be77db95ea716889568bde853be082e764da9Clara Bayarri                .authority(authority)
602b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                .build();
60343c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka        final Uri fileBaseUri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
60443c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                .authority(authority)
60543c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                .appendPath("file")
60643c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                .build();
60769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        try (Cursor cursor = context.getContentResolver().query(uri, new String[] { Columns._ID,
60843c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                        Columns.FILE_ID, Columns.TTC_INDEX, Columns.VARIATION_SETTINGS,
60943c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                        Columns.STYLE, Columns.WEIGHT, Columns.ITALIC, Columns.RESULT_CODE },
61069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                "query = ?", new String[] { request.getQuery() }, null, cancellationSignal);) {
611b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            // TODO: Should we restrict the amount of fonts that can be returned?
612b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            // TODO: Write documentation explaining that all results should be from the same family.
613b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            if (cursor != null && cursor.getCount() > 0) {
614bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                final int resultCodeColumnIndex = cursor.getColumnIndex(Columns.RESULT_CODE);
615b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                result = new ArrayList<>();
616bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                final int idColumnIndex = cursor.getColumnIndexOrThrow(Columns._ID);
61743c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                final int fileIdColumnIndex = cursor.getColumnIndex(Columns.FILE_ID);
618b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                final int ttcIndexColumnIndex = cursor.getColumnIndex(Columns.TTC_INDEX);
619b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                final int vsColumnIndex = cursor.getColumnIndex(Columns.VARIATION_SETTINGS);
620fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka                final int weightColumnIndex = cursor.getColumnIndex(Columns.WEIGHT);
621fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka                final int italicColumnIndex = cursor.getColumnIndex(Columns.ITALIC);
622b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                final int styleColumnIndex = cursor.getColumnIndex(Columns.STYLE);
623b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                while (cursor.moveToNext()) {
62469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    int resultCode = resultCodeColumnIndex != -1
625bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                            ? cursor.getInt(resultCodeColumnIndex) : Columns.RESULT_CODE_OK;
62669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    final int ttcIndex = ttcIndexColumnIndex != -1
62769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                            ? cursor.getInt(ttcIndexColumnIndex) : 0;
62869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    final String variationSettings = vsColumnIndex != -1
62969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                            ? cursor.getString(vsColumnIndex) : null;
63069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka
63143c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                    Uri fileUri;
63243c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                    if (fileIdColumnIndex == -1) {
63343c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                        long id = cursor.getLong(idColumnIndex);
63443c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                        fileUri = ContentUris.withAppendedId(uri, id);
63543c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                    } else {
63643c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                        long id = cursor.getLong(fileIdColumnIndex);
63743c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                        fileUri = ContentUris.withAppendedId(fileBaseUri, id);
63843c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                    }
63969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    // TODO: Stop using STYLE column and enforce WEIGHT/ITALIC column.
64069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    int weight;
64169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    boolean italic;
64269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    if (weightColumnIndex != -1 && italicColumnIndex != -1) {
64369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        weight = cursor.getInt(weightColumnIndex);
64469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        italic = cursor.getInt(italicColumnIndex) == 1;
64569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    } else if (styleColumnIndex != -1) {
64669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        final int style = cursor.getInt(styleColumnIndex);
64769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        weight = (style & Typeface.BOLD) != 0 ?
64869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                                Typeface.Builder.BOLD_WEIGHT : Typeface.Builder.NORMAL_WEIGHT;
64969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        italic = (style & Typeface.ITALIC) != 0;
65069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    } else {
65169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        weight = Typeface.Builder.NORMAL_WEIGHT;
65269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                        italic = false;
653b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                    }
65469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    FontVariationAxis[] axes =
65569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                            FontVariationAxis.fromFontVariationSettings(variationSettings);
65669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka                    result.add(new FontInfo(fileUri, ttcIndex, axes, weight, italic, resultCode));
657b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                }
658b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            }
659b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        }
66069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka        return result.toArray(new FontInfo[0]);
661b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    }
662b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri}
663