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 java.lang.annotation.RetentionPolicy.SOURCE; 1969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka 2069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport android.annotation.IntDef; 2169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport android.annotation.IntRange; 2269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport android.annotation.NonNull; 2369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport android.annotation.Nullable; 24b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.content.ContentResolver; 25b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.content.ContentUris; 26b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.content.Context; 273c4be77db95ea716889568bde853be082e764da9Clara Bayarriimport android.content.pm.PackageInfo; 2869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport android.content.pm.PackageManager.NameNotFoundException; 29b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.content.pm.PackageManager; 30b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.content.pm.ProviderInfo; 313c4be77db95ea716889568bde853be082e764da9Clara Bayarriimport android.content.pm.Signature; 32b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.database.Cursor; 333c4be77db95ea716889568bde853be082e764da9Clara Bayarriimport android.graphics.Typeface; 3469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport android.graphics.fonts.FontVariationAxis; 35b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.net.Uri; 36b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.os.Bundle; 3769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport android.os.CancellationSignal; 38b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.os.Handler; 39b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.os.HandlerThread; 40b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.os.ParcelFileDescriptor; 41b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.os.Process; 42b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.os.ResultReceiver; 435a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonakaimport android.util.ArraySet; 44b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.util.Log; 45daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonakaimport android.util.LruCache; 46b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri 47b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport com.android.internal.annotations.GuardedBy; 483c4be77db95ea716889568bde853be082e764da9Clara Bayarriimport com.android.internal.annotations.VisibleForTesting; 4969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport com.android.internal.util.Preconditions; 50b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri 5169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport java.io.FileInputStream; 52b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport java.io.FileNotFoundException; 53bacf2352ab892724551431551ae973ae3b68db35Clara Bayarriimport java.io.IOException; 5469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport java.lang.annotation.Retention; 5569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport java.lang.annotation.RetentionPolicy; 5669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport java.nio.ByteBuffer; 5769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport java.nio.channels.FileChannel; 58b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport java.util.ArrayList; 59fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarriimport java.util.Arrays; 60fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarriimport java.util.Collections; 61fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarriimport java.util.Comparator; 6269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport java.util.HashMap; 633c4be77db95ea716889568bde853be082e764da9Clara Bayarriimport java.util.List; 6469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonakaimport java.util.Map; 655a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonakaimport java.util.Set; 66d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonakaimport java.util.concurrent.TimeUnit; 67d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonakaimport java.util.concurrent.locks.Condition; 68d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonakaimport java.util.concurrent.locks.Lock; 69d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonakaimport java.util.concurrent.locks.ReentrantLock; 70d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonakaimport java.util.concurrent.atomic.AtomicBoolean; 71d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonakaimport java.util.concurrent.atomic.AtomicReference; 72b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri 73b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri/** 74b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * Utility class to deal with Font ContentProviders. 75b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri */ 76b0812a30499376e09e2deb5995e998c629f24985Clara Bayarripublic class FontsContract { 77b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri private static final String TAG = "FontsContract"; 78b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri 79b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri /** 80b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * Defines the constants used in a response from a Font Provider. The cursor returned from the 81b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * query should have the ID column populated with the content uri ID for the resulting font. 82b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * This should point to a real file or shared memory, as the client will mmap the given file 83b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * descriptor. Pipes, sockets and other non-mmap-able file descriptors will fail to load in the 84b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * client application. 85b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri */ 86b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri public static final class Columns implements BaseColumns { 877fea2e264e2e793586bb999ee80897d488e62141Clara Bayarri 887fea2e264e2e793586bb999ee80897d488e62141Clara Bayarri // Do not instantiate. 897fea2e264e2e793586bb999ee80897d488e62141Clara Bayarri private Columns() {} 907fea2e264e2e793586bb999ee80897d488e62141Clara Bayarri 91b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri /** 92b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * Constant used to request data from a font provider. The cursor returned from the query 9343c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka * may populate this column with a long for the font file ID. The client will request a file 9443c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka * descriptor to "file/FILE_ID" with this ID immediately under the top-level content URI. If 9543c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka * not present, the client will request a file descriptor to the top-level URI with the 9643c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka * given base font ID. Note that several results may return the same file ID, e.g. for TTC 9743c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka * files with different indices. 9843c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka */ 9943c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka public static final String FILE_ID = "file_id"; 10043c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka /** 10143c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka * Constant used to request data from a font provider. The cursor returned from the query 102b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * should have this column populated with an int for the ttc index for the resulting font. 103b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri */ 104b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri public static final String TTC_INDEX = "font_ttc_index"; 105b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri /** 106b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * Constant used to request data from a font provider. The cursor returned from the query 107b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * may populate this column with the font variation settings String information for the 108b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * font. 109b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri */ 110b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri public static final String VARIATION_SETTINGS = "font_variation_settings"; 111b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri /** 112bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri * Constant used to request data from a font provider. The cursor returned from the query 113fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka * should have this column populated with the int weight for the resulting font. This value 114fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka * should be between 100 and 900. The most common values are 400 for regular weight and 700 115fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka * for bold weight. 116fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka */ 117fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka public static final String WEIGHT = "font_weight"; 118fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka /** 119fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka * Constant used to request data from a font provider. The cursor returned from the query 120fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka * should have this column populated with the int italic for the resulting font. This should 121fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka * be 0 for regular style and 1 for italic. 122fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka */ 123fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka public static final String ITALIC = "font_italic"; 124fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka /** 125fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka * Constant used to request data from a font provider. The cursor returned from the query 126bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri * should have this column populated to indicate the result status of the 127bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri * query. This will be checked before any other data in the cursor. Possible values are 128bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri * {@link #RESULT_CODE_OK}, {@link #RESULT_CODE_FONT_NOT_FOUND}, 1295706a1b12dd891098fb7bf479623d42979171144Clara Bayarri * {@link #RESULT_CODE_MALFORMED_QUERY} and {@link #RESULT_CODE_FONT_UNAVAILABLE} for system 1305706a1b12dd891098fb7bf479623d42979171144Clara Bayarri * defined values. You may also define your own values in the 0x000010000..0xFFFF0000 range. 1315706a1b12dd891098fb7bf479623d42979171144Clara Bayarri * If not present, {@link #RESULT_CODE_OK} will be assumed. 132bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri */ 133bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri public static final String RESULT_CODE = "result_code"; 134bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri 135bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri /** 136bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri * Constant used to represent a result was retrieved successfully. The given fonts will be 137bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri * attempted to retrieve immediately via 138bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri * {@link android.content.ContentProvider#openFile(Uri, String)}. See {@link #RESULT_CODE}. 139bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri */ 140bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri public static final int RESULT_CODE_OK = 0; 141bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri /** 142bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri * Constant used to represent a result was not found. See {@link #RESULT_CODE}. 143bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri */ 144bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri public static final int RESULT_CODE_FONT_NOT_FOUND = 1; 145bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri /** 146bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri * Constant used to represent a result was found, but cannot be provided at this moment. Use 147bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri * this to indicate, for example, that a font needs to be fetched from the network. See 148bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri * {@link #RESULT_CODE}. 149bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri */ 150bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri public static final int RESULT_CODE_FONT_UNAVAILABLE = 2; 151bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri /** 152bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri * Constant used to represent that the query was not in a supported format by the provider. 153bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri * See {@link #RESULT_CODE}. 154bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri */ 155bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri public static final int RESULT_CODE_MALFORMED_QUERY = 3; 156b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri } 157b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri 15854084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka private static final Object sLock = new Object(); 15954084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka @GuardedBy("sLock") 16054084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka private static Handler sHandler; 16154084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka @GuardedBy("sLock") 16254084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka private static HandlerThread sThread; 16354084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka @GuardedBy("sLock") 16454084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka private static Set<String> sInQueueSet; 165b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri 16654084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka private volatile static Context sContext; // set once in setApplicationContextForResources 167b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri 168daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka private static final LruCache<String, Typeface> sTypefaceCache = new LruCache<>(16); 169daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka 17054084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka private FontsContract() { 17154084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka } 17254084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka 173b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri /** @hide */ 17454084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka public static void setApplicationContextForResources(Context context) { 17554084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka sContext = context.getApplicationContext(); 176b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri } 177b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri 17869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka /** 17969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * Object represent a font entry in the family returned from {@link #fetchFonts}. 18069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka */ 18169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka public static class FontInfo { 18269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka private final Uri mUri; 18369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka private final int mTtcIndex; 18469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka private final FontVariationAxis[] mAxes; 18569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka private final int mWeight; 18669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka private final boolean mItalic; 18769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka private final int mResultCode; 18869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka 18969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka /** 19069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * Creates a Font with all the information needed about a provided font. 19169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * @param uri A URI associated to the font file. 19269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * @param ttcIndex If providing a TTC_INDEX file, the index to point to. Otherwise, 0. 19369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * @param axes If providing a variation font, the settings for it. May be null. 19469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * @param weight An integer that indicates the font weight. 19569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * @param italic A boolean that indicates the font is italic style or not. 19669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * @param resultCode A boolean that indicates the font contents is ready. 19769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka */ 19869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka /** @hide */ 19969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka public FontInfo(@NonNull Uri uri, @IntRange(from = 0) int ttcIndex, 20069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka @Nullable FontVariationAxis[] axes, @IntRange(from = 1, to = 1000) int weight, 20169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka boolean italic, int resultCode) { 20269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka mUri = Preconditions.checkNotNull(uri); 20369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka mTtcIndex = ttcIndex; 20469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka mAxes = axes; 20569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka mWeight = weight; 20669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka mItalic = italic; 20769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka mResultCode = resultCode; 20869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka } 20969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka 21069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka /** 21169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * Returns a URI associated to this record. 21269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka */ 21369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka public @NonNull Uri getUri() { 21469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka return mUri; 21569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka } 21669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka 21769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka /** 21869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * Returns the index to be used to access this font when accessing a TTC file. 21969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka */ 22069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka public @IntRange(from = 0) int getTtcIndex() { 22169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka return mTtcIndex; 22269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka } 22369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka 22469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka /** 22569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * Returns the list of axes associated to this font. 22669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka */ 22769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka public @Nullable FontVariationAxis[] getAxes() { 22869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka return mAxes; 22969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka } 23069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka 23169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka /** 23269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * Returns the weight value for this font. 23369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka */ 23469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka public @IntRange(from = 1, to = 1000) int getWeight() { 23569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka return mWeight; 23669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka } 23769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka 23869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka /** 23969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * Returns whether this font is italic. 24069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka */ 24169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka public boolean isItalic() { 24269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka return mItalic; 24369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka } 24469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka 24569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka /** 24669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * Returns result code. 24769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * 24869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * {@link FontsContract.Columns#RESULT_CODE} 24969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka */ 25069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka public int getResultCode() { 25169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka return mResultCode; 25269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka } 25369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka } 25469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka 25569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka /** 25669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * Object returned from {@link #fetchFonts}. 25769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka */ 25869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka public static class FontFamilyResult { 25969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka /** 26069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * Constant represents that the font was successfully retrieved. Note that when this value 26169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * is set and {@link #getFonts} returns an empty array, it means there were no fonts 26269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * matching the given query. 26369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka */ 26469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka public static final int STATUS_OK = 0; 26569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka 26669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka /** 26769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * Constant represents that the given certificate was not matched with the provider's 26869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * signature. {@link #getFonts} returns null if this status was set. 26969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka */ 27069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka public static final int STATUS_WRONG_CERTIFICATES = 1; 27169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka 27269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka /** 27369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * Constant represents that the provider returns unexpected data. {@link #getFonts} returns 27469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * null if this status was set. For example, this value is set when the font provider 27569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * gives invalid format of variation settings. 27669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka */ 27769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka public static final int STATUS_UNEXPECTED_DATA_PROVIDED = 2; 27869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka 279ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka /** 280ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka * Constant represents that the fetching font data was rejected by system. This happens if 281ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka * the passed context is restricted. 282ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka */ 283ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka public static final int STATUS_REJECTED = 3; 284ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka 28569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka /** @hide */ 286ce8db9911494225fcd99711d7df85a130de5a6ceJeff Sharkey @IntDef(prefix = { "STATUS_" }, value = { 287ce8db9911494225fcd99711d7df85a130de5a6ceJeff Sharkey STATUS_OK, 288ce8db9911494225fcd99711d7df85a130de5a6ceJeff Sharkey STATUS_WRONG_CERTIFICATES, 289ce8db9911494225fcd99711d7df85a130de5a6ceJeff Sharkey STATUS_UNEXPECTED_DATA_PROVIDED 290ce8db9911494225fcd99711d7df85a130de5a6ceJeff Sharkey }) 29169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka @Retention(RetentionPolicy.SOURCE) 29269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka @interface FontResultStatus {} 29369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka 29469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka private final @FontResultStatus int mStatusCode; 29569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka private final FontInfo[] mFonts; 29669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka 29769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka /** @hide */ 29869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka public FontFamilyResult(@FontResultStatus int statusCode, @Nullable FontInfo[] fonts) { 29969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka mStatusCode = statusCode; 30069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka mFonts = fonts; 30169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka } 30269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka 30369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka public @FontResultStatus int getStatusCode() { 30469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka return mStatusCode; 30569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka } 30669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka 30769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka public @NonNull FontInfo[] getFonts() { 30869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka return mFonts; 30969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka } 3103c4be77db95ea716889568bde853be082e764da9Clara Bayarri } 3113c4be77db95ea716889568bde853be082e764da9Clara Bayarri 31254084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka private static final int THREAD_RENEWAL_THRESHOLD_MS = 10000; 31354084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka 314d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka private static final long SYNC_FONT_FETCH_TIMEOUT_MS = 500; 315d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka 316b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri // We use a background thread to post the content resolving work for all requests on. This 317b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri // thread should be quit/stopped after all requests are done. 31854084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka // TODO: Factor out to other class. Consider to switch MessageQueue.IdleHandler. 31954084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka private static final Runnable sReplaceDispatcherThreadRunnable = new Runnable() { 320b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri @Override 321b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri public void run() { 32254084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka synchronized (sLock) { 32354084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka if (sThread != null) { 32454084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka sThread.quitSafely(); 32554084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka sThread = null; 32654084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka sHandler = null; 327b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri } 328b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri } 329b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri } 330b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri }; 331b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri 332bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri /** @hide */ 333d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka public static Typeface getFontSync(FontRequest request) { 3345a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka final String id = request.getIdentifier(); 3355a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka Typeface cachedTypeface = sTypefaceCache.get(id); 3365a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka if (cachedTypeface != null) { 3375a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka return cachedTypeface; 3385a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka } 3395a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka 3405a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka // Unfortunately the typeface is not available at this time, but requesting from the font 3415a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka // provider takes too much time. For now, request the font data to ensure it is in the cache 3425a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka // next time and return. 34354084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka synchronized (sLock) { 34454084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka if (sHandler == null) { 34554084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka sThread = new HandlerThread("fonts", Process.THREAD_PRIORITY_BACKGROUND); 34654084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka sThread.start(); 34754084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka sHandler = new Handler(sThread.getLooper()); 3485a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka } 349d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka final Lock lock = new ReentrantLock(); 350d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka final Condition cond = lock.newCondition(); 351d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka final AtomicReference<Typeface> holder = new AtomicReference<>(); 352d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka final AtomicBoolean waiting = new AtomicBoolean(true); 353d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka final AtomicBoolean timeout = new AtomicBoolean(false); 354d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka 35554084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka sHandler.post(() -> { 35669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka try { 35754084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka FontFamilyResult result = fetchFonts(sContext, null, request); 3585a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka if (result.getStatusCode() == FontFamilyResult.STATUS_OK) { 35954084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka Typeface typeface = buildTypeface(sContext, null, result.getFonts()); 3605a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka if (typeface != null) { 3615a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka sTypefaceCache.put(id, typeface); 36269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka } 363d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka holder.set(typeface); 36469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka } 3655a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka } catch (NameNotFoundException e) { 3665a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka // Ignore. 36769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka } 368d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka lock.lock(); 369d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka try { 370d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka if (!timeout.get()) { 371d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka waiting.set(false); 372d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka cond.signal(); 373d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka } 374d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka } finally { 375d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka lock.unlock(); 376d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka } 377b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri }); 37854084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka sHandler.removeCallbacks(sReplaceDispatcherThreadRunnable); 37954084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka sHandler.postDelayed(sReplaceDispatcherThreadRunnable, THREAD_RENEWAL_THRESHOLD_MS); 380d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka 381d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka long remaining = TimeUnit.MILLISECONDS.toNanos(SYNC_FONT_FETCH_TIMEOUT_MS); 382d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka lock.lock(); 383d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka try { 384d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka if (!waiting.get()) { 385d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka return holder.get(); 386d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka } 387d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka for (;;) { 388d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka try { 389d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka remaining = cond.awaitNanos(remaining); 390d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka } catch (InterruptedException e) { 391d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka // do nothing. 392d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka } 393d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka if (!waiting.get()) { 394d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka return holder.get(); 395d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka } 396d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka if (remaining <= 0) { 397d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka timeout.set(true); 398d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka Log.w(TAG, "Remote font fetch timed out: " + 399d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka request.getProviderAuthority() + "/" + request.getQuery()); 400d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka return null; 401d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka } 402d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka } 403d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka } finally { 404d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka lock.unlock(); 405d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka } 406b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri } 407b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri } 408b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri 40969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka /** 4100b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka * Interface used to receive asynchronously fetched typefaces. 4110b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka */ 4120b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka public static class FontRequestCallback { 4130b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka /** 4140b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given 4150b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka * provider was not found on the device. 4160b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka */ 41754084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka public static final int FAIL_REASON_PROVIDER_NOT_FOUND = -1; 4180b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka /** 4190b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given 4200b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka * provider must be authenticated and the given certificates do not match its signature. 4210b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka */ 42254084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka public static final int FAIL_REASON_WRONG_CERTIFICATES = -2; 4230b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka /** 4240b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the font 4250b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka * returned by the provider was not loaded properly. 4260b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka */ 4270b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka public static final int FAIL_REASON_FONT_LOAD_ERROR = -3; 4280b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka /** 4290b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the font 4300b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka * provider did not return any results for the given query. 4310b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka */ 4320b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka public static final int FAIL_REASON_FONT_NOT_FOUND = Columns.RESULT_CODE_FONT_NOT_FOUND; 4330b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka /** 4340b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the font 4350b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka * provider found the queried font, but it is currently unavailable. 4360b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka */ 4370b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka public static final int FAIL_REASON_FONT_UNAVAILABLE = Columns.RESULT_CODE_FONT_UNAVAILABLE; 4380b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka /** 4390b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given 4400b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka * query was not supported by the provider. 4410b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka */ 4420b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka public static final int FAIL_REASON_MALFORMED_QUERY = Columns.RESULT_CODE_MALFORMED_QUERY; 4430b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka 4440b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka /** @hide */ 445ce8db9911494225fcd99711d7df85a130de5a6ceJeff Sharkey @IntDef(prefix = { "FAIL_" }, value = { 446ce8db9911494225fcd99711d7df85a130de5a6ceJeff Sharkey FAIL_REASON_PROVIDER_NOT_FOUND, 447ce8db9911494225fcd99711d7df85a130de5a6ceJeff Sharkey FAIL_REASON_FONT_LOAD_ERROR, 448ce8db9911494225fcd99711d7df85a130de5a6ceJeff Sharkey FAIL_REASON_FONT_NOT_FOUND, 449ce8db9911494225fcd99711d7df85a130de5a6ceJeff Sharkey FAIL_REASON_FONT_UNAVAILABLE, 450ce8db9911494225fcd99711d7df85a130de5a6ceJeff Sharkey FAIL_REASON_MALFORMED_QUERY 451ce8db9911494225fcd99711d7df85a130de5a6ceJeff Sharkey }) 4520b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka @Retention(RetentionPolicy.SOURCE) 4530b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka @interface FontRequestFailReason {} 4540b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka 4550b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka public FontRequestCallback() {} 4560b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka 4570b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka /** 45867f9d5070a74a0bf34f0335899a96dedcac26c96Jeff Sharkey * Called then a Typeface request done via {@link #requestFonts} is complete. Note that this 4595a09c64345ba35783b5d24ed7c4ca0ea8afbcc0aSeigo Nonaka * method will not be called if {@link #onTypefaceRequestFailed(int)} is called instead. 4600b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka * @param typeface The Typeface object retrieved. 4610b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka */ 4620b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka public void onTypefaceRetrieved(Typeface typeface) {} 4630b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka 4640b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka /** 46567f9d5070a74a0bf34f0335899a96dedcac26c96Jeff Sharkey * Called when a Typeface request done via {@link #requestFonts}} fails. 4660b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka * @param reason One of {@link #FAIL_REASON_PROVIDER_NOT_FOUND}, 4670b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka * {@link #FAIL_REASON_FONT_NOT_FOUND}, 4680b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka * {@link #FAIL_REASON_FONT_LOAD_ERROR}, 4690b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka * {@link #FAIL_REASON_FONT_UNAVAILABLE} or 4705706a1b12dd891098fb7bf479623d42979171144Clara Bayarri * {@link #FAIL_REASON_MALFORMED_QUERY} if returned by the system. May also be 4715706a1b12dd891098fb7bf479623d42979171144Clara Bayarri * a positive value greater than 0 defined by the font provider as an 4725706a1b12dd891098fb7bf479623d42979171144Clara Bayarri * additional error code. Refer to the provider's documentation for more 4735706a1b12dd891098fb7bf479623d42979171144Clara Bayarri * information on possible returned error codes. 4740b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka */ 4750b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka public void onTypefaceRequestFailed(@FontRequestFailReason int reason) {} 4760b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka } 4770b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka 4780b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka /** 4790b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka * Create a typeface object given a font request. The font will be asynchronously fetched, 4800b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka * therefore the result is delivered to the given callback. See {@link FontRequest}. 4810b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka * Only one of the methods in callback will be invoked, depending on whether the request 4820b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka * succeeds or fails. These calls will happen on the caller thread. 483daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka * 484daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka * Note that the result Typeface may be cached internally and the same instance will be returned 485daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka * the next time you call this method with the same request. If you want to bypass this cache, 486daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka * use {@link #fetchFonts} and {@link #buildTypeface} instead. 487daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka * 4880b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka * @param context A context to be used for fetching from font provider. 4890b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka * @param request A {@link FontRequest} object that identifies the provider and query for the 4900b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka * request. May not be null. 4910b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka * @param handler A handler to be processed the font fetching. 4928ea62b036dd28231cb07beb210d361d9341c618eSeigo Nonaka * @param cancellationSignal A signal to cancel the operation in progress, or null if none. If 4938ea62b036dd28231cb07beb210d361d9341c618eSeigo Nonaka * the operation is canceled, then {@link 4948ea62b036dd28231cb07beb210d361d9341c618eSeigo Nonaka * android.os.OperationCanceledException} will be thrown. 4958ea62b036dd28231cb07beb210d361d9341c618eSeigo Nonaka * @param callback A callback that will be triggered when results are obtained. May not be null. 4960b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka */ 4978ea62b036dd28231cb07beb210d361d9341c618eSeigo Nonaka public static void requestFonts(@NonNull Context context, @NonNull FontRequest request, 4988ea62b036dd28231cb07beb210d361d9341c618eSeigo Nonaka @NonNull Handler handler, @Nullable CancellationSignal cancellationSignal, 4998ea62b036dd28231cb07beb210d361d9341c618eSeigo Nonaka @NonNull FontRequestCallback callback) { 5000b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka 5010b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka final Handler callerThreadHandler = new Handler(); 502daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka final Typeface cachedTypeface = sTypefaceCache.get(request.getIdentifier()); 503daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka if (cachedTypeface != null) { 504daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka callerThreadHandler.post(() -> callback.onTypefaceRetrieved(cachedTypeface)); 505daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka return; 506daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka } 507daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka 5080b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka handler.post(() -> { 5090b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka FontFamilyResult result; 5100b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka try { 5118ea62b036dd28231cb07beb210d361d9341c618eSeigo Nonaka result = fetchFonts(context, cancellationSignal, request); 5120b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka } catch (NameNotFoundException e) { 5130b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka callerThreadHandler.post(() -> callback.onTypefaceRequestFailed( 5140b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka FontRequestCallback.FAIL_REASON_PROVIDER_NOT_FOUND)); 5150b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka return; 5160b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka } 5170b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka 518daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka // Same request might be dispatched during fetchFonts. Check the cache again. 519daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka final Typeface anotherCachedTypeface = sTypefaceCache.get(request.getIdentifier()); 520daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka if (anotherCachedTypeface != null) { 521daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka callerThreadHandler.post(() -> callback.onTypefaceRetrieved(anotherCachedTypeface)); 522daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka return; 523daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka } 524daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka 5250b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka if (result.getStatusCode() != FontFamilyResult.STATUS_OK) { 5260b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka switch (result.getStatusCode()) { 5270b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka case FontFamilyResult.STATUS_WRONG_CERTIFICATES: 5280b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka callerThreadHandler.post(() -> callback.onTypefaceRequestFailed( 5290b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka FontRequestCallback.FAIL_REASON_WRONG_CERTIFICATES)); 5300b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka return; 5310b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka case FontFamilyResult.STATUS_UNEXPECTED_DATA_PROVIDED: 5320b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka callerThreadHandler.post(() -> callback.onTypefaceRequestFailed( 5330b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR)); 5340b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka return; 5350b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka default: 5360b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka // fetchFont returns unexpected status type. Fallback to load error. 5370b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka callerThreadHandler.post(() -> callback.onTypefaceRequestFailed( 5380b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR)); 5390b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka return; 5400b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka } 5410b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka } 5420b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka 5430b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka final FontInfo[] fonts = result.getFonts(); 5440b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka if (fonts == null || fonts.length == 0) { 5450b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka callerThreadHandler.post(() -> callback.onTypefaceRequestFailed( 5460b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka FontRequestCallback.FAIL_REASON_FONT_NOT_FOUND)); 5470b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka return; 5480b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka } 5490b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka for (final FontInfo font : fonts) { 5500b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka if (font.getResultCode() != Columns.RESULT_CODE_OK) { 5510b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka // We proceed if all font entry is ready to use. Otherwise report the first 5520b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka // error. 5530b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka final int resultCode = font.getResultCode(); 5540b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka if (resultCode < 0) { 5550b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka // Negative values are reserved for internal errors. Fallback to load error. 5560b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka callerThreadHandler.post(() -> callback.onTypefaceRequestFailed( 5570b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR)); 5580b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka } else { 5590b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka callerThreadHandler.post(() -> callback.onTypefaceRequestFailed( 5600b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka resultCode)); 5610b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka } 5620b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka return; 5630b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka } 5640b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka } 5650b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka 5668ea62b036dd28231cb07beb210d361d9341c618eSeigo Nonaka final Typeface typeface = buildTypeface(context, cancellationSignal, fonts); 5670b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka if (typeface == null) { 5680b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka // Something went wrong during reading font files. This happens if the given font 5690b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka // file is an unsupported font type. 5700b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka callerThreadHandler.post(() -> callback.onTypefaceRequestFailed( 5710b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR)); 5720b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka return; 5730b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka } 5740b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka 575daa8dfc690c4755510ccc15da5ed5bbdd9731fa4Seigo Nonaka sTypefaceCache.put(request.getIdentifier(), typeface); 5760b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka callerThreadHandler.post(() -> callback.onTypefaceRetrieved(typeface)); 5770b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka }); 5780b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka } 5790b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka 5800b73a4287e8f630c45bf7ef0a7e0b2541d6b4067Seigo Nonaka /** 58169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * Fetch fonts given a font request. 58269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * 58369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * @param context A {@link Context} to be used for fetching fonts. 58469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * @param cancellationSignal A signal to cancel the operation in progress, or null if none. If 58569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * the operation is canceled, then {@link 58669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * android.os.OperationCanceledException} will be thrown when the 58769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * query is executed. 58869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * @param request A {@link FontRequest} object that identifies the provider and query for the 58969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * request. 59069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * 59169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * @return {@link FontFamilyResult} 59269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * 59369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * @throws NameNotFoundException If requested package or authority was not found in system. 59469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka */ 59569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka public static @NonNull FontFamilyResult fetchFonts( 59669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka @NonNull Context context, @Nullable CancellationSignal cancellationSignal, 59769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka @NonNull FontRequest request) throws NameNotFoundException { 598ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka if (context.isRestricted()) { 599ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka // TODO: Should we allow if the peer process is system or myself? 600ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka return new FontFamilyResult(FontFamilyResult.STATUS_REJECTED, null); 601ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka } 60269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka ProviderInfo providerInfo = getProvider(context.getPackageManager(), request); 60369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka if (providerInfo == null) { 60469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka return new FontFamilyResult(FontFamilyResult.STATUS_WRONG_CERTIFICATES, null); 60569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka 60669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka } 60769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka try { 60869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka FontInfo[] fonts = getFontFromProvider( 60969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka context, request, providerInfo.authority, cancellationSignal); 61069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka return new FontFamilyResult(FontFamilyResult.STATUS_OK, fonts); 6110f07dd5b14e76695bbae758e948e00b86935232cSeigo Nonaka } catch (IllegalArgumentException e) { 61269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka return new FontFamilyResult(FontFamilyResult.STATUS_UNEXPECTED_DATA_PROVIDED, null); 61369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka } 61469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka } 61569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka 61669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka /** 61769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * Build a Typeface from an array of {@link FontInfo} 61869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * 61969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * Results that are marked as not ready will be skipped. 62069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * 62169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * @param context A {@link Context} that will be used to fetch the font contents. 62269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * @param cancellationSignal A signal to cancel the operation in progress, or null if none. If 62369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * the operation is canceled, then {@link 62469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * android.os.OperationCanceledException} will be thrown. 62569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * @param fonts An array of {@link FontInfo} to be used to create a Typeface. 62669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * @return A Typeface object. Returns null if typeface creation fails. 62769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka */ 62869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka public static Typeface buildTypeface(@NonNull Context context, 62969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka @Nullable CancellationSignal cancellationSignal, @NonNull FontInfo[] fonts) { 630ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka if (context.isRestricted()) { 631ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka // TODO: Should we allow if the peer process is system or myself? 632ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka return null; 633ebecd7e802cd65bfc5cf1d8de1e6ea031580ae79Seigo Nonaka } 63469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka final Map<Uri, ByteBuffer> uriBuffer = 63569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka prepareFontData(context, fonts, cancellationSignal); 636d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka if (uriBuffer.isEmpty()) { 637d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka return null; 638d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka } 63969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka return new Typeface.Builder(fonts, uriBuffer).build(); 64069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka } 64169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka 64269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka /** 64369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * A helper function to create a mapping from {@link Uri} to {@link ByteBuffer}. 64469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * 64569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * Skip if the file contents is not ready to be read. 64669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * 64769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * @param context A {@link Context} to be used for resolving content URI in 64869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * {@link FontInfo}. 64969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * @param fonts An array of {@link FontInfo}. 65069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka * @return A map from {@link Uri} to {@link ByteBuffer}. 65169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka */ 65269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka private static Map<Uri, ByteBuffer> prepareFontData(Context context, FontInfo[] fonts, 65369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka CancellationSignal cancellationSignal) { 65469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka final HashMap<Uri, ByteBuffer> out = new HashMap<>(); 65569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka final ContentResolver resolver = context.getContentResolver(); 65669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka 65769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka for (FontInfo font : fonts) { 65869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka if (font.getResultCode() != Columns.RESULT_CODE_OK) { 65969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka continue; 66069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka } 66169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka 66269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka final Uri uri = font.getUri(); 66369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka if (out.containsKey(uri)) { 66469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka continue; 66569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka } 66669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka 66769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka ByteBuffer buffer = null; 66869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka try (final ParcelFileDescriptor pfd = 669d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka resolver.openFileDescriptor(uri, "r", cancellationSignal)) { 670d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka if (pfd != null) { 671d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka try (final FileInputStream fis = 672d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka new FileInputStream(pfd.getFileDescriptor())) { 673d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka final FileChannel fileChannel = fis.getChannel(); 674d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka final long size = fileChannel.size(); 675d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka buffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, size); 676d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka } catch (IOException e) { 677d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka // ignore 678d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka } 679d9de8be233d18ccc881cb647a5de2b32ff3e737cSeigo Nonaka } 68069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka } catch (IOException e) { 68169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka // ignore 68269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka } 68369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka 68469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka // TODO: try other approach?, e.g. read all contents instead of mmap. 68569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka 68669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka out.put(uri, buffer); 68769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka } 68869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka return Collections.unmodifiableMap(out); 68969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka } 69069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka 6913c4be77db95ea716889568bde853be082e764da9Clara Bayarri /** @hide */ 6923c4be77db95ea716889568bde853be082e764da9Clara Bayarri @VisibleForTesting 69369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka public static @Nullable ProviderInfo getProvider( 69469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka PackageManager packageManager, FontRequest request) throws NameNotFoundException { 6953c4be77db95ea716889568bde853be082e764da9Clara Bayarri String providerAuthority = request.getProviderAuthority(); 69669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka ProviderInfo info = packageManager.resolveContentProvider(providerAuthority, 0); 6973c4be77db95ea716889568bde853be082e764da9Clara Bayarri if (info == null) { 69869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka throw new NameNotFoundException("No package found for authority: " + providerAuthority); 6993c4be77db95ea716889568bde853be082e764da9Clara Bayarri } 7003c4be77db95ea716889568bde853be082e764da9Clara Bayarri 7013c4be77db95ea716889568bde853be082e764da9Clara Bayarri if (!info.packageName.equals(request.getProviderPackage())) { 70269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka throw new NameNotFoundException("Found content provider " + providerAuthority 70369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka + ", but package was not " + request.getProviderPackage()); 7043c4be77db95ea716889568bde853be082e764da9Clara Bayarri } 7053c4be77db95ea716889568bde853be082e764da9Clara Bayarri // Trust system apps without signature checks 7063c4be77db95ea716889568bde853be082e764da9Clara Bayarri if (info.applicationInfo.isSystemApp()) { 7073c4be77db95ea716889568bde853be082e764da9Clara Bayarri return info; 7083c4be77db95ea716889568bde853be082e764da9Clara Bayarri } 7093c4be77db95ea716889568bde853be082e764da9Clara Bayarri 710fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri List<byte[]> signatures; 71169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka PackageInfo packageInfo = packageManager.getPackageInfo(info.packageName, 71269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka PackageManager.GET_SIGNATURES); 71369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka signatures = convertToByteArrayList(packageInfo.signatures); 71469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka Collections.sort(signatures, sByteArrayComparator); 71569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka 7163c4be77db95ea716889568bde853be082e764da9Clara Bayarri List<List<byte[]>> requestCertificatesList = request.getCertificates(); 7173c4be77db95ea716889568bde853be082e764da9Clara Bayarri for (int i = 0; i < requestCertificatesList.size(); ++i) { 718fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri // Make a copy so we can sort it without modifying the incoming data. 719fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri List<byte[]> requestSignatures = new ArrayList<>(requestCertificatesList.get(i)); 720fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri Collections.sort(requestSignatures, sByteArrayComparator); 721fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri if (equalsByteArrayList(signatures, requestSignatures)) { 7223c4be77db95ea716889568bde853be082e764da9Clara Bayarri return info; 7233c4be77db95ea716889568bde853be082e764da9Clara Bayarri } 7243c4be77db95ea716889568bde853be082e764da9Clara Bayarri } 7253c4be77db95ea716889568bde853be082e764da9Clara Bayarri return null; 7263c4be77db95ea716889568bde853be082e764da9Clara Bayarri } 7273c4be77db95ea716889568bde853be082e764da9Clara Bayarri 728fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri private static final Comparator<byte[]> sByteArrayComparator = (l, r) -> { 729fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri if (l.length != r.length) { 730fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri return l.length - r.length; 7313c4be77db95ea716889568bde853be082e764da9Clara Bayarri } 732fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri for (int i = 0; i < l.length; ++i) { 733fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri if (l[i] != r[i]) { 734fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri return l[i] - r[i]; 735fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri } 736fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri } 737fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri return 0; 738fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri }; 739fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri 74069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka private static boolean equalsByteArrayList( 74169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka List<byte[]> signatures, List<byte[]> requestSignatures) { 742fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri if (signatures.size() != requestSignatures.size()) { 743fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri return false; 744fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri } 745fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri for (int i = 0; i < signatures.size(); ++i) { 746fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri if (!Arrays.equals(signatures.get(i), requestSignatures.get(i))) { 747fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri return false; 748fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri } 749fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri } 750fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri return true; 7513c4be77db95ea716889568bde853be082e764da9Clara Bayarri } 7523c4be77db95ea716889568bde853be082e764da9Clara Bayarri 75369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka private static List<byte[]> convertToByteArrayList(Signature[] signatures) { 754fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri List<byte[]> shas = new ArrayList<>(); 755fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri for (int i = 0; i < signatures.length; ++i) { 756fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri shas.add(signatures[i].toByteArray()); 757fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri } 7583c4be77db95ea716889568bde853be082e764da9Clara Bayarri return shas; 7593c4be77db95ea716889568bde853be082e764da9Clara Bayarri } 7603c4be77db95ea716889568bde853be082e764da9Clara Bayarri 7613c4be77db95ea716889568bde853be082e764da9Clara Bayarri /** @hide */ 7623c4be77db95ea716889568bde853be082e764da9Clara Bayarri @VisibleForTesting 76369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka public static @NonNull FontInfo[] getFontFromProvider( 76469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka Context context, FontRequest request, String authority, 7650f07dd5b14e76695bbae758e948e00b86935232cSeigo Nonaka CancellationSignal cancellationSignal) { 76669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka ArrayList<FontInfo> result = new ArrayList<>(); 76743c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka final Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT) 7683c4be77db95ea716889568bde853be082e764da9Clara Bayarri .authority(authority) 769b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri .build(); 77043c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka final Uri fileBaseUri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT) 77143c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka .authority(authority) 77243c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka .appendPath("file") 77343c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka .build(); 77469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka try (Cursor cursor = context.getContentResolver().query(uri, new String[] { Columns._ID, 77543c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka Columns.FILE_ID, Columns.TTC_INDEX, Columns.VARIATION_SETTINGS, 77654084b64b1860b652b1c50ba942b4cfc7fb28805Seigo Nonaka Columns.WEIGHT, Columns.ITALIC, Columns.RESULT_CODE }, 77769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka "query = ?", new String[] { request.getQuery() }, null, cancellationSignal);) { 778b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri // TODO: Should we restrict the amount of fonts that can be returned? 779b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri // TODO: Write documentation explaining that all results should be from the same family. 780b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri if (cursor != null && cursor.getCount() > 0) { 781bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri final int resultCodeColumnIndex = cursor.getColumnIndex(Columns.RESULT_CODE); 782b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri result = new ArrayList<>(); 783bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri final int idColumnIndex = cursor.getColumnIndexOrThrow(Columns._ID); 78443c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka final int fileIdColumnIndex = cursor.getColumnIndex(Columns.FILE_ID); 785b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri final int ttcIndexColumnIndex = cursor.getColumnIndex(Columns.TTC_INDEX); 786b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri final int vsColumnIndex = cursor.getColumnIndex(Columns.VARIATION_SETTINGS); 787fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka final int weightColumnIndex = cursor.getColumnIndex(Columns.WEIGHT); 788fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka final int italicColumnIndex = cursor.getColumnIndex(Columns.ITALIC); 789b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri while (cursor.moveToNext()) { 79069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka int resultCode = resultCodeColumnIndex != -1 791bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri ? cursor.getInt(resultCodeColumnIndex) : Columns.RESULT_CODE_OK; 79269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka final int ttcIndex = ttcIndexColumnIndex != -1 79369754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka ? cursor.getInt(ttcIndexColumnIndex) : 0; 79469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka final String variationSettings = vsColumnIndex != -1 79569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka ? cursor.getString(vsColumnIndex) : null; 79669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka 79743c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka Uri fileUri; 79843c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka if (fileIdColumnIndex == -1) { 79943c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka long id = cursor.getLong(idColumnIndex); 80043c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka fileUri = ContentUris.withAppendedId(uri, id); 80143c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka } else { 80243c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka long id = cursor.getLong(fileIdColumnIndex); 80343c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka fileUri = ContentUris.withAppendedId(fileBaseUri, id); 80443c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka } 80569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka int weight; 80669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka boolean italic; 80769754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka if (weightColumnIndex != -1 && italicColumnIndex != -1) { 80869754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka weight = cursor.getInt(weightColumnIndex); 80969754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka italic = cursor.getInt(italicColumnIndex) == 1; 81069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka } else { 81169754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka weight = Typeface.Builder.NORMAL_WEIGHT; 81269754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka italic = false; 813b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri } 81469754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka FontVariationAxis[] axes = 81569754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka FontVariationAxis.fromFontVariationSettings(variationSettings); 81669754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka result.add(new FontInfo(fileUri, ttcIndex, axes, weight, italic, resultCode)); 817b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri } 818b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri } 819b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri } 82069754bf66dae9d047d5a0ff2c71820aa35b9cc70Seigo Nonaka return result.toArray(new FontInfo[0]); 821b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri } 822b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri} 823