public class

EmojiMetadata

extends java.lang.Object

 java.lang.Object

↳androidx.emoji2.text.EmojiMetadata

Overview

Information about a single emoji.

Summary

Fields
public static final intHAS_GLYPH_ABSENT

Device cannot render the emoji.

public static final intHAS_GLYPH_EXISTS

Device can render the emoji.

public static final intHAS_GLYPH_UNKNOWN

Not calculated on device yet.

Methods
public voiddraw(Canvas canvas, float x, float y, Paint paint)

Draws the emoji represented by this EmojiMetadata onto a canvas with origin at (x,y), using the specified paint.

public intgetCodepointAt(int index)

public intgetCodepointsLength()

public shortgetCompatAdded()

public intgetHasGlyph()

public shortgetHeight()

public intgetId()

public shortgetSdkAdded()

public TypefacegetTypeface()

public shortgetWidth()

public booleanisDefaultEmoji()

public voidresetHasGlyphCache()

Reset any cached values of hasGlyph on this metadata.

public voidsetHasGlyph(boolean hasGlyph)

Set whether the system can render the emoji.

public java.lang.StringtoString()

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

Fields

public static final int HAS_GLYPH_UNKNOWN

Not calculated on device yet.

public static final int HAS_GLYPH_ABSENT

Device cannot render the emoji.

public static final int HAS_GLYPH_EXISTS

Device can render the emoji.

Methods

public void draw(Canvas canvas, float x, float y, Paint paint)

Draws the emoji represented by this EmojiMetadata onto a canvas with origin at (x,y), using the specified paint.

Parameters:

canvas: Canvas to be drawn
x: x-coordinate of the origin of the emoji being drawn
y: y-coordinate of the baseline of the emoji being drawn
paint: Paint used for the text (e.g. color, size, style)

public Typeface getTypeface()

Returns:

return typeface to be used to render this metadata

public int getId()

Returns:

unique id for the emoji

public short getWidth()

Returns:

width of the emoji image

public short getHeight()

Returns:

height of the emoji image

public short getCompatAdded()

Returns:

in which metadata version the emoji was added to metadata

public short getSdkAdded()

Returns:

first SDK that the support for this emoji was added

public int getHasGlyph()

Returns:

whether the emoji is in Emoji Presentation by default (without emoji style selector 0xFE0F)

public void resetHasGlyphCache()

Reset any cached values of hasGlyph on this metadata. This is only useful for testing EmojiMetadata, and will make the next display of this emoji slower.

public void setHasGlyph(boolean hasGlyph)

Set whether the system can render the emoji.

Parameters:

hasGlyph: true if system can render the emoji

public boolean isDefaultEmoji()

Returns:

whether the emoji is in Emoji Presentation by default (without emoji style selector 0xFE0F)

public int getCodepointAt(int index)

Parameters:

index: index of the codepoint

Returns:

the codepoint at index

public int getCodepointsLength()

Returns:

the length of the codepoints for this emoji

public java.lang.String toString()

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 static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
import static androidx.annotation.RestrictTo.Scope.TESTS;

import android.annotation.SuppressLint;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Typeface;

import androidx.annotation.AnyThread;
import androidx.annotation.IntDef;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import androidx.emoji2.text.flatbuffer.MetadataItem;
import androidx.emoji2.text.flatbuffer.MetadataList;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * Information about a single emoji.
 *
 * @hide
 */
@RestrictTo(LIBRARY_GROUP)
@AnyThread
@RequiresApi(19)
public class EmojiMetadata {
    /**
     * Defines whether the system can render the emoji.
     */
    @IntDef({HAS_GLYPH_UNKNOWN, HAS_GLYPH_ABSENT, HAS_GLYPH_EXISTS})
    @Retention(RetentionPolicy.SOURCE)
    public @interface HasGlyph {
    }

    /**
     * Not calculated on device yet.
     */
    public static final int HAS_GLYPH_UNKNOWN = 0;

    /**
     * Device cannot render the emoji.
     */
    public static final int HAS_GLYPH_ABSENT = 1;

    /**
     * Device can render the emoji.
     */
    public static final int HAS_GLYPH_EXISTS = 2;

    /**
     * @see #getMetadataItem()
     */
    private static final ThreadLocal<MetadataItem> sMetadataItem = new ThreadLocal<>();

    /**
     * Index of the EmojiMetadata in {@link MetadataList}.
     */
    private final int mIndex;

    /**
     * MetadataRepo that holds this instance.
     */
    @NonNull
    private final MetadataRepo mMetadataRepo;

    /**
     * Whether the system can render the emoji. Calculated at runtime on the device.
     */
    @HasGlyph
    private volatile int mHasGlyph = HAS_GLYPH_UNKNOWN;

    EmojiMetadata(@NonNull final MetadataRepo metadataRepo, @IntRange(from = 0) final int index) {
        mMetadataRepo = metadataRepo;
        mIndex = index;
    }

    /**
     * Draws the emoji represented by this EmojiMetadata onto a canvas with origin at (x,y), using
     * the specified paint.
     *
     * @param canvas Canvas to be drawn
     * @param x x-coordinate of the origin of the emoji being drawn
     * @param y y-coordinate of the baseline of the emoji being drawn
     * @param paint Paint used for the text (e.g. color, size, style)
     */
    public void draw(@NonNull final Canvas canvas, final float x, final float y,
            @NonNull final Paint paint) {
        final Typeface typeface = mMetadataRepo.getTypeface();
        final Typeface oldTypeface = paint.getTypeface();
        paint.setTypeface(typeface);
        // MetadataRepo.getEmojiCharArray() is a continuous array of chars that is used to store the
        // chars for emojis. since all emojis are mapped to a single codepoint, and since it is 2
        // chars wide, we assume that the start index of the current emoji is mIndex * 2, and it is
        // 2 chars long.
        final int charArrayStartIndex = mIndex * 2;
        canvas.drawText(mMetadataRepo.getEmojiCharArray(), charArrayStartIndex, 2, x, y, paint);
        paint.setTypeface(oldTypeface);
    }

    /**
     * @return return typeface to be used to render this metadata
     */
    @NonNull
    public Typeface getTypeface() {
        return mMetadataRepo.getTypeface();
    }

    /**
     * @return a ThreadLocal instance of MetadataItem for this EmojiMetadata
     */
    private MetadataItem getMetadataItem() {
        MetadataItem result = sMetadataItem.get();
        if (result == null) {
            result = new MetadataItem();
            sMetadataItem.set(result);
        }
        // MetadataList is a wrapper around the metadata ByteBuffer. MetadataItem is a wrapper with
        // an index (pointer) on this ByteBuffer that represents a single emoji. Both are FlatBuffer
        // classes that wraps a ByteBuffer and gives access to the information in it. In order not
        // to create a wrapper class for each EmojiMetadata, we use mIndex as the index of the
        // MetadataItem in the ByteBuffer. We need to reiniitalize the current thread local instance
        // by executing the statement below. All the statement does is to set an int index in
        // MetadataItem. the same instance is used by all EmojiMetadata classes in the same thread.
        mMetadataRepo.getMetadataList().list(result, mIndex);
        return result;
    }

    /**
     * @return unique id for the emoji
     */
    public int getId() {
        return getMetadataItem().id();
    }

    /**
     * @return width of the emoji image
     */
    public short getWidth() {
        return getMetadataItem().width();
    }

    /**
     * @return height of the emoji image
     */
    public short getHeight() {
        return getMetadataItem().height();
    }

    /**
     * @return in which metadata version the emoji was added to metadata
     */
    public short getCompatAdded() {
        return getMetadataItem().compatAdded();
    }

    /**
     * @return first SDK that the support for this emoji was added
     */
    public short getSdkAdded() {
        return getMetadataItem().sdkAdded();
    }

    /**
     * @return whether the emoji is in Emoji Presentation by default (without emoji
     * style selector 0xFE0F)
     */
    @HasGlyph
    @SuppressLint("KotlinPropertyAccess")
    public int getHasGlyph() {
        return mHasGlyph;
    }

    /**
     * Reset any cached values of hasGlyph on this metadata.
     *
     * This is only useful for testing EmojiMetadata, and will make the next display of this
     * emoji slower.
     *
     * @hide
     */
    @RestrictTo(TESTS)
    public void resetHasGlyphCache() {
        mHasGlyph = HAS_GLYPH_UNKNOWN;
    }

    /**
     * Set whether the system can render the emoji.
     *
     * @param hasGlyph {@code true} if system can render the emoji
     */
    @SuppressLint("KotlinPropertyAccess")
    public void setHasGlyph(boolean hasGlyph) {
        mHasGlyph = hasGlyph ? HAS_GLYPH_EXISTS : HAS_GLYPH_ABSENT;
    }

    /**
     * @return whether the emoji is in Emoji Presentation by default (without emoji
     *         style selector 0xFE0F)
     */
    public boolean isDefaultEmoji() {
        return getMetadataItem().emojiStyle();
    }

    /**
     * @param index index of the codepoint
     *
     * @return the codepoint at index
     */
    public int getCodepointAt(int index) {
        return getMetadataItem().codepoints(index);
    }

    /**
     * @return the length of the codepoints for this emoji
     */
    public int getCodepointsLength() {
        return getMetadataItem().codepointsLength();
    }

    @Override
    public String toString() {
        final StringBuilder builder = new StringBuilder();
        builder.append(super.toString());
        builder.append(", id:");
        builder.append(Integer.toHexString(getId()));
        builder.append(", codepoints:");
        final int codepointsLength = getCodepointsLength();
        for (int i = 0; i < codepointsLength; i++) {
            builder.append(Integer.toHexString(getCodepointAt(i)));
            builder.append(" ");
        }
        return builder.toString();
    }
}