FontsContract.java revision 43c20cf6d4bd661d85bed76c78953aa656dbcc62
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.content.ContentResolver;
19b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.content.ContentUris;
20b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.content.Context;
213c4be77db95ea716889568bde853be082e764da9Clara Bayarriimport android.content.pm.PackageInfo;
22b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.content.pm.PackageManager;
23b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.content.pm.ProviderInfo;
243c4be77db95ea716889568bde853be082e764da9Clara Bayarriimport android.content.pm.Signature;
25b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.database.Cursor;
263c4be77db95ea716889568bde853be082e764da9Clara Bayarriimport android.graphics.Typeface;
27b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.graphics.fonts.FontRequest;
28b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.graphics.fonts.FontResult;
29b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.net.Uri;
30b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.os.Bundle;
31b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.os.Handler;
32b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.os.HandlerThread;
33b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.os.ParcelFileDescriptor;
34b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.os.Process;
35b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.os.ResultReceiver;
36b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport android.util.Log;
37b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
38b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport com.android.internal.annotations.GuardedBy;
393c4be77db95ea716889568bde853be082e764da9Clara Bayarriimport com.android.internal.annotations.VisibleForTesting;
40b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
41b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport java.io.FileNotFoundException;
42bacf2352ab892724551431551ae973ae3b68db35Clara Bayarriimport java.io.IOException;
43b0812a30499376e09e2deb5995e998c629f24985Clara Bayarriimport java.util.ArrayList;
44fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarriimport java.util.Arrays;
45fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarriimport java.util.Collections;
46fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarriimport java.util.Comparator;
473c4be77db95ea716889568bde853be082e764da9Clara Bayarriimport java.util.List;
48b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
49b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri/**
50b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri * Utility class to deal with Font ContentProviders.
51b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri */
52b0812a30499376e09e2deb5995e998c629f24985Clara Bayarripublic class FontsContract {
53b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    private static final String TAG = "FontsContract";
54b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
55b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    /**
56b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     * Defines the constants used in a response from a Font Provider. The cursor returned from the
57b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     * query should have the ID column populated with the content uri ID for the resulting font.
58b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     * This should point to a real file or shared memory, as the client will mmap the given file
59b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     * descriptor. Pipes, sockets and other non-mmap-able file descriptors will fail to load in the
60b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     * client application.
61b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     */
62b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    public static final class Columns implements BaseColumns {
63b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        /**
64b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri         * Constant used to request data from a font provider. The cursor returned from the query
6543c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka         * may populate this column with a long for the font file ID. The client will request a file
6643c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka         * descriptor to "file/FILE_ID" with this ID immediately under the top-level content URI. If
6743c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka         * not present, the client will request a file descriptor to the top-level URI with the
6843c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka         * given base font ID. Note that several results may return the same file ID, e.g. for TTC
6943c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka         * files with different indices.
7043c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka         */
7143c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka        public static final String FILE_ID = "file_id";
7243c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka        /**
7343c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka         * Constant used to request data from a font provider. The cursor returned from the query
74b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri         * should have this column populated with an int for the ttc index for the resulting font.
75b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri         */
76b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        public static final String TTC_INDEX = "font_ttc_index";
77b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        /**
78b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri         * Constant used to request data from a font provider. The cursor returned from the query
79b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri         * may populate this column with the font variation settings String information for the
80b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri         * font.
81b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri         */
82b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        public static final String VARIATION_SETTINGS = "font_variation_settings";
83b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        /**
84fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * DO NOT USE THIS COLUMN.
85fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * This column is kept for preventing demo apps.
86fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * TODO: Remove once nobody uses this column.
87fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * @hide
88fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * @removed
89b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri         */
90b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        public static final String STYLE = "font_style";
91bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        /**
92bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * Constant used to request data from a font provider. The cursor returned from the query
93fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * should have this column populated with the int weight for the resulting font. This value
94fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * should be between 100 and 900. The most common values are 400 for regular weight and 700
95fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * for bold weight.
96fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         */
97fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka        public static final String WEIGHT = "font_weight";
98fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka        /**
99fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * Constant used to request data from a font provider. The cursor returned from the query
100fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * should have this column populated with the int italic for the resulting font. This should
101fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * be 0 for regular style and 1 for italic.
102fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         */
103fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka        public static final String ITALIC = "font_italic";
104fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka        /**
105fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka         * Constant used to request data from a font provider. The cursor returned from the query
106bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * should have this column populated to indicate the result status of the
107bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * query. This will be checked before any other data in the cursor. Possible values are
108bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * {@link #RESULT_CODE_OK}, {@link #RESULT_CODE_FONT_NOT_FOUND},
109bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * {@link #RESULT_CODE_MALFORMED_QUERY} and {@link #RESULT_CODE_FONT_UNAVAILABLE}. If not
110bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * present, {@link #RESULT_CODE_OK} will be assumed.
111bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         */
112bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        public static final String RESULT_CODE = "result_code";
113bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri
114bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        /**
115bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * Constant used to represent a result was retrieved successfully. The given fonts will be
116bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * attempted to retrieve immediately via
117bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * {@link android.content.ContentProvider#openFile(Uri, String)}. See {@link #RESULT_CODE}.
118bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         */
119bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        public static final int RESULT_CODE_OK = 0;
120bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        /**
121bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * Constant used to represent a result was not found. See {@link #RESULT_CODE}.
122bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         */
123bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        public static final int RESULT_CODE_FONT_NOT_FOUND = 1;
124bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        /**
125bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * Constant used to represent a result was found, but cannot be provided at this moment. Use
126bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * this to indicate, for example, that a font needs to be fetched from the network. See
127bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * {@link #RESULT_CODE}.
128bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         */
129bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        public static final int RESULT_CODE_FONT_UNAVAILABLE = 2;
130bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        /**
131bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * Constant used to represent that the query was not in a supported format by the provider.
132bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         * See {@link #RESULT_CODE}.
133bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri         */
134bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        public static final int RESULT_CODE_MALFORMED_QUERY = 3;
135b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    }
136b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
137b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    /**
138b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     * Constant used to identify the List of {@link ParcelFileDescriptor} item in the Bundle
139b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     * returned to the ResultReceiver in getFont.
140b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     * @hide
141b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri     */
142b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    public static final String PARCEL_FONT_RESULTS = "font_results";
143b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
144bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri    // Error codes internal to the system, which can not come from a provider. To keep the number
145bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri    // space open for new provider codes, these should all be negative numbers.
146b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    /** @hide */
147bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri    public static final int RESULT_CODE_PROVIDER_NOT_FOUND = -1;
148b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    /** @hide */
149bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri    public static final int RESULT_CODE_WRONG_CERTIFICATES = -2;
150bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri    // Note -3 is used by Typeface to indicate the font failed to load.
151b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
152b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    private static final int THREAD_RENEWAL_THRESHOLD_MS = 10000;
153b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
154b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    private final Context mContext;
155b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    private final PackageManager mPackageManager;
156b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    private final Object mLock = new Object();
157b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    @GuardedBy("mLock")
158b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    private Handler mHandler;
159b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    @GuardedBy("mLock")
160b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    private HandlerThread mThread;
161b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
162b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    /** @hide */
163ff221613ec1c328489a303491e1aa88850e4a273Clara Bayarri    public FontsContract(Context context) {
164ff221613ec1c328489a303491e1aa88850e4a273Clara Bayarri        mContext = context.getApplicationContext();
165b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        mPackageManager = mContext.getPackageManager();
166b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    }
167b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
1683c4be77db95ea716889568bde853be082e764da9Clara Bayarri    /** @hide */
1693c4be77db95ea716889568bde853be082e764da9Clara Bayarri    @VisibleForTesting
1703c4be77db95ea716889568bde853be082e764da9Clara Bayarri    public FontsContract(Context context, PackageManager packageManager) {
1713c4be77db95ea716889568bde853be082e764da9Clara Bayarri        mContext = context;
1723c4be77db95ea716889568bde853be082e764da9Clara Bayarri        mPackageManager = packageManager;
1733c4be77db95ea716889568bde853be082e764da9Clara Bayarri    }
1743c4be77db95ea716889568bde853be082e764da9Clara Bayarri
175b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    // We use a background thread to post the content resolving work for all requests on. This
176b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    // thread should be quit/stopped after all requests are done.
177b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    private final Runnable mReplaceDispatcherThreadRunnable = new Runnable() {
178b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        @Override
179b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        public void run() {
180b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            synchronized (mLock) {
181b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                if (mThread != null) {
182b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                    mThread.quitSafely();
183b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                    mThread = null;
184b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                    mHandler = null;
185b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                }
186b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            }
187b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        }
188b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    };
189b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
190bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri    /** @hide */
191b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    public void getFont(FontRequest request, ResultReceiver receiver) {
192b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        synchronized (mLock) {
193b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            if (mHandler == null) {
194b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                mThread = new HandlerThread("fonts", Process.THREAD_PRIORITY_BACKGROUND);
195b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                mThread.start();
196b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                mHandler = new Handler(mThread.getLooper());
197b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            }
198b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            mHandler.post(() -> {
199bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                ProviderInfo providerInfo = getProvider(request, receiver);
200b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                if (providerInfo == null) {
201b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                    return;
202b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                }
2033c4be77db95ea716889568bde853be082e764da9Clara Bayarri                getFontFromProvider(request, receiver, providerInfo.authority);
204b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            });
205b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            mHandler.removeCallbacks(mReplaceDispatcherThreadRunnable);
206b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            mHandler.postDelayed(mReplaceDispatcherThreadRunnable, THREAD_RENEWAL_THRESHOLD_MS);
207b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        }
208b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    }
209b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri
2103c4be77db95ea716889568bde853be082e764da9Clara Bayarri    /** @hide */
2113c4be77db95ea716889568bde853be082e764da9Clara Bayarri    @VisibleForTesting
212bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri    public ProviderInfo getProvider(FontRequest request, ResultReceiver receiver) {
2133c4be77db95ea716889568bde853be082e764da9Clara Bayarri        String providerAuthority = request.getProviderAuthority();
2143c4be77db95ea716889568bde853be082e764da9Clara Bayarri        ProviderInfo info = mPackageManager.resolveContentProvider(providerAuthority, 0);
2153c4be77db95ea716889568bde853be082e764da9Clara Bayarri        if (info == null) {
2163c4be77db95ea716889568bde853be082e764da9Clara Bayarri            Log.e(TAG, "Can't find content provider " + providerAuthority);
217bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri            receiver.send(RESULT_CODE_PROVIDER_NOT_FOUND, null);
2183c4be77db95ea716889568bde853be082e764da9Clara Bayarri            return null;
2193c4be77db95ea716889568bde853be082e764da9Clara Bayarri        }
2203c4be77db95ea716889568bde853be082e764da9Clara Bayarri
2213c4be77db95ea716889568bde853be082e764da9Clara Bayarri        if (!info.packageName.equals(request.getProviderPackage())) {
2223c4be77db95ea716889568bde853be082e764da9Clara Bayarri            Log.e(TAG, "Found content provider " + providerAuthority + ", but package was not "
2233c4be77db95ea716889568bde853be082e764da9Clara Bayarri                    + request.getProviderPackage());
224bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri            receiver.send(RESULT_CODE_PROVIDER_NOT_FOUND, null);
2253c4be77db95ea716889568bde853be082e764da9Clara Bayarri            return null;
2263c4be77db95ea716889568bde853be082e764da9Clara Bayarri        }
2273c4be77db95ea716889568bde853be082e764da9Clara Bayarri        // Trust system apps without signature checks
2283c4be77db95ea716889568bde853be082e764da9Clara Bayarri        if (info.applicationInfo.isSystemApp()) {
2293c4be77db95ea716889568bde853be082e764da9Clara Bayarri            return info;
2303c4be77db95ea716889568bde853be082e764da9Clara Bayarri        }
2313c4be77db95ea716889568bde853be082e764da9Clara Bayarri
232fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        List<byte[]> signatures;
2333c4be77db95ea716889568bde853be082e764da9Clara Bayarri        try {
2343c4be77db95ea716889568bde853be082e764da9Clara Bayarri            PackageInfo packageInfo = mPackageManager.getPackageInfo(info.packageName,
2353c4be77db95ea716889568bde853be082e764da9Clara Bayarri                    PackageManager.GET_SIGNATURES);
236fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            signatures = convertToByteArrayList(packageInfo.signatures);
237fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            Collections.sort(signatures, sByteArrayComparator);
2383c4be77db95ea716889568bde853be082e764da9Clara Bayarri        } catch (PackageManager.NameNotFoundException e) {
2393c4be77db95ea716889568bde853be082e764da9Clara Bayarri            Log.e(TAG, "Can't find content provider " + providerAuthority, e);
240bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri            receiver.send(RESULT_CODE_PROVIDER_NOT_FOUND, null);
2413c4be77db95ea716889568bde853be082e764da9Clara Bayarri            return null;
2423c4be77db95ea716889568bde853be082e764da9Clara Bayarri        }
2433c4be77db95ea716889568bde853be082e764da9Clara Bayarri        List<List<byte[]>> requestCertificatesList = request.getCertificates();
2443c4be77db95ea716889568bde853be082e764da9Clara Bayarri        for (int i = 0; i < requestCertificatesList.size(); ++i) {
245fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            // Make a copy so we can sort it without modifying the incoming data.
246fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            List<byte[]> requestSignatures = new ArrayList<>(requestCertificatesList.get(i));
247fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            Collections.sort(requestSignatures, sByteArrayComparator);
248fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            if (equalsByteArrayList(signatures, requestSignatures)) {
2493c4be77db95ea716889568bde853be082e764da9Clara Bayarri                return info;
2503c4be77db95ea716889568bde853be082e764da9Clara Bayarri            }
2513c4be77db95ea716889568bde853be082e764da9Clara Bayarri        }
2523c4be77db95ea716889568bde853be082e764da9Clara Bayarri        Log.e(TAG, "Certificates don't match for given provider " + providerAuthority);
253bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        receiver.send(RESULT_CODE_WRONG_CERTIFICATES, null);
2543c4be77db95ea716889568bde853be082e764da9Clara Bayarri        return null;
2553c4be77db95ea716889568bde853be082e764da9Clara Bayarri    }
2563c4be77db95ea716889568bde853be082e764da9Clara Bayarri
257fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri    private static final Comparator<byte[]> sByteArrayComparator = (l, r) -> {
258fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        if (l.length != r.length) {
259fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            return l.length - r.length;
2603c4be77db95ea716889568bde853be082e764da9Clara Bayarri        }
261fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        for (int i = 0; i < l.length; ++i) {
262fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            if (l[i] != r[i]) {
263fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri                return l[i] - r[i];
264fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            }
265fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        }
266fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        return 0;
267fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri    };
268fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri
269fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri    private boolean equalsByteArrayList(List<byte[]> signatures, List<byte[]> requestSignatures) {
270fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        if (signatures.size() != requestSignatures.size()) {
271fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            return false;
272fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        }
273fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        for (int i = 0; i < signatures.size(); ++i) {
274fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            if (!Arrays.equals(signatures.get(i), requestSignatures.get(i))) {
275fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri                return false;
276fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            }
277fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        }
278fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        return true;
2793c4be77db95ea716889568bde853be082e764da9Clara Bayarri    }
2803c4be77db95ea716889568bde853be082e764da9Clara Bayarri
281fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri    private List<byte[]> convertToByteArrayList(Signature[] signatures) {
282fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        List<byte[]> shas = new ArrayList<>();
283fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        for (int i = 0; i < signatures.length; ++i) {
284fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri            shas.add(signatures[i].toByteArray());
285fb483cc90c27a9c0fcafa28343a8fd644f8384a4Clara Bayarri        }
2863c4be77db95ea716889568bde853be082e764da9Clara Bayarri        return shas;
2873c4be77db95ea716889568bde853be082e764da9Clara Bayarri    }
2883c4be77db95ea716889568bde853be082e764da9Clara Bayarri
2893c4be77db95ea716889568bde853be082e764da9Clara Bayarri    /** @hide */
2903c4be77db95ea716889568bde853be082e764da9Clara Bayarri    @VisibleForTesting
2913c4be77db95ea716889568bde853be082e764da9Clara Bayarri    public void getFontFromProvider(FontRequest request, ResultReceiver receiver,
2923c4be77db95ea716889568bde853be082e764da9Clara Bayarri            String authority) {
293b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        ArrayList<FontResult> result = null;
29443c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka        final Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
2953c4be77db95ea716889568bde853be082e764da9Clara Bayarri                .authority(authority)
296b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                .build();
29743c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka        final Uri fileBaseUri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
29843c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                .authority(authority)
29943c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                .appendPath("file")
30043c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                .build();
301b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        try (Cursor cursor = mContext.getContentResolver().query(uri, new String[] { Columns._ID,
30243c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                        Columns.FILE_ID, Columns.TTC_INDEX, Columns.VARIATION_SETTINGS,
30343c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                        Columns.STYLE, Columns.WEIGHT, Columns.ITALIC, Columns.RESULT_CODE },
304b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                "query = ?", new String[] { request.getQuery() }, null);) {
305b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            // TODO: Should we restrict the amount of fonts that can be returned?
306b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            // TODO: Write documentation explaining that all results should be from the same family.
307b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            if (cursor != null && cursor.getCount() > 0) {
308bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                final int resultCodeColumnIndex = cursor.getColumnIndex(Columns.RESULT_CODE);
309bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                int resultCode = -1;
310b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                result = new ArrayList<>();
311bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                final int idColumnIndex = cursor.getColumnIndexOrThrow(Columns._ID);
31243c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                final int fileIdColumnIndex = cursor.getColumnIndex(Columns.FILE_ID);
313b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                final int ttcIndexColumnIndex = cursor.getColumnIndex(Columns.TTC_INDEX);
314b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                final int vsColumnIndex = cursor.getColumnIndex(Columns.VARIATION_SETTINGS);
315fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka                final int weightColumnIndex = cursor.getColumnIndex(Columns.WEIGHT);
316fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka                final int italicColumnIndex = cursor.getColumnIndex(Columns.ITALIC);
317b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                final int styleColumnIndex = cursor.getColumnIndex(Columns.STYLE);
318b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                while (cursor.moveToNext()) {
319bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                    resultCode = resultCodeColumnIndex != -1
320bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                            ? cursor.getInt(resultCodeColumnIndex) : Columns.RESULT_CODE_OK;
321bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                    if (resultCode != Columns.RESULT_CODE_OK) {
322bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                        if (resultCode < 0) {
323bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                            // Negative values are reserved for the internal errors.
324bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                            resultCode = Columns.RESULT_CODE_FONT_NOT_FOUND;
325bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                        }
326bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                        for (int i = 0; i < result.size(); ++i) {
327bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                            try {
328bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                                result.get(i).getFileDescriptor().close();
329bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                            } catch (IOException e) {
330bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                                // Ignore, as we are closing fds for cleanup.
331bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                            }
332bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                        }
333bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                        receiver.send(resultCode, null);
334bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                        return;
335bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri                    }
33643c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                    Uri fileUri;
33743c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                    if (fileIdColumnIndex == -1) {
33843c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                        long id = cursor.getLong(idColumnIndex);
33943c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                        fileUri = ContentUris.withAppendedId(uri, id);
34043c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                    } else {
34143c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                        long id = cursor.getLong(fileIdColumnIndex);
34243c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                        fileUri = ContentUris.withAppendedId(fileBaseUri, id);
34343c20cf6d4bd661d85bed76c78953aa656dbcc62Seigo Nonaka                    }
344b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                    try {
345b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                        ParcelFileDescriptor pfd =
346b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                                mContext.getContentResolver().openFileDescriptor(fileUri, "r");
3473c4be77db95ea716889568bde853be082e764da9Clara Bayarri                        final int ttcIndex = ttcIndexColumnIndex != -1
3483c4be77db95ea716889568bde853be082e764da9Clara Bayarri                                ? cursor.getInt(ttcIndexColumnIndex) : 0;
3493c4be77db95ea716889568bde853be082e764da9Clara Bayarri                        final String variationSettings = vsColumnIndex != -1
3503c4be77db95ea716889568bde853be082e764da9Clara Bayarri                                ? cursor.getString(vsColumnIndex) : null;
351fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka                        // TODO: Stop using STYLE column and enforce WEIGHT/ITALIC column.
352fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka                        int weight;
353fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka                        boolean italic;
354fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka                        if (weightColumnIndex != -1 && italicColumnIndex != -1) {
355fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka                            weight = cursor.getInt(weightColumnIndex);
356fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka                            italic = cursor.getInt(italicColumnIndex) == 1;
357fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka                        } else if (styleColumnIndex != -1) {
358fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka                            final int style = cursor.getInt(styleColumnIndex);
359fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka                            weight = (style & Typeface.BOLD) != 0 ? 700 : 400;
360fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka                            italic = (style & Typeface.ITALIC) != 0;
361fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka                        } else {
362fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka                            weight = 400;
363fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka                            italic = false;
364fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka                        }
365fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka                        result.add(
366fe04aa840e0682e9813e1ac4958772f898eb02caSeigo Nonaka                                new FontResult(pfd, ttcIndex, variationSettings, weight, italic));
367b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                    } catch (FileNotFoundException e) {
368b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                        Log.e(TAG, "FileNotFoundException raised when interacting with content "
3693c4be77db95ea716889568bde853be082e764da9Clara Bayarri                                + "provider " + authority, e);
370b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                    }
371b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri                }
372b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            }
373b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        }
374b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        if (result != null && !result.isEmpty()) {
375b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            Bundle bundle = new Bundle();
376b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri            bundle.putParcelableArrayList(PARCEL_FONT_RESULTS, result);
377bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri            receiver.send(Columns.RESULT_CODE_OK, bundle);
3783c4be77db95ea716889568bde853be082e764da9Clara Bayarri            return;
379b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri        }
380bacf2352ab892724551431551ae973ae3b68db35Clara Bayarri        receiver.send(Columns.RESULT_CODE_FONT_NOT_FOUND, null);
381b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri    }
382b0812a30499376e09e2deb5995e998c629f24985Clara Bayarri}
383