Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0b73a428 authored by Seigo Nonaka's avatar Seigo Nonaka
Browse files

Introduce FontsContract.requestFont and deprecate Typeface.create

Since background fetch should be synchronized with life cycle of
Activities, so should not create new background thread inside this
method. Not to break existing apps, mark as deprecated and will be
removed from public API untile next release.

New API accepts Handler so that the developer can pass their own thread
.

Test: TBD
Bug: 37253785
Change-Id: I87fdc6a354a829db679253824f42489f25698fa0
parent 061db23b
Loading
Loading
Loading
Loading
+15 −2
Original line number Diff line number Diff line
@@ -13761,7 +13761,7 @@ package android.graphics {
  }
  public class Typeface {
    method public static void create(android.graphics.fonts.FontRequest, android.graphics.Typeface.FontRequestCallback);
    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);
@@ -13795,7 +13795,7 @@ package android.graphics {
    method public android.graphics.Typeface.Builder setWeight(int);
  }
  public static abstract interface Typeface.FontRequestCallback {
  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
@@ -34504,6 +34504,7 @@ package android.provider {
    method public static android.graphics.Typeface buildTypeface(android.content.Context, android.os.CancellationSignal, android.provider.FontsContract.FontInfo[], int, boolean, java.lang.String);
    method public static android.graphics.Typeface buildTypeface(android.content.Context, android.os.CancellationSignal, android.provider.FontsContract.FontInfo[]);
    method public static android.provider.FontsContract.FontFamilyResult fetchFonts(android.content.Context, android.os.CancellationSignal, android.graphics.fonts.FontRequest) throws android.content.pm.PackageManager.NameNotFoundException;
    method public static void requestFont(android.content.Context, android.graphics.fonts.FontRequest, android.provider.FontsContract.FontRequestCallback, android.os.Handler);
  }
  public static final class FontsContract.Columns implements android.provider.BaseColumns {
@@ -34537,6 +34538,18 @@ package android.provider {
    method public boolean isItalic();
  }
  public static class FontsContract.FontRequestCallback {
    ctor public FontsContract.FontRequestCallback();
    method public void onTypefaceRequestFailed(int);
    method public 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 final deprecated class LiveFolders implements android.provider.BaseColumns {
    field public static final java.lang.String ACTION_CREATE_LIVE_FOLDER = "android.intent.action.CREATE_LIVE_FOLDER";
    field public static final java.lang.String DESCRIPTION = "description";
+15 −2
Original line number Diff line number Diff line
@@ -14528,7 +14528,7 @@ package android.graphics {
  }
  public class Typeface {
    method public static void create(android.graphics.fonts.FontRequest, android.graphics.Typeface.FontRequestCallback);
    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);
@@ -14562,7 +14562,7 @@ package android.graphics {
    method public android.graphics.Typeface.Builder setWeight(int);
  }
  public static abstract interface Typeface.FontRequestCallback {
  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
@@ -37481,6 +37481,7 @@ package android.provider {
    method public static android.graphics.Typeface buildTypeface(android.content.Context, android.os.CancellationSignal, android.provider.FontsContract.FontInfo[], int, boolean, java.lang.String);
    method public static android.graphics.Typeface buildTypeface(android.content.Context, android.os.CancellationSignal, android.provider.FontsContract.FontInfo[]);
    method public static android.provider.FontsContract.FontFamilyResult fetchFonts(android.content.Context, android.os.CancellationSignal, android.graphics.fonts.FontRequest) throws android.content.pm.PackageManager.NameNotFoundException;
    method public static void requestFont(android.content.Context, android.graphics.fonts.FontRequest, android.provider.FontsContract.FontRequestCallback, android.os.Handler);
  }
  public static final class FontsContract.Columns implements android.provider.BaseColumns {
@@ -37514,6 +37515,18 @@ package android.provider {
    method public boolean isItalic();
  }
  public static class FontsContract.FontRequestCallback {
    ctor public FontsContract.FontRequestCallback();
    method public void onTypefaceRequestFailed(int);
    method public 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 final deprecated class LiveFolders implements android.provider.BaseColumns {
    field public static final java.lang.String ACTION_CREATE_LIVE_FOLDER = "android.intent.action.CREATE_LIVE_FOLDER";
    field public static final java.lang.String DESCRIPTION = "description";
+15 −2
Original line number Diff line number Diff line
@@ -13812,7 +13812,7 @@ package android.graphics {
  }
  public class Typeface {
    method public static void create(android.graphics.fonts.FontRequest, android.graphics.Typeface.FontRequestCallback);
    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);
@@ -13846,7 +13846,7 @@ package android.graphics {
    method public android.graphics.Typeface.Builder setWeight(int);
  }
  public static abstract interface Typeface.FontRequestCallback {
  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
@@ -34647,6 +34647,7 @@ package android.provider {
    method public static android.graphics.Typeface buildTypeface(android.content.Context, android.os.CancellationSignal, android.provider.FontsContract.FontInfo[], int, boolean, java.lang.String);
    method public static android.graphics.Typeface buildTypeface(android.content.Context, android.os.CancellationSignal, android.provider.FontsContract.FontInfo[]);
    method public static android.provider.FontsContract.FontFamilyResult fetchFonts(android.content.Context, android.os.CancellationSignal, android.graphics.fonts.FontRequest) throws android.content.pm.PackageManager.NameNotFoundException;
    method public static void requestFont(android.content.Context, android.graphics.fonts.FontRequest, android.provider.FontsContract.FontRequestCallback, android.os.Handler);
  }
  public static final class FontsContract.Columns implements android.provider.BaseColumns {
@@ -34680,6 +34681,18 @@ package android.provider {
    method public boolean isItalic();
  }
  public static class FontsContract.FontRequestCallback {
    ctor public FontsContract.FontRequestCallback();
    method public void onTypefaceRequestFailed(int);
    method public 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 final deprecated class LiveFolders implements android.provider.BaseColumns {
    field public static final java.lang.String ACTION_CREATE_LIVE_FOLDER = "android.intent.action.CREATE_LIVE_FOLDER";
    field public static final java.lang.String DESCRIPTION = "description";
+144 −0
Original line number Diff line number Diff line
@@ -393,6 +393,150 @@ public class FontsContract {
        }
    }

    /**
     * Interface used to receive asynchronously fetched typefaces.
     */
    public static class FontRequestCallback {
        /**
         * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given
         * provider was not found on the device.
         */
        public static final int FAIL_REASON_PROVIDER_NOT_FOUND = 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.
         */
        public static final int FAIL_REASON_WRONG_CERTIFICATES = RESULT_CODE_WRONG_CERTIFICATES;
        /**
         * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the font
         * returned by the provider was not loaded properly.
         */
        public static final 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.
         */
        public static final int FAIL_REASON_FONT_NOT_FOUND = 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.
         */
        public static final int FAIL_REASON_FONT_UNAVAILABLE = Columns.RESULT_CODE_FONT_UNAVAILABLE;
        /**
         * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given
         * query was not supported by the provider.
         */
        public static final int FAIL_REASON_MALFORMED_QUERY = 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 {}

        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.
         * @param typeface  The Typeface object retrieved.
         */
        public void onTypefaceRetrieved(Typeface typeface) {}

        /**
         * Called when a Typeface request done via {@link Typeface#create(FontRequest,
         * FontRequestCallback)} fails.
         * @param reason 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}.
         */
        public void onTypefaceRequestFailed(@FontRequestFailReason int reason) {}
    }

    /**
     * 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 caller thread.
     * @param context A context to be used for fetching from font provider.
     * @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.
     * @param handler A handler to be processed the font fetching.
     */
    public static void requestFont(@NonNull Context context, @NonNull FontRequest request,
            @NonNull FontRequestCallback callback, @NonNull Handler handler) {

        final Handler callerThreadHandler = new Handler();
        handler.post(() -> {
            // TODO: Cache the result.
            FontFamilyResult result;
            try {
                result = fetchFonts(context, null /* cancellation signal */, request);
            } catch (NameNotFoundException e) {
                callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
                        FontRequestCallback.FAIL_REASON_PROVIDER_NOT_FOUND));
                return;
            }

            if (result.getStatusCode() != FontFamilyResult.STATUS_OK) {
                switch (result.getStatusCode()) {
                    case FontFamilyResult.STATUS_WRONG_CERTIFICATES:
                        callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
                                FontRequestCallback.FAIL_REASON_WRONG_CERTIFICATES));
                        return;
                    case FontFamilyResult.STATUS_UNEXPECTED_DATA_PROVIDED:
                        callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
                                FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR));
                        return;
                    default:
                        // fetchFont returns unexpected status type. Fallback to load error.
                        callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
                                FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR));
                        return;
                }
            }

            final FontInfo[] fonts = result.getFonts();
            if (fonts == null || fonts.length == 0) {
                callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
                        FontRequestCallback.FAIL_REASON_FONT_NOT_FOUND));
                return;
            }
            for (final FontInfo font : fonts) {
                if (font.getResultCode() != Columns.RESULT_CODE_OK) {
                    // We proceed if all font entry is ready to use. Otherwise report the first
                    // error.
                    final int resultCode = font.getResultCode();
                    if (resultCode < 0) {
                        // Negative values are reserved for internal errors. Fallback to load error.
                        callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
                                FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR));
                    } else {
                        callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
                                resultCode));
                    }
                    return;
                }
            }

            final Typeface typeface = buildTypeface(context, null /* cancellation signal */, fonts);
            if (typeface == null) {
                // Something went wrong during reading font files. This happens if the given font
                // file is an unsupported font type.
                callerThreadHandler.post(() -> callback.onTypefaceRequestFailed(
                        FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR));
                return;
            }

            callerThreadHandler.post(() -> callback.onTypefaceRetrieved(typeface));
        });
    }

    /**
     * Fetch fonts given a font request.
     *
+2 −0
Original line number Diff line number Diff line
@@ -292,6 +292,7 @@ public class Typeface {
     *                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
@@ -404,6 +405,7 @@ public class Typeface {
    /**
     * Interface used to receive asynchronously fetched typefaces.
     */
    @Deprecated
    public interface FontRequestCallback {
        /**
         * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given