| // Copyright 2013 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| package io.flutter.embedding.android; |
| |
| import androidx.annotation.NonNull; |
| import androidx.annotation.Nullable; |
| import java.io.UnsupportedEncodingException; |
| import java.nio.ByteBuffer; |
| import java.nio.ByteOrder; |
| |
| /** |
| * The resulting Flutter key events generated by {@link KeyEmbedderResponder}, and are sent through |
| * the messenger after being marshalled with {@link #toBytes()}. |
| * |
| * <p>This class is the Java adaption of {@code KeyData} and {@code KeyDataPacket} in the C engine. |
| * Changes made to either side must also be made to the other. |
| * |
| * <p>Each {@link KeyData} corresponds to a {@code ui.KeyData} in the framework. |
| */ |
| public class KeyData { |
| private static final String TAG = "KeyData"; |
| |
| /** |
| * The channel that key data should be sent through. |
| * |
| * <p>Must be kept in sync with kFlutterKeyDataChannel in embedder.cc |
| */ |
| public static final String CHANNEL = "flutter/keydata"; |
| |
| // The number of fields except for `character`. |
| private static final int FIELD_COUNT = 5; |
| private static final int BYTES_PER_FIELD = 8; |
| |
| /** The action type of the key data. */ |
| public enum Type { |
| kDown(0), |
| kUp(1), |
| kRepeat(2); |
| |
| private long value; |
| |
| private Type(long value) { |
| this.value = value; |
| } |
| |
| public long getValue() { |
| return value; |
| } |
| |
| static Type fromLong(long value) { |
| switch ((int) value) { |
| case 0: |
| return kDown; |
| case 1: |
| return kUp; |
| case 2: |
| return kRepeat; |
| default: |
| throw new AssertionError("Unexpected Type value"); |
| } |
| } |
| } |
| |
| /** Creates an empty {@link KeyData}. */ |
| public KeyData() {} |
| |
| /** |
| * Unmarshal fields from a buffer. |
| * |
| * <p>For the binary format, see {@code lib/ui/window/key_data_packet.h}. |
| */ |
| public KeyData(@NonNull ByteBuffer buffer) { |
| final long charSize = buffer.getLong(); |
| this.timestamp = buffer.getLong(); |
| this.type = Type.fromLong(buffer.getLong()); |
| this.physicalKey = buffer.getLong(); |
| this.logicalKey = buffer.getLong(); |
| this.synthesized = buffer.getLong() != 0; |
| |
| if (buffer.remaining() != charSize) { |
| throw new AssertionError( |
| String.format( |
| "Unexpected char length: charSize is %d while buffer has position %d, capacity %d, limit %d", |
| charSize, buffer.position(), buffer.capacity(), buffer.limit())); |
| } |
| this.character = null; |
| if (charSize != 0) { |
| final byte[] strBytes = new byte[(int) charSize]; |
| buffer.get(strBytes, 0, (int) charSize); |
| try { |
| this.character = new String(strBytes, "UTF-8"); |
| } catch (UnsupportedEncodingException e) { |
| throw new AssertionError("UTF-8 unsupported"); |
| } |
| } |
| } |
| |
| long timestamp; |
| Type type; |
| long physicalKey; |
| long logicalKey; |
| boolean synthesized; |
| |
| /** The character of this key data encoded in UTF-8. */ |
| @Nullable String character; |
| |
| /** |
| * Marshal the key data to a new byte buffer. |
| * |
| * <p>For the binary format, see {@code lib/ui/window/key_data_packet.h}. |
| * |
| * @return the marshalled bytes. |
| */ |
| ByteBuffer toBytes() { |
| byte[] charBytes; |
| try { |
| charBytes = character == null ? null : character.getBytes("UTF-8"); |
| } catch (UnsupportedEncodingException e) { |
| throw new AssertionError("UTF-8 not supported"); |
| } |
| final int charSize = charBytes == null ? 0 : charBytes.length; |
| final ByteBuffer packet = |
| ByteBuffer.allocateDirect((1 + FIELD_COUNT) * BYTES_PER_FIELD + charSize); |
| packet.order(ByteOrder.LITTLE_ENDIAN); |
| |
| packet.putLong(charSize); |
| packet.putLong(timestamp); |
| packet.putLong(type.getValue()); |
| packet.putLong(physicalKey); |
| packet.putLong(logicalKey); |
| packet.putLong(synthesized ? 1L : 0L); |
| if (charBytes != null) { |
| packet.put(charBytes); |
| } |
| |
| return packet; |
| } |
| } |