Using Downloadable Fonts from Google Fonts Provider

android downloadable fonts

Amongst all new Android O features, mentioned at Google I/O 2017, we were told about such thing as Downloadable Fonts. Now you don’t need to increase size of your apk because of custom fonts, if it’s already provided by Google Fonts Provider (https://fonts.google.com/). You just need to set the font in layout file via xml, or write a short code snippet manually, and mentioned font will be downloaded to the user’s device automatically. Of course, if the user has the latest Google Play Service version installed (11+), otherwise – here is the default system font)

Today we’ll make such kind of app, just to take a look at this new functionality:

android downloadable fonts

Now, you need to do some preparation before starting to code, actually. For the time this article was published, here they are:

1. Setup (or update to) Android Studio 3.0 – https://developer.android.com/studio/preview/index.html

2. Download virtual device image – we need Android O with Google Play (!) app installed. Here is the screenshot of selecting device model (Pixel, Nexus 4, Nexus 5, etc). We need one with Google Play icon near it:

android downloadable fonts

Then select OS version – we need Android O with Google Play:

android downloadable fonts

After that, finish the process and you should see the following in the AVD list:

android downloadable fonts

3. Update Google Play Services to version 11 or above:

– For the time this article was written, you could only get Play Service 11+ of you’re a beta tester of it. To become such, navigate this link https://developers.google.com/android/guides/beta-program and join the beta program.

– Next, you should link your beta-tester’s Google account to the newly created virtual device. Launch the emulator and sign in to your Google account.

– Now, update the Google Play Services app. Go to Settings – options menu in top right corner – Help and Feedback – options menu in top right corner – View in Google Play Store

 

After that it takes you to the Google Play app where you can make an update. Now we’re good to go.

Let’s create a new project with following settings:

In the project-level build.gradle add new google’s maven repository (now support library will be updated right from there):

allprojects {
    repositories {
        ...
        maven { url 'https://maven.google.com' }
    }
}

In the app-level build.gradle add following dependencies:

compile 'com.android.support:appcompat-v7:26.0.0-beta1'
compile 'com.android.support:support-v4:26.0.0-beta1'

We will need support-v4 library for backward compatibility. Please take note that new functionality we need here is only in 26.0.0-beta1 version and above.

Let’s also setup correct versions for build tools, compile sdk version, min sdk version and target sdk version:

android {
    compileSdkVersion 'android-O'
    buildToolsVersion '26.0.0 rc2'
    defaultConfig {
        ...
        minSdkVersion 14
        targetSdkVersion 26
        ...
    }
    ...
}

Sync your gradle files, and let’s move to our fonts!

First, create a simple layout file for our main Activity:


<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:text="Hello World!"
        android:textSize="42sp"
        android:layout_gravity="center"
        android:gravity="center"/>

    <EditText
        android:id="@+id/et_font_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:layout_marginBottom="8dp"
        android:hint="Enter font name"
        android:inputType="textCapWords"/>

    <Button
        android:id="@+id/btn_load"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Load font"
        android:layout_gravity="center"/>

</LinearLayout>

There are just TextView for our custom font, EditText to input font name and Button to send the request.

Now to the Activity. We will need loadFont() method which will be called after clicking on the button and will send the font request:

private void loadFont(String fontName) {
    
    if(!TextUtils.isEmpty(fontName)) {

        FontRequest request = new FontRequest(
                "com.google.android.gms.fonts",
                "com.google.android.gms",
                "name="+fontName,
                R.array.com_google_android_gms_fonts_certs);

        FontsContractCompat.FontRequestCallback callback = new FontsContractCompat.FontRequestCallback() {

            @Override
            public void onTypefaceRetrieved(Typeface typeface) {
                if(typeface != null) {
                    tvText.setTypeface(typeface);
                }
            }

            @Override
            public void onTypefaceRequestFailed(int reason) {
                Toast.makeText(
                        MainActivity.this,
                        getUserFriendlyFontError(reason),
                        Toast.LENGTH_LONG
                ).show();
            }
        };

        FontsContractCompat.requestFont(this, request, callback, mHandler);

    }
}

About this method in details:

fontName – a String with font name user input to the EditText

FontRequest – the main request to the fonts provider. We use Google Fonts Provider for now, and from I saw at Google I/O, it’s the only fonts provider supported right now. But they are ready to include other providers as well, so we’ll see)

To create a font request we need to set the following properties:

provider’s name – “com.google.android.gms”
what we need from it – “com.google.android.gms.fonts”
the query itself – “name=”+fontName
and provider’s certificates, stored in xml array – R.array.com_google_android_gms_fonts_certs

We can also add other properties to the query:

weight – int (0, 1000)

width – float, (0, +)

italic – float, [0, 1]

bestEffort – boolean

For example, it can look like this:

name=&weight=2&width=15.5&italic=0.5&bestEffort=true

Provider’s certificates have such values:

<array name="com_google_android_gms_fonts_certs">
        <item>@array/com_google_android_gms_fonts_certs_dev</item>
        <item>@array/com_google_android_gms_fonts_certs_prod</item>
    </array>
    <string-array name="com_google_android_gms_fonts_certs_dev">
        <item>
            MIIEqDCCA5CgAwIBAgIJANWFuGx90071MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAeFw0wODA0MTUyMzM2NTZaFw0zNTA5MDEyMzM2NTZaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBANbOLggKv+IxTdGNs8/TGFy0PTP6DHThvbbR24kT9ixcOd9W+EaBPWW+wPPKQmsHxajtWjmQwWfna8mZuSeJS48LIgAZlKkpFeVyxW0qMBujb8X8ETrWy550NaFtI6t9+u7hZeTfHwqNvacKhp1RbE6dBRGWynwMVX8XW8N1+UjFaq6GCJukT4qmpN2afb8sCjUigq0GuMwYXrFVee74bQgLHWGJwPmvmLHC69EH6kWr22ijx4OKXlSIx2xT1AsSHee70w5iDBiK4aph27yH3TxkXy9V89TDdexAcKk/cVHYNnDBapcavl7y0RiQ4biu8ymM8Ga/nmzhRKya6G0cGw8CAQOjgfwwgfkwHQYDVR0OBBYEFI0cxb6VTEM8YYY6FbBMvAPyT+CyMIHJBgNVHSMEgcEwgb6AFI0cxb6VTEM8YYY6FbBMvAPyT+CyoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJANWFuGx90071MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBABnTDPEF+3iSP0wNfdIjIz1AlnrPzgAIHVvXxunW7SBrDhEglQZBbKJEk5kT0mtKoOD1JMrSu1xuTKEBahWRbqHsXclaXjoBADb0kkjVEJu/Lh5hgYZnOjvlba8Ld7HCKePCVePoTJBdI4fvugnL8TsgK05aIskyY0hKI9L8KfqfGTl1lzOv2KoWD0KWwtAWPoGChZxmQ+nBli+gwYMzM1vAkP+aayLe0a1EQimlOalO762r0GXO0ks+UeXde2Z4e+8S/pf7pITEI/tP+MxJTALw9QUWEv9lKTk+jkbqxbsh8nfBUapfKqYn0eidpwq2AzVp3juYl7//fKnaPhJD9gs=
        </item>
    </string-array>
    <string-array name="com_google_android_gms_fonts_certs_prod">
        <item>
            MIIEQzCCAyugAwIBAgIJAMLgh0ZkSjCNMA0GCSqGSIb3DQEBBAUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAeFw0wODA4MjEyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAKtWLgDYO6IIrgqWbxJOKdoR8qtW0I9Y4sypEwPpt1TTcvZApxsdyxMJZ2JORland2qSGT2y5b+3JKkedxiLDmpHpDsz2WCbdxgxRczfey5YZnTJ4VZbH0xqWVW/8lGmPav5xVwnIiJS6HXk+BVKZF+JcWjAsb/GEuq/eFdpuzSqeYTcfi6idkyugwfYwXFU1+5fZKUaRKYCwkkFQVfcAs1fXA5V+++FGfvjJ/CxURaSxaBvGdGDhfXE28LWuT9ozCl5xw4Yq5OGazvV24mZVSoOO0yZ31j7kYvtwYK6NeADwbSxDdJEqO4k//0zOHKrUiGYXtqw/A0LFFtqoZKFjnkCAQOjgdkwgdYwHQYDVR0OBBYEFMd9jMIhF1Ylmn/Tgt9r45jk14alMIGmBgNVHSMEgZ4wgZuAFMd9jMIhF1Ylmn/Tgt9r45jk14aloXikdjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29vZ2xlIEluYy4xEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMTB0FuZHJvaWSCCQDC4IdGZEowjTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBt0lLO74UwLDYKqs6Tm8/yzKkEu116FmH4rkaymUIE0P9KaMftGlMexFlaYjzmB2OxZyl6euNXEsQH8gjwyxCUKRJNexBiGcCEyj6z+a1fuHHvkiaai+KL8W1EyNmgjmyy8AW7P+LLlkR+ho5zEHatRbM/YAnqGcFh5iZBqpknHf1SKMXFh4dd239FJ1jWYfbMDMy3NS5CTMQ2XFI1MvcyUTdZPErjQfTbQe3aDQsQcafEQPD+nqActifKZ0Np0IS9L9kR/wbNvyz6ENwPiTrjV2KRkEjH78ZMcUQXg0L3BYHJ3lc69Vs5Ddf9uUGGMYldX3WfMBEmh/9iFBDAaTCK
        </item>
    </string-array>

I’ve found this info on Google’s example project for Downloadable Fonts on Github, it was in res folder. If you’ve found this somewhere on ‘official’ Google Fonts Provider page, please share in comments.

Next, we create a callback function that will be called after the font request gets the response. If it was finished successfully, we apply the font to our TextView:

@Override
public void onTypefaceRetrieved(Typeface typeface) {
    if(typeface != null) {
        tvText.setTypeface(typeface);
     }
}

Otherwise, we show an error message to the user:

@Override
public void onTypefaceRequestFailed(int reason) {
    Toast.makeText(
        MainActivity.this,
        getUserFriendlyFontError(reason),
        Toast.LENGTH_LONG
        ).show();
}

Now we launch the request and all is done. Here we pass the Context, the font request itself, our mentioned callback function and a Handler which tells the system what thread should we use to download a font.

FontsContractCompat.requestFont(this, request, callback, mHandler);

About Handler in more details:

Handler mHandler;
HandlerThread mHandlerThread;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ...

    //here we create a new thread with message queue and start it
    mHandlerThread = new HandlerThread("fonts");
    mHandlerThread.start();

    //then we get a Handler linked to that thread, where we will send our messages - 
    //request to process
    mHandler = new Handler(mHandlerThread.getLooper());

    ...
}

Don’t forget to quit the thread after finishing the activity:

@Override
protected void onDestroy() {
    if(mHandlerThread != null) {
        mHandlerThread.quit();
    }
    super.onDestroy();
}

Full source code you can find here – https://github.com/nerdgrlapps/android-downloadable-fonts-example

4 Responses to “Using Downloadable Fonts from Google Fonts Provider”

  1. how can we create the certificate?

    • NerdGrl says:

      We don’t need to create anything, just copy and paste strings array to your string.xml file. These long sets of symbols named ‘com_google_android_gms_fonts_certs_dev’ and ‘com_google_android_gms_fonts_certs_prod’ are the certificates.

  2. Mbel says:

    you forget somthing in the manifest file (add meta-data)

Leave a Reply

Your email address will not be published. Required fields are marked *