1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.inputmethod; 18 19 import static android.view.inputmethod.InputConnectionCallProto.GET_CURSOR_CAPS_MODE; 20 import static android.view.inputmethod.InputConnectionCallProto.GET_EXTRACTED_TEXT; 21 import static android.view.inputmethod.InputConnectionCallProto.GET_SELECTED_TEXT; 22 import static android.view.inputmethod.InputConnectionCallProto.GET_SURROUNDING_TEXT; 23 import static android.view.inputmethod.InputConnectionCallProto.GET_TEXT_AFTER_CURSOR; 24 import static android.view.inputmethod.InputConnectionCallProto.GET_TEXT_BEFORE_CURSOR; 25 import static android.view.inputmethod.InputConnectionCallProto.GetExtractedText.REQUEST; 26 27 import android.annotation.IntRange; 28 import android.annotation.NonNull; 29 import android.annotation.Nullable; 30 import android.util.proto.ProtoOutputStream; 31 import android.view.inputmethod.ExtractedText; 32 import android.view.inputmethod.ExtractedTextRequest; 33 import android.view.inputmethod.InputConnectionCallProto.GetCursorCapsMode; 34 import android.view.inputmethod.InputConnectionCallProto.GetExtractedText; 35 import android.view.inputmethod.InputConnectionCallProto.GetSelectedText; 36 import android.view.inputmethod.InputConnectionCallProto.GetSurroundingText; 37 import android.view.inputmethod.InputConnectionCallProto.GetTextAfterCursor; 38 import android.view.inputmethod.InputConnectionCallProto.GetTextBeforeCursor; 39 import android.view.inputmethod.SurroundingText; 40 41 /** 42 * Helper class for constructing {@link android.view.inputmethod.InputConnection} dumps, which are 43 * integrated into {@link ImeTracing}. 44 */ 45 public final class InputConnectionProtoDumper { 46 static final String TAG = "InputConnectionProtoDumper"; 47 InputConnectionProtoDumper()48 private InputConnectionProtoDumper() {} 49 50 /** 51 * Builder for InputConnectionCallProto to hold 52 * {@link android.view.inputmethod.InputConnection#getTextAfterCursor(int, int)} data. 53 * 54 * @param length The expected length of the text. This must be non-negative. 55 * @param flags Supplies additional options controlling how the text is 56 * returned. May be either {@code 0} or 57 * {@link android.view.inputmethod.InputConnection#GET_TEXT_WITH_STYLES}. 58 * @param result The text after the cursor position; the length of the 59 * returned text might be less than <var>length</var>. 60 * @return Byte-array holding the InputConnectionCallProto data. 61 */ 62 @NonNull buildGetTextAfterCursorProto(@ntRangefrom = 0) int length, int flags, @Nullable CharSequence result)63 public static byte[] buildGetTextAfterCursorProto(@IntRange(from = 0) int length, int flags, 64 @Nullable CharSequence result) { 65 ProtoOutputStream proto = new ProtoOutputStream(); 66 final long token = proto.start(GET_TEXT_AFTER_CURSOR); 67 proto.write(GetTextAfterCursor.LENGTH, length); 68 proto.write(GetTextAfterCursor.FLAGS, flags); 69 proto.end(token); 70 return proto.getBytes(); 71 } 72 73 /** 74 * Builder for InputConnectionCallProto to hold 75 * {@link android.view.inputmethod.InputConnection#getTextBeforeCursor(int, int)} data. 76 * 77 * @param length The expected length of the text. This must be non-negative. 78 * @param flags Supplies additional options controlling how the text is 79 * returned. May be either {@code 0} or 80 * {@link android.view.inputmethod.InputConnection#GET_TEXT_WITH_STYLES}. 81 * @param result The text before the cursor position; the length of the 82 * returned text might be less than <var>length</var>. 83 * @return Byte-array holding the InputConnectionCallProto data. 84 */ 85 @NonNull buildGetTextBeforeCursorProto(@ntRangefrom = 0) int length, int flags, @Nullable CharSequence result)86 public static byte[] buildGetTextBeforeCursorProto(@IntRange(from = 0) int length, 87 int flags, @Nullable CharSequence result) { 88 ProtoOutputStream proto = new ProtoOutputStream(); 89 final long token = proto.start(GET_TEXT_BEFORE_CURSOR); 90 proto.write(GetTextBeforeCursor.LENGTH, length); 91 proto.write(GetTextBeforeCursor.FLAGS, flags); 92 proto.end(token); 93 return proto.getBytes(); 94 } 95 96 /** 97 * Builder for InputConnectionCallProto to hold 98 * {@link android.view.inputmethod.InputConnection#getSelectedText(int)} data. 99 * 100 * @param flags Supplies additional options controlling how the text is 101 * returned. May be either {@code 0} or 102 * {@link android.view.inputmethod.InputConnection#GET_TEXT_WITH_STYLES}. 103 * @param result the text that is currently selected, if any, or null if 104 * no text is selected. In {@link android.os.Build.VERSION_CODES#N} and 105 * later, returns false when the target application does not implement 106 * this method. 107 * @return Byte-array holding the InputConnectionCallProto data. 108 */ 109 @NonNull buildGetSelectedTextProto(int flags, @Nullable CharSequence result)110 public static byte[] buildGetSelectedTextProto(int flags, @Nullable CharSequence result) { 111 ProtoOutputStream proto = new ProtoOutputStream(); 112 final long token = proto.start(GET_SELECTED_TEXT); 113 proto.write(GetSelectedText.FLAGS, flags); 114 proto.end(token); 115 return proto.getBytes(); 116 } 117 118 /** 119 * Builder for InputConnectionCallProto to hold 120 * {@link android.view.inputmethod.InputConnection#getSurroundingText(int, int, int)} data. 121 * 122 * @param beforeLength The expected length of the text before the cursor. 123 * @param afterLength The expected length of the text after the cursor. 124 * @param flags Supplies additional options controlling how the text is 125 * returned. May be either {@code 0} or 126 * {@link android.view.inputmethod.InputConnection#GET_TEXT_WITH_STYLES}. 127 * @param result an {@link SurroundingText} object describing the 128 * surrounding text and state of selection, or null if the input connection is no longer valid, 129 * or the editor can't comply with the request for some reason, or the application does not 130 * implement this method. The length of the returned text might be less than the sum of 131 * <var>beforeLength</var> and <var>afterLength</var> . 132 * @return Byte-array holding the InputConnectionCallProto data. 133 */ 134 @NonNull buildGetSurroundingTextProto(@ntRangefrom = 0) int beforeLength, @IntRange(from = 0) int afterLength, int flags, @Nullable SurroundingText result)135 public static byte[] buildGetSurroundingTextProto(@IntRange(from = 0) int beforeLength, 136 @IntRange(from = 0) int afterLength, int flags, @Nullable SurroundingText result) { 137 ProtoOutputStream proto = new ProtoOutputStream(); 138 final long token = proto.start(GET_SURROUNDING_TEXT); 139 proto.write(GetSurroundingText.BEFORE_LENGTH, beforeLength); 140 proto.write(GetSurroundingText.AFTER_LENGTH, afterLength); 141 proto.write(GetSurroundingText.FLAGS, flags); 142 if (result != null) { 143 final long token_result = proto.start(GetSurroundingText.RESULT); 144 proto.write(GetSurroundingText.SurroundingText.SELECTION_START, 145 result.getSelectionStart()); 146 proto.write(GetSurroundingText.SurroundingText.SELECTION_END, 147 result.getSelectionEnd()); 148 proto.write(GetSurroundingText.SurroundingText.OFFSET, result.getOffset()); 149 proto.end(token_result); 150 } 151 proto.end(token); 152 return proto.getBytes(); 153 } 154 155 /** 156 * Builder for InputConnectionCallProto to hold 157 * {@link android.view.inputmethod.InputConnection#getCursorCapsMode(int)} data. 158 * 159 * @param reqModes The desired modes to retrieve, as defined by 160 * {@link android.text.TextUtils#getCapsMode TextUtils.getCapsMode}. 161 * @param result the caps mode flags that are in effect at the current 162 * cursor position. See TYPE_TEXT_FLAG_CAPS_* in {@link android.text.InputType}. 163 * @return Byte-array holding the InputConnectionCallProto data. 164 */ 165 @NonNull buildGetCursorCapsModeProto(int reqModes, int result)166 public static byte[] buildGetCursorCapsModeProto(int reqModes, int result) { 167 ProtoOutputStream proto = new ProtoOutputStream(); 168 final long token = proto.start(GET_CURSOR_CAPS_MODE); 169 proto.write(GetCursorCapsMode.REQ_MODES, reqModes); 170 proto.write(GetCursorCapsMode.RESULT, result); 171 proto.end(token); 172 return proto.getBytes(); 173 } 174 175 /** 176 * Builder for InputConnectionCallProto to hold 177 * {@link android.view.inputmethod.InputConnection#getExtractedText(ExtractedTextRequest, int)} 178 * data. 179 * 180 * @param request Description of how the text should be returned. 181 * {@link ExtractedTextRequest} 182 * @param flags Additional options to control the client, either {@code 0} or 183 * {@link android.view.inputmethod.InputConnection#GET_EXTRACTED_TEXT_MONITOR}. 184 * @param result an {@link ExtractedText} 185 * object describing the state of the text view and containing the 186 * extracted text itself, or null if the input connection is no 187 * longer valid of the editor can't comply with the request for 188 * some reason. 189 * @return Byte-array holding the InputConnectionCallProto data. 190 */ 191 @NonNull buildGetExtractedTextProto(@onNull ExtractedTextRequest request, int flags, @Nullable ExtractedText result)192 public static byte[] buildGetExtractedTextProto(@NonNull ExtractedTextRequest 193 request, int flags, @Nullable ExtractedText result) { 194 ProtoOutputStream proto = new ProtoOutputStream(); 195 final long token = proto.start(GET_EXTRACTED_TEXT); 196 final long token_request = proto.start(REQUEST); 197 proto.write(GetExtractedText.ExtractedTextRequest.TOKEN, request.token); 198 proto.write(GetExtractedText.ExtractedTextRequest.FLAGS, request.flags); 199 proto.write(GetExtractedText.ExtractedTextRequest.HINT_MAX_LINES, request.hintMaxLines); 200 proto.write(GetExtractedText.ExtractedTextRequest.HINT_MAX_CHARS, request.hintMaxChars); 201 proto.end(token_request); 202 proto.write(GetExtractedText.FLAGS, flags); 203 proto.end(token); 204 return proto.getBytes(); 205 } 206 } 207