• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package io.flutter.plugin.common;
6 
7 import io.flutter.plugin.common.StandardMessageCodec.ExposedByteArrayOutputStream;
8 import java.nio.ByteBuffer;
9 import java.nio.ByteOrder;
10 
11 /**
12  * A {@link MethodCodec} using the Flutter standard binary encoding.
13  *
14  * <p>This codec is guaranteed to be compatible with the corresponding
15  * <a href="https://docs.flutter.io/flutter/services/StandardMethodCodec-class.html">StandardMethodCodec</a>
16  * on the Dart side. These parts of the Flutter SDK are evolved synchronously.</p>
17  *
18  * <p>Values supported as method arguments and result payloads are those supported by
19  * {@link StandardMessageCodec}.</p>
20  */
21 public final class StandardMethodCodec implements MethodCodec {
22     public static final StandardMethodCodec INSTANCE = new StandardMethodCodec(StandardMessageCodec.INSTANCE);
23     private final StandardMessageCodec messageCodec;
24 
25     /**
26      * Creates a new method codec based on the specified message codec.
27      */
StandardMethodCodec(StandardMessageCodec messageCodec)28     public StandardMethodCodec(StandardMessageCodec messageCodec) {
29       this.messageCodec = messageCodec;
30     }
31 
32     @Override
encodeMethodCall(MethodCall methodCall)33     public ByteBuffer encodeMethodCall(MethodCall methodCall) {
34         final ExposedByteArrayOutputStream stream = new ExposedByteArrayOutputStream();
35         messageCodec.writeValue(stream, methodCall.method);
36         messageCodec.writeValue(stream, methodCall.arguments);
37         final ByteBuffer buffer = ByteBuffer.allocateDirect(stream.size());
38         buffer.put(stream.buffer(), 0, stream.size());
39         return buffer;
40     }
41 
42     @Override
decodeMethodCall(ByteBuffer methodCall)43     public MethodCall decodeMethodCall(ByteBuffer methodCall) {
44         methodCall.order(ByteOrder.nativeOrder());
45         final Object method = messageCodec.readValue(methodCall);
46         final Object arguments = messageCodec.readValue(methodCall);
47         if (method instanceof String && !methodCall.hasRemaining()) {
48             return new MethodCall((String) method, arguments);
49         }
50         throw new IllegalArgumentException("Method call corrupted");
51     }
52 
53     @Override
encodeSuccessEnvelope(Object result)54     public ByteBuffer encodeSuccessEnvelope(Object result) {
55         final ExposedByteArrayOutputStream stream = new ExposedByteArrayOutputStream();
56         stream.write(0);
57         messageCodec.writeValue(stream, result);
58         final ByteBuffer buffer = ByteBuffer.allocateDirect(stream.size());
59         buffer.put(stream.buffer(), 0, stream.size());
60         return buffer;
61     }
62 
63     @Override
encodeErrorEnvelope(String errorCode, String errorMessage, Object errorDetails)64     public ByteBuffer encodeErrorEnvelope(String errorCode, String errorMessage,
65         Object errorDetails) {
66         final ExposedByteArrayOutputStream stream = new ExposedByteArrayOutputStream();
67         stream.write(1);
68         messageCodec.writeValue(stream, errorCode);
69         messageCodec.writeValue(stream, errorMessage);
70         messageCodec.writeValue(stream, errorDetails);
71         final ByteBuffer buffer = ByteBuffer.allocateDirect(stream.size());
72         buffer.put(stream.buffer(), 0, stream.size());
73         return buffer;
74     }
75 
76     @Override
decodeEnvelope(ByteBuffer envelope)77     public Object decodeEnvelope(ByteBuffer envelope) {
78         envelope.order(ByteOrder.nativeOrder());
79         final byte flag = envelope.get();
80         switch (flag) {
81             case 0: {
82                 final Object result = messageCodec.readValue(envelope);
83                 if (!envelope.hasRemaining()) {
84                     return result;
85                 }
86             }
87             // Falls through intentionally.
88             case 1: {
89                 final Object code = messageCodec.readValue(envelope);
90                 final Object message = messageCodec.readValue(envelope);
91                 final Object details = messageCodec.readValue(envelope);
92                 if (code instanceof String
93                     && (message == null || message instanceof String)
94                     && !envelope.hasRemaining()) {
95                     throw new FlutterException((String) code, (String) message, details);
96                 }
97             }
98         }
99         throw new IllegalArgumentException("Envelope corrupted");
100     }
101 }
102