public class

EmojiCompatInitializer

extends java.lang.Object

implements Initializer<java.lang.Boolean>

 java.lang.Object

↳androidx.emoji2.text.EmojiCompatInitializer

Gradle dependencies

compile group: 'androidx.emoji2', name: 'emoji2', version: '1.2.0-alpha04'

  • groupId: androidx.emoji2
  • artifactId: emoji2
  • version: 1.2.0-alpha04

Artifact androidx.emoji2:emoji2:1.2.0-alpha04 it located at Google repository (https://maven.google.com/)

Overview

Initializer for configuring EmojiCompat with the system installed downloadable font provider.

This initializer will initialize EmojiCompat immediately then defer loading the font for a short delay to avoid delaying application startup. Typically, the font will be loaded shortly after the first screen of your application loads, which means users may see system emoji briefly prior to the compat font loading.

This is the recommended configuration for all apps that don't need specialized configuration, and don't need to control the background thread that initialization runs on. For more information see DefaultEmojiCompatConfig.

In addition to the reasons listed in DefaultEmojiCompatConfig you may wish to disable this automatic configuration if you intend to call initialization from an existing background thread pool in your application.

This is enabled by default by including the :emoji2:emoji2 gradle artifact. To disable the default configuration (and allow manual configuration) add this to your manifest:

     <provider
         android:name="androidx.startup.InitializationProvider"
         android:authorities="${applicationId}.androidx-startup"
         android:exported="false"
         tools:node="merge">
         <meta-data android:name="androidx.emoji2.text.EmojiCompatInitializer"
                   tools:node="remove" />
     </provider>
 
This initializer depends on ProcessLifecycleInitializer.

Summary

Constructors
publicEmojiCompatInitializer()

Methods
public java.lang.Booleancreate(Context context)

Initialize EmojiCompat with the app's context.

public java.util.List<java.lang.Class>dependencies()

Dependes on ProcessLifecycleInitializer

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Constructors

public EmojiCompatInitializer()

Methods

public java.lang.Boolean create(Context context)

Initialize EmojiCompat with the app's context.

Parameters:

context: application context

Returns:

result of default init

public java.util.List<java.lang.Class> dependencies()

Dependes on ProcessLifecycleInitializer

Source

/*
 * Copyright 2021 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 androidx.emoji2.text;

import android.content.Context;
import android.os.Build;
import android.os.Handler;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.WorkerThread;
import androidx.core.os.TraceCompat;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.ProcessLifecycleInitializer;
import androidx.startup.AppInitializer;
import androidx.startup.Initializer;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * Initializer for configuring EmojiCompat with the system installed downloadable font provider.
 *
 * <p>This initializer will initialize EmojiCompat immediately then defer loading the font for a
 * short delay to avoid delaying application startup. Typically, the font will be loaded shortly
 * after the first screen of your application loads, which means users may see system emoji
 * briefly prior to the compat font loading.</p>
 *
 * <p>This is the recommended configuration for all apps that don't need specialized configuration,
 * and don't need to control the background thread that initialization runs on. For more information
 * see {@link androidx.emoji2.text.DefaultEmojiCompatConfig}.</p>
 *
 * <p>In addition to the reasons listed in {@code DefaultEmojiCompatConfig} you may wish to disable
 * this automatic configuration if you intend to call initialization from an existing background
 * thread pool in your application.</p>
 *
 * <p>This is enabled by default by including the {@code :emoji2:emoji2} gradle artifact. To
 * disable the default configuration (and allow manual configuration) add this to your manifest:</p>
 *
 * <pre>
 *     &lt;provider
 *         android:name="androidx.startup.InitializationProvider"
 *         android:authorities="${applicationId}.androidx-startup"
 *         android:exported="false"
 *         tools:node="merge"&gt;
 *         &lt;meta-data android:name="androidx.emoji2.text.EmojiCompatInitializer"
 *                   tools:node="remove" /&gt;
 *     &lt;/provider&gt;
 * </pre>
 *
 * This initializer depends on {@link ProcessLifecycleInitializer}.
 *
 * @see androidx.emoji2.text.DefaultEmojiCompatConfig
 */
public class EmojiCompatInitializer implements Initializer<Boolean> {
    private static final long STARTUP_THREAD_CREATION_DELAY_MS = 500L;
    private static final String S_INITIALIZER_THREAD_NAME = "EmojiCompatInitializer";

    /**
     * Initialize EmojiCompat with the app's context.
     *
     * @param context application context
     * @return result of default init
     */
    @SuppressWarnings("AutoBoxing")
    @NonNull
    @Override
    public Boolean create(@NonNull Context context) {
        if (Build.VERSION.SDK_INT >= 19) {
            EmojiCompat.init(new BackgroundDefaultConfig(context));
            delayUntilFirstResume(context);
            return true;
        }
        return false;
    }

    /**
     * Wait until the first frame of the application to do anything.
     *
     * This allows startup code to run before the delay is scheduled.
     */
    @RequiresApi(19)
    void delayUntilFirstResume(@NonNull Context context) {
        // schedule delay after first Activity resumes
        AppInitializer appInitializer = AppInitializer.getInstance(context);
        LifecycleOwner lifecycleOwner = appInitializer
                .initializeComponent(ProcessLifecycleInitializer.class);
        Lifecycle lifecycle = lifecycleOwner.getLifecycle();
        lifecycle.addObserver(new DefaultLifecycleObserver() {
            @Override
            public void onResume(@NonNull LifecycleOwner owner) {
                loadEmojiCompatAfterDelay();
                lifecycle.removeObserver(this);
            }
        });
    }

    @RequiresApi(19)
    void loadEmojiCompatAfterDelay() {
        final Handler mainHandler = ConcurrencyHelpers.mainHandlerAsync();
        mainHandler.postDelayed(new LoadEmojiCompatRunnable(), STARTUP_THREAD_CREATION_DELAY_MS);
    }

    /**
     * Dependes on ProcessLifecycleInitializer
     */
    @NonNull
    @Override
    public List<Class<? extends Initializer<?>>> dependencies() {
        return Collections.singletonList(ProcessLifecycleInitializer.class);
    }

    static class LoadEmojiCompatRunnable implements Runnable {
        @Override
        public void run() {
            try {
                // this is main thread, so mark what we're doing (this trace includes thread
                // start time in BackgroundLoadingLoader.load
                TraceCompat.beginSection("EmojiCompat.EmojiCompatInitializer.run");
                if (EmojiCompat.isConfigured()) {
                    EmojiCompat.get().load();
                }
            } finally {
                TraceCompat.endSection();
            }
        }
    }

    @RequiresApi(19)
    static class BackgroundDefaultConfig extends EmojiCompat.Config {
        protected BackgroundDefaultConfig(Context context) {
            super(new BackgroundDefaultLoader(context));
            setMetadataLoadStrategy(EmojiCompat.LOAD_STRATEGY_MANUAL);
        }
    }

    @RequiresApi(19)
    static class BackgroundDefaultLoader implements EmojiCompat.MetadataRepoLoader {
        private final Context mContext;

        BackgroundDefaultLoader(Context context) {
            mContext = context.getApplicationContext();
        }

        @Override
        public void load(@NonNull EmojiCompat.MetadataRepoLoaderCallback loaderCallback) {
            ThreadPoolExecutor executor = ConcurrencyHelpers.createBackgroundPriorityExecutor(
                            S_INITIALIZER_THREAD_NAME);
            executor.execute(() -> doLoad(loaderCallback, executor));
        }

        @WorkerThread
        void doLoad(@NonNull EmojiCompat.MetadataRepoLoaderCallback loaderCallback,
                @NonNull ThreadPoolExecutor executor) {
            try {
                FontRequestEmojiCompatConfig config = DefaultEmojiCompatConfig.create(mContext);
                if (config == null) {
                    throw new RuntimeException("EmojiCompat font provider not available on this "
                            + "device.");
                }
                config.setLoadingExecutor(executor);
                config.getMetadataRepoLoader().load(new EmojiCompat.MetadataRepoLoaderCallback() {
                    @Override
                    public void onLoaded(@NonNull MetadataRepo metadataRepo) {
                        try {
                            // main thread is notified before returning, so we can quit now
                            loaderCallback.onLoaded(metadataRepo);
                        } finally {
                            executor.shutdown();
                        }
                    }

                    @Override
                    public void onFailed(@Nullable Throwable throwable) {
                        try {
                            // main thread is notified before returning, so we can quit now
                            loaderCallback.onFailed(throwable);
                        } finally {
                            executor.shutdown();
                        }
                    }
                });
            } catch (Throwable t) {
                loaderCallback.onFailed(t);
                executor.shutdown();
            }
        }
    }

}