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