Merge "Remove Typeface.create" into oc-dev

This commit is contained in:
TreeHugger Robot
2017-04-25 17:26:58 +00:00
committed by Android (Google) Code Review
6 changed files with 40 additions and 427 deletions

View File

@@ -13777,7 +13777,6 @@ package android.graphics {
}
public class Typeface {
method public static deprecated void create(android.graphics.fonts.FontRequest, android.graphics.Typeface.FontRequestCallback);
method public static android.graphics.Typeface create(java.lang.String, int);
method public static android.graphics.Typeface create(android.graphics.Typeface, int);
method public static android.graphics.Typeface createFromAsset(android.content.res.AssetManager, java.lang.String);
@@ -13812,17 +13811,6 @@ package android.graphics {
method public android.graphics.Typeface.Builder setWeight(int);
}
public static abstract deprecated interface Typeface.FontRequestCallback {
method public abstract void onTypefaceRequestFailed(int);
method public abstract void onTypefaceRetrieved(android.graphics.Typeface);
field public static final int FAIL_REASON_FONT_LOAD_ERROR = -3; // 0xfffffffd
field public static final int FAIL_REASON_FONT_NOT_FOUND = 1; // 0x1
field public static final int FAIL_REASON_FONT_UNAVAILABLE = 2; // 0x2
field public static final int FAIL_REASON_MALFORMED_QUERY = 3; // 0x3
field public static final int FAIL_REASON_PROVIDER_NOT_FOUND = -1; // 0xffffffff
field public static final int FAIL_REASON_WRONG_CERTIFICATES = -2; // 0xfffffffe
}
public class Xfermode {
ctor public Xfermode();
}

View File

@@ -14552,7 +14552,6 @@ package android.graphics {
}
public class Typeface {
method public static deprecated void create(android.graphics.fonts.FontRequest, android.graphics.Typeface.FontRequestCallback);
method public static android.graphics.Typeface create(java.lang.String, int);
method public static android.graphics.Typeface create(android.graphics.Typeface, int);
method public static android.graphics.Typeface createFromAsset(android.content.res.AssetManager, java.lang.String);
@@ -14587,17 +14586,6 @@ package android.graphics {
method public android.graphics.Typeface.Builder setWeight(int);
}
public static abstract deprecated interface Typeface.FontRequestCallback {
method public abstract void onTypefaceRequestFailed(int);
method public abstract void onTypefaceRetrieved(android.graphics.Typeface);
field public static final int FAIL_REASON_FONT_LOAD_ERROR = -3; // 0xfffffffd
field public static final int FAIL_REASON_FONT_NOT_FOUND = 1; // 0x1
field public static final int FAIL_REASON_FONT_UNAVAILABLE = 2; // 0x2
field public static final int FAIL_REASON_MALFORMED_QUERY = 3; // 0x3
field public static final int FAIL_REASON_PROVIDER_NOT_FOUND = -1; // 0xffffffff
field public static final int FAIL_REASON_WRONG_CERTIFICATES = -2; // 0xfffffffe
}
public class Xfermode {
ctor public Xfermode();
}

View File

@@ -13819,7 +13819,6 @@ package android.graphics {
}
public class Typeface {
method public static deprecated void create(android.graphics.fonts.FontRequest, android.graphics.Typeface.FontRequestCallback);
method public static android.graphics.Typeface create(java.lang.String, int);
method public static android.graphics.Typeface create(android.graphics.Typeface, int);
method public static android.graphics.Typeface createFromAsset(android.content.res.AssetManager, java.lang.String);
@@ -13854,17 +13853,6 @@ package android.graphics {
method public android.graphics.Typeface.Builder setWeight(int);
}
public static abstract deprecated interface Typeface.FontRequestCallback {
method public abstract void onTypefaceRequestFailed(int);
method public abstract void onTypefaceRetrieved(android.graphics.Typeface);
field public static final int FAIL_REASON_FONT_LOAD_ERROR = -3; // 0xfffffffd
field public static final int FAIL_REASON_FONT_NOT_FOUND = 1; // 0x1
field public static final int FAIL_REASON_FONT_UNAVAILABLE = 2; // 0x2
field public static final int FAIL_REASON_MALFORMED_QUERY = 3; // 0x3
field public static final int FAIL_REASON_PROVIDER_NOT_FOUND = -1; // 0xffffffff
field public static final int FAIL_REASON_WRONG_CERTIFICATES = -2; // 0xfffffffe
}
public class Xfermode {
ctor public Xfermode();
}

View File

@@ -33,7 +33,6 @@ import android.content.pm.Signature;
import android.database.Cursor;
import android.graphics.Typeface;
import android.graphics.fonts.FontRequest;
import android.graphics.fonts.FontResult;
import android.graphics.fonts.FontVariationAxis;
import android.net.Uri;
import android.os.Bundle;
@@ -43,6 +42,7 @@ import android.os.HandlerThread;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.ResultReceiver;
import android.util.ArraySet;
import android.util.Log;
import android.util.LruCache;
@@ -64,6 +64,7 @@ import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Utility class to deal with Font ContentProviders.
@@ -181,6 +182,8 @@ public class FontsContract {
private Handler mHandler;
@GuardedBy("mLock")
private HandlerThread mThread;
@GuardedBy("mLock")
private Set<String> mInQueueSet;
private static final LruCache<String, Typeface> sTypefaceCache = new LruCache<>(16);
@@ -330,81 +333,54 @@ public class FontsContract {
mThread.quitSafely();
mThread = null;
mHandler = null;
mInQueueSet = null;
}
}
}
};
/** @hide */
public void getFont(FontRequest request, ResultReceiver receiver) {
public Typeface getFontOrWarmUpCache(FontRequest request) {
final String id = request.getIdentifier();
Typeface cachedTypeface = sTypefaceCache.get(id);
if (cachedTypeface != null) {
return cachedTypeface;
}
// Unfortunately the typeface is not available at this time, but requesting from the font
// provider takes too much time. For now, request the font data to ensure it is in the cache
// next time and return.
synchronized (mLock) {
if (mHandler == null) {
mThread = new HandlerThread("fonts", Process.THREAD_PRIORITY_BACKGROUND);
mThread.start();
mHandler = new Handler(mThread.getLooper());
mInQueueSet = new ArraySet<String>();
}
if (mInQueueSet.contains(id)) {
return null; // Already requested.
}
mInQueueSet.add(id);
mHandler.post(() -> {
ProviderInfo providerInfo;
try {
providerInfo = getProvider(mPackageManager, request);
if (providerInfo == null) {
receiver.send(RESULT_CODE_PROVIDER_NOT_FOUND, null);
return;
}
} catch (PackageManager.NameNotFoundException e) {
receiver.send(RESULT_CODE_PROVIDER_NOT_FOUND, null);
return;
synchronized (mLock) {
mInQueueSet.remove(id);
}
FontInfo[] fonts;
try {
fonts = getFontFromProvider(mContext, request, providerInfo.authority,
null /* cancellation signal */);
} catch (InvalidFormatException e) {
receiver.send(RESULT_CODE_PROVIDER_NOT_FOUND, null);
return;
}
ArrayList<FontResult> result = new ArrayList<>();
int resultCode = -1;
for (FontInfo font : fonts) {
try {
resultCode = font.getResultCode();
if (resultCode != Columns.RESULT_CODE_OK) {
if (resultCode < 0) {
// Negative values are reserved for the internal errors.
resultCode = Columns.RESULT_CODE_FONT_NOT_FOUND;
}
for (int i = 0; i < result.size(); ++i) {
try {
result.get(i).getFileDescriptor().close();
} catch (IOException e) {
// Ignore, as we are closing fds for cleanup.
}
}
receiver.send(resultCode, null);
return;
FontFamilyResult result = fetchFonts(mContext, null, request);
if (result.getStatusCode() == FontFamilyResult.STATUS_OK) {
Typeface typeface = buildTypeface(mContext, null, result.getFonts());
if (typeface != null) {
sTypefaceCache.put(id, typeface);
}
ParcelFileDescriptor pfd = mContext.getContentResolver().openFileDescriptor(
font.getUri(), "r");
result.add(new FontResult(pfd, font.getTtcIndex(),
FontVariationAxis.toFontVariationSettings(font.getAxes()),
font.getWeight(), font.isItalic()));
} catch (FileNotFoundException e) {
Log.e(TAG, "FileNotFoundException raised when interacting with content "
+ "provider " + providerInfo.authority, e);
}
} catch (NameNotFoundException e) {
// Ignore.
}
if (!result.isEmpty()) {
Bundle bundle = new Bundle();
bundle.putParcelableArrayList(PARCEL_FONT_RESULTS, result);
receiver.send(Columns.RESULT_CODE_OK, bundle);
return;
}
receiver.send(Columns.RESULT_CODE_FONT_NOT_FOUND, null);
});
mHandler.removeCallbacks(mReplaceDispatcherThreadRunnable);
mHandler.postDelayed(mReplaceDispatcherThreadRunnable, THREAD_RENEWAL_THRESHOLD_MS);
}
return null;
}
/**
@@ -452,16 +428,14 @@ public class FontsContract {
public FontRequestCallback() {}
/**
* Called then a Typeface request done via {@link Typeface#create(FontRequest,
* FontRequestCallback)} is complete. Note that this method will not be called if
* {@link #onTypefaceRequestFailed(int)} is called instead.
* Called then a Typeface request done via {@link #requestFont} is complete. Note that this
* method will not be called if {@link #onTypefaceRequestFailed(int)} is called instead.
* @param typeface The Typeface object retrieved.
*/
public void onTypefaceRetrieved(Typeface typeface) {}
/**
* Called when a Typeface request done via {@link Typeface#create(FontRequest,
* FontRequestCallback)} fails.
* Called when a Typeface request done via {@link #requestFont}} fails.
* @param reason One of {@link #FAIL_REASON_PROVIDER_NOT_FOUND},
* {@link #FAIL_REASON_FONT_NOT_FOUND},
* {@link #FAIL_REASON_FONT_LOAD_ERROR},

View File

@@ -31,7 +31,6 @@ import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.FontListParser;
import android.graphics.fonts.FontRequest;
import android.graphics.fonts.FontResult;
import android.graphics.fonts.FontVariationAxis;
import android.graphics.fonts.FontVariationAxis.InvalidFormatException;
import android.net.Uri;
@@ -102,8 +101,6 @@ public class Typeface {
new LongSparseArray<>(3);
@GuardedBy("sLock")
private static FontsContract sFontsContract;
@GuardedBy("sLock")
private static Handler sHandler;
/**
* Cache for Typeface objects dynamically loaded from assets. Currently max size is 16.
@@ -205,16 +202,9 @@ public class Typeface {
public static Typeface createFromResources(
FamilyResourceEntry entry, AssetManager mgr, String path) {
if (sFallbackFonts != null) {
Typeface typeface = findFromCache(mgr, path);
if (typeface != null) return typeface;
if (entry instanceof ProviderResourceEntry) {
final ProviderResourceEntry providerEntry = (ProviderResourceEntry) entry;
// Downloadable font
typeface = findFromCache(providerEntry.getAuthority(), providerEntry.getQuery());
if (typeface != null) {
return typeface;
}
List<List<String>> givenCerts = providerEntry.getCerts();
List<List<byte[]>> certs = new ArrayList<>();
if (givenCerts != null) {
@@ -229,11 +219,15 @@ public class Typeface {
}
// Downloaded font and it wasn't cached, request it again and return a
// default font instead (nothing we can do now).
create(new FontRequest(providerEntry.getAuthority(), providerEntry.getPackage(),
providerEntry.getQuery(), certs), NO_OP_REQUEST_CALLBACK);
return DEFAULT;
FontRequest request = new FontRequest(providerEntry.getAuthority(),
providerEntry.getPackage(), providerEntry.getQuery(), certs);
Typeface typeface = sFontsContract.getFontOrWarmUpCache(request);
return typeface == null ? DEFAULT : typeface;
}
Typeface typeface = findFromCache(mgr, path);
if (typeface != null) return typeface;
// family is FontFamilyFilesResourceEntry
final FontFamilyFilesResourceEntry filesEntry =
(FontFamilyFilesResourceEntry) entry;
@@ -291,214 +285,10 @@ public class Typeface {
synchronized (sLock) {
if (sFontsContract == null) {
sFontsContract = new FontsContract(context);
sHandler = new Handler();
}
}
}
/**
* Create a typeface object given a font request. The font will be asynchronously fetched,
* therefore the result is delivered to the given callback. See {@link FontRequest}.
* Only one of the methods in callback will be invoked, depending on whether the request
* succeeds or fails. These calls will happen on the main thread.
* @param request A {@link FontRequest} object that identifies the provider and query for the
* request. May not be null.
* @param callback A callback that will be triggered when results are obtained. May not be null.
*/
@Deprecated
public static void create(@NonNull FontRequest request, @NonNull FontRequestCallback callback) {
// Check the cache first
// TODO: would the developer want to avoid a cache hit and always ask for the freshest
// result?
Typeface cachedTypeface = findFromCache(
request.getProviderAuthority(), request.getQuery());
if (cachedTypeface != null) {
sHandler.post(() -> callback.onTypefaceRetrieved(cachedTypeface));
return;
}
synchronized (sLock) {
if (sFontsContract == null) {
throw new RuntimeException("Context not initialized, can't query provider");
}
final ResultReceiver receiver = new ResultReceiver(null) {
@Override
public void onReceiveResult(int resultCode, Bundle resultData) {
sHandler.post(() -> receiveResult(request, callback, resultCode, resultData));
}
};
sFontsContract.getFont(request, receiver);
}
}
private static Typeface findFromCache(String providerAuthority, String query) {
synchronized (sDynamicTypefaceCache) {
final String key = createProviderUid(providerAuthority, query);
Typeface typeface = sDynamicTypefaceCache.get(key);
if (typeface != null) {
return typeface;
}
}
return null;
}
private static void receiveResult(FontRequest request, FontRequestCallback callback,
int resultCode, Bundle resultData) {
Typeface cachedTypeface = findFromCache(
request.getProviderAuthority(), request.getQuery());
if (cachedTypeface != null) {
// We already know the result.
// Probably the requester requests the same font again in a short interval.
callback.onTypefaceRetrieved(cachedTypeface);
return;
}
if (resultCode != FontsContract.Columns.RESULT_CODE_OK) {
callback.onTypefaceRequestFailed(resultCode);
return;
}
if (resultData == null) {
callback.onTypefaceRequestFailed(
FontRequestCallback.FAIL_REASON_FONT_NOT_FOUND);
return;
}
List<FontResult> resultList =
resultData.getParcelableArrayList(FontsContract.PARCEL_FONT_RESULTS);
if (resultList == null || resultList.isEmpty()) {
callback.onTypefaceRequestFailed(
FontRequestCallback.FAIL_REASON_FONT_NOT_FOUND);
return;
}
FontFamily fontFamily = new FontFamily();
for (int i = 0; i < resultList.size(); ++i) {
FontResult result = resultList.get(i);
ParcelFileDescriptor fd = result.getFileDescriptor();
if (fd == null) {
callback.onTypefaceRequestFailed(
FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR);
return;
}
try (FileInputStream is = new FileInputStream(fd.getFileDescriptor())) {
FileChannel fileChannel = is.getChannel();
long fontSize = fileChannel.size();
ByteBuffer fontBuffer = fileChannel.map(
FileChannel.MapMode.READ_ONLY, 0, fontSize);
int weight = result.getWeight();
int italic = result.getItalic() ? STYLE_ITALIC : STYLE_NORMAL;
FontVariationAxis[] axes = null;
try {
axes = FontVariationAxis.fromFontVariationSettings(
result.getFontVariationSettings());
} catch (FontVariationAxis.InvalidFormatException e) {
// TODO: Nice to pass FontVariationAxis[] directly instead of string.
}
if (!fontFamily.addFontFromBuffer(fontBuffer, result.getTtcIndex(),
axes, weight, italic)) {
Log.e(TAG, "Error creating font " + request.getQuery());
callback.onTypefaceRequestFailed(
FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR);
return;
}
} catch (IOException e) {
Log.e(TAG, "Error reading font " + request.getQuery(), e);
callback.onTypefaceRequestFailed(
FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR);
return;
} finally {
IoUtils.closeQuietly(fd);
}
}
if (!fontFamily.freeze()) {
callback.onTypefaceRequestFailed(
FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR);
return;
}
Typeface typeface = Typeface.createFromFamiliesWithDefault(
new FontFamily[] { fontFamily },
RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE);
synchronized (sDynamicTypefaceCache) {
String key = createProviderUid(request.getProviderAuthority(), request.getQuery());
sDynamicTypefaceCache.put(key, typeface);
}
callback.onTypefaceRetrieved(typeface);
}
/**
* Interface used to receive asynchronously fetched typefaces.
*/
@Deprecated
public interface FontRequestCallback {
/**
* Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given
* provider was not found on the device.
*/
int FAIL_REASON_PROVIDER_NOT_FOUND = FontsContract.RESULT_CODE_PROVIDER_NOT_FOUND;
/**
* Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given
* provider must be authenticated and the given certificates do not match its signature.
*/
int FAIL_REASON_WRONG_CERTIFICATES = FontsContract.RESULT_CODE_WRONG_CERTIFICATES;
/**
* Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the font
* returned by the provider was not loaded properly.
*/
int FAIL_REASON_FONT_LOAD_ERROR = -3;
/**
* Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the font
* provider did not return any results for the given query.
*/
int FAIL_REASON_FONT_NOT_FOUND = FontsContract.Columns.RESULT_CODE_FONT_NOT_FOUND;
/**
* Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the font
* provider found the queried font, but it is currently unavailable.
*/
int FAIL_REASON_FONT_UNAVAILABLE = FontsContract.Columns.RESULT_CODE_FONT_UNAVAILABLE;
/**
* Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given
* query was not supported by the provider.
*/
int FAIL_REASON_MALFORMED_QUERY = FontsContract.Columns.RESULT_CODE_MALFORMED_QUERY;
/** @hide */
@IntDef({ FAIL_REASON_PROVIDER_NOT_FOUND, FAIL_REASON_FONT_LOAD_ERROR,
FAIL_REASON_FONT_NOT_FOUND, FAIL_REASON_FONT_UNAVAILABLE,
FAIL_REASON_MALFORMED_QUERY })
@Retention(RetentionPolicy.SOURCE)
@interface FontRequestFailReason {}
/**
* Called then a Typeface request done via {@link Typeface#create(FontRequest,
* FontRequestCallback)} is complete. Note that this method will not be called if
* {@link #onTypefaceRequestFailed(int)} is called instead.
* @param typeface The Typeface object retrieved.
*/
void onTypefaceRetrieved(Typeface typeface);
/**
* Called when a Typeface request done via {@link Typeface#create(FontRequest,
* FontRequestCallback)} fails.
* @param reason May be one of {@link #FAIL_REASON_PROVIDER_NOT_FOUND},
* {@link #FAIL_REASON_FONT_NOT_FOUND},
* {@link #FAIL_REASON_FONT_LOAD_ERROR},
* {@link #FAIL_REASON_FONT_UNAVAILABLE} or
* {@link #FAIL_REASON_MALFORMED_QUERY} if returned by the system. May also be
* a positive value greater than 0 defined by the font provider as an
* additional error code. Refer to the provider's documentation for more
* information on possible returned error codes.
*/
void onTypefaceRequestFailed(@FontRequestFailReason int reason);
}
private static final FontRequestCallback NO_OP_REQUEST_CALLBACK = new FontRequestCallback() {
@Override
public void onTypefaceRetrieved(Typeface typeface) {
// Do nothing.
}
@Override
public void onTypefaceRequestFailed(@FontRequestFailReason int reason) {
// Do nothing.
}
};
/**
* A builder class for creating new Typeface instance.
*

View File

@@ -1,115 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.graphics.fonts;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Paint;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import com.android.internal.util.Preconditions;
import java.io.FileDescriptor;
import java.io.IOException;
/**
* Results returned from a Font Provider to the system.
* @hide
*/
public final class FontResult implements Parcelable {
private final ParcelFileDescriptor mFileDescriptor;
private final int mTtcIndex;
private final String mFontVariationSettings;
private final int mWeight;
private final boolean mItalic;
/**
* Creates a FontResult with all the information needed about a provided font.
* @param fileDescriptor A ParcelFileDescriptor pointing to the font file. This shoult point to
* a real file or shared memory, as the client will mmap the given file
* descriptor. Pipes, sockets and other non-mmap-able file descriptors
* will fail to load in the client application.
* @param ttcIndex If providing a TTC_INDEX file, the index to point to. Otherwise, 0.
* @param fontVariationSettings If providing a variation font, the settings for it. May be null.
* @param weight An integer that indicates the font weight.
* @param italic A boolean that indicates the font is italic style or not.
*/
public FontResult(@NonNull ParcelFileDescriptor fileDescriptor, int ttcIndex,
@Nullable String fontVariationSettings, int weight, boolean italic) {
mFileDescriptor = Preconditions.checkNotNull(fileDescriptor);
mTtcIndex = ttcIndex;
mFontVariationSettings = fontVariationSettings;
mWeight = weight;
mItalic = italic;
}
public ParcelFileDescriptor getFileDescriptor() {
return mFileDescriptor;
}
public int getTtcIndex() {
return mTtcIndex;
}
public String getFontVariationSettings() {
return mFontVariationSettings;
}
public int getWeight() {
return mWeight;
}
public boolean getItalic() {
return mItalic;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(mFileDescriptor, flags);
dest.writeInt(mTtcIndex);
dest.writeString(mFontVariationSettings);
dest.writeInt(mWeight);
dest.writeBoolean(mItalic);
}
private FontResult(Parcel in) {
mFileDescriptor = in.readParcelable(null);
mTtcIndex = in.readInt();
mFontVariationSettings = in.readString();
mWeight = in.readInt();
mItalic = in.readBoolean();
}
public static final Parcelable.Creator<FontResult> CREATOR =
new Parcelable.Creator<FontResult>() {
@Override
public FontResult createFromParcel(Parcel in) {
return new FontResult(in);
}
@Override
public FontResult[] newArray(int size) {
return new FontResult[size];
}
};
}