FontsContract.java revision b0812a30499376e09e2deb5995e998c629f24985
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 18b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.app.ActivityThread; 19b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.content.ContentResolver; 20b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.content.ContentUris; 21b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.content.Context; 22b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.content.pm.PackageManager; 23b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.content.pm.ProviderInfo; 24b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.database.Cursor; 25b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.graphics.fonts.FontRequest; 26b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.graphics.fonts.FontResult; 27b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.net.Uri; 28b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.os.Bundle; 29b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.os.Handler; 30b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.os.HandlerThread; 31b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.os.ParcelFileDescriptor; 32b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.os.Process; 33b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.os.ResultReceiver; 34b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.util.Log; 35b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri 36b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport com.android.internal.annotations.GuardedBy; 37b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri 38b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport java.io.FileNotFoundException; 39b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport java.util.ArrayList; 40b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri 41b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri/** 42b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * Utility class to deal with Font ContentProviders. 43b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri */ 44b0812a30499376e09e2deb5995e998c629f24985Clara Bayarripublic class FontsContract { 45b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri private static final String TAG = "FontsContract"; 46b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri 47b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri /** 48b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * Defines the constants used in a response from a Font Provider. The cursor returned from the 49b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * query should have the ID column populated with the content uri ID for the resulting font. 50b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * This should point to a real file or shared memory, as the client will mmap the given file 51b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * descriptor. Pipes, sockets and other non-mmap-able file descriptors will fail to load in the 52b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * client application. 53b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri */ 54b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri public static final class Columns implements BaseColumns { 55b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri /** 56b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * Constant used to request data from a font provider. The cursor returned from the query 57b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * should have this column populated with an int for the ttc index for the resulting font. 58b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri */ 59b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri public static final String TTC_INDEX = "font_ttc_index"; 60b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri /** 61b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * Constant used to request data from a font provider. The cursor returned from the query 62b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * may populate this column with the font variation settings String information for the 63b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * font. 64b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri */ 65b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri public static final String VARIATION_SETTINGS = "font_variation_settings"; 66b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri /** 67b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * Constant used to request data from a font provider. The cursor returned from the query 68b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * should have this column populated with the int style for the resulting font. This should 69b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * be one of {@link android.graphics.Typeface#NORMAL}, 70b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * {@link android.graphics.Typeface#BOLD}, {@link android.graphics.Typeface#ITALIC} or 71b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * {@link android.graphics.Typeface#BOLD_ITALIC} 72b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri */ 73b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri public static final String STYLE = "font_style"; 74b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri } 75b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri 76b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri /** 77b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * Constant used to identify the List of {@link ParcelFileDescriptor} item in the Bundle 78b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * returned to the ResultReceiver in getFont. 79b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * @hide 80b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri */ 81b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri public static final String PARCEL_FONT_RESULTS = "font_results"; 82b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri 83b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri /** @hide */ 84b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri public static final int RESULT_CODE_OK = 0; 85b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri /** @hide */ 86b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri public static final int RESULT_CODE_FONT_NOT_FOUND = 1; 87b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri /** @hide */ 88b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri public static final int RESULT_CODE_PROVIDER_NOT_FOUND = 2; 89b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri 90b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri private static final int THREAD_RENEWAL_THRESHOLD_MS = 10000; 91b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri 92b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri private final Context mContext; 93b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri private final PackageManager mPackageManager; 94b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri private final Object mLock = new Object(); 95b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri @GuardedBy("mLock") 96b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri private Handler mHandler; 97b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri @GuardedBy("mLock") 98b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri private HandlerThread mThread; 99b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri 100b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri /** @hide */ 101b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri public FontsContract() { 102b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri // TODO: investigate if the system context is the best option here. ApplicationContext or 103b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri // the one passed by developer? 104b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri // TODO: Looks like ActivityThread.currentActivityThread() can return null. Check when it 105b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri // returns null and check if we need to handle null case. 106b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri mContext = ActivityThread.currentActivityThread().getSystemContext(); 107b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri mPackageManager = mContext.getPackageManager(); 108b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri } 109b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri 110b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri // We use a background thread to post the content resolving work for all requests on. This 111b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri // thread should be quit/stopped after all requests are done. 112b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri private final Runnable mReplaceDispatcherThreadRunnable = new Runnable() { 113b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri @Override 114b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri public void run() { 115b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri synchronized (mLock) { 116b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri if (mThread != null) { 117b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri mThread.quitSafely(); 118b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri mThread = null; 119b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri mHandler = null; 120b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri } 121b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri } 122b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri } 123b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri }; 124b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri 125b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri /** 126b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * @hide 127b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri */ 128b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri public void getFont(FontRequest request, ResultReceiver receiver) { 129b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri synchronized (mLock) { 130b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri if (mHandler == null) { 131b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri mThread = new HandlerThread("fonts", Process.THREAD_PRIORITY_BACKGROUND); 132b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri mThread.start(); 133b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri mHandler = new Handler(mThread.getLooper()); 134b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri } 135b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri mHandler.post(() -> { 136b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri String providerAuthority = request.getProviderAuthority(); 137b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri // TODO: Implement cert checking for non-system apps 138b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri ProviderInfo providerInfo = mPackageManager.resolveContentProvider( 139b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri providerAuthority, PackageManager.MATCH_SYSTEM_ONLY); 140b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri if (providerInfo == null) { 141b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri receiver.send(RESULT_CODE_PROVIDER_NOT_FOUND, null); 142b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri return; 143b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri } 144b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri Bundle result = getFontFromProvider(request, receiver, providerInfo); 145b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri if (result == null) { 146b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri receiver.send(RESULT_CODE_FONT_NOT_FOUND, null); 147b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri return; 148b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri } 149b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri receiver.send(RESULT_CODE_OK, result); 150b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri }); 151b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri mHandler.removeCallbacks(mReplaceDispatcherThreadRunnable); 152b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri mHandler.postDelayed(mReplaceDispatcherThreadRunnable, THREAD_RENEWAL_THRESHOLD_MS); 153b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri } 154b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri } 155b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri 156b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri private Bundle getFontFromProvider(FontRequest request, ResultReceiver receiver, 157b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri ProviderInfo providerInfo) { 158b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri ArrayList<FontResult> result = null; 159b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT) 160b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri .authority(providerInfo.authority) 161b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri .build(); 162b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri try (Cursor cursor = mContext.getContentResolver().query(uri, new String[] { Columns._ID, 163b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri Columns.TTC_INDEX, Columns.VARIATION_SETTINGS, Columns.STYLE }, 164b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri "query = ?", new String[] { request.getQuery() }, null);) { 165b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri // TODO: Should we restrict the amount of fonts that can be returned? 166b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri // TODO: Write documentation explaining that all results should be from the same family. 167b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri if (cursor != null && cursor.getCount() > 0) { 168b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri result = new ArrayList<>(); 169b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri final int idColumnIndex = cursor.getColumnIndex(Columns._ID); 170b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri final int ttcIndexColumnIndex = cursor.getColumnIndex(Columns.TTC_INDEX); 171b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri final int vsColumnIndex = cursor.getColumnIndex(Columns.VARIATION_SETTINGS); 172b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri final int styleColumnIndex = cursor.getColumnIndex(Columns.STYLE); 173b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri while (cursor.moveToNext()) { 174b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri long id = cursor.getLong(idColumnIndex); 175b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri Uri fileUri = ContentUris.withAppendedId(uri, id); 176b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri try { 177b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri ParcelFileDescriptor pfd = 178b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri mContext.getContentResolver().openFileDescriptor(fileUri, "r"); 179b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri final int ttcIndex = cursor.getInt(ttcIndexColumnIndex); 180b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri final String variationSettings = cursor.getString(vsColumnIndex); 181b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri final int style = cursor.getInt(styleColumnIndex); 182b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri result.add(new FontResult(pfd, ttcIndex, variationSettings, style)); 183b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri } catch (FileNotFoundException e) { 184b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri Log.e(TAG, "FileNotFoundException raised when interacting with content " 185b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri + "provider " + providerInfo.authority, e); 186b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri } 187b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri } 188b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri } 189b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri } 190b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri if (result != null && !result.isEmpty()) { 191b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri Bundle bundle = new Bundle(); 192b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri bundle.putParcelableArrayList(PARCEL_FONT_RESULTS, result); 193b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri return bundle; 194b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri } 195b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri return null; 196b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri } 197b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri} 198