| /* |
| * Copyright (C) 2022 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 com.example.android.sampleinputmethodaccessibilityservice; |
| |
| import android.os.Parcel; |
| import android.view.inputmethod.EditorInfo; |
| |
| import androidx.annotation.Nullable; |
| |
| final class EventMonitor { |
| @FunctionalInterface |
| interface DebugMessageCallback { |
| void onMessageChanged(String message); |
| } |
| |
| private enum State { |
| BeforeFirstStartInput, |
| InputStarted, |
| InputRestarted, |
| InputFinished, |
| } |
| |
| private State mState = State.BeforeFirstStartInput; |
| private int mStartInputCount = 0; |
| private int mUpdateSelectionCount = 0; |
| private int mFinishInputCount = 0; |
| private int mSelStart = -1; |
| private int mSelEnd = -1; |
| private int mCompositionStart = -1; |
| private int mCompositionEnd = -1; |
| @Nullable |
| private EditorInfo mEditorInfo; |
| |
| @Nullable |
| private final DebugMessageCallback mDebugMessageCallback; |
| |
| void onStartInput(EditorInfo attribute, boolean restarting) { |
| ++mStartInputCount; |
| mState = restarting ? State.InputRestarted : State.InputStarted; |
| mSelStart = attribute.initialSelStart; |
| mSelEnd = attribute.initialSelEnd; |
| mCompositionStart = -1; |
| mCompositionEnd = -1; |
| mEditorInfo = cloneEditorInfo(attribute); |
| updateMessage(); |
| } |
| |
| void onFinishInput() { |
| ++mFinishInputCount; |
| mState = State.InputFinished; |
| mEditorInfo = null; |
| updateMessage(); |
| } |
| |
| void onUpdateSelection(int oldSelStart, int oldSelEnd, int newSelStart, |
| int newSelEnd, int candidatesStart, int candidatesEnd) { |
| ++mUpdateSelectionCount; |
| mSelStart = newSelStart; |
| mSelEnd = newSelEnd; |
| mCompositionStart = candidatesStart; |
| mCompositionEnd = candidatesEnd; |
| updateMessage(); |
| } |
| |
| EventMonitor(@Nullable DebugMessageCallback callback) { |
| mDebugMessageCallback = callback; |
| } |
| |
| private void updateMessage() { |
| if (mDebugMessageCallback == null) { |
| return; |
| } |
| |
| final StringBuilder sb = new StringBuilder(); |
| sb.append("state=").append(mState).append("\n") |
| .append("startInputCount=").append(mStartInputCount).append("\n") |
| .append("finishInputCount=").append(mFinishInputCount).append("\n") |
| .append("updateSelectionCount=").append(mUpdateSelectionCount).append("\n"); |
| if (mSelStart == -1 && mSelEnd == -1) { |
| sb.append("selection=none\n"); |
| } else { |
| sb.append("selection=(").append(mSelStart).append(",").append(mSelEnd).append(")\n"); |
| } |
| if (mCompositionStart == -1 && mCompositionEnd == -1) { |
| sb.append("composition=none"); |
| } else { |
| sb.append("composition=(") |
| .append(mCompositionStart).append(",").append(mCompositionEnd).append(")"); |
| } |
| if (mEditorInfo != null) { |
| sb.append("\n"); |
| sb.append("packageName=").append(mEditorInfo.packageName).append("\n"); |
| sb.append("inputType="); |
| EditorInfoUtil.dumpInputType(sb, mEditorInfo.inputType); |
| sb.append("\n"); |
| sb.append("imeOptions="); |
| EditorInfoUtil.dumpImeOptions(sb, mEditorInfo.imeOptions); |
| } |
| |
| mDebugMessageCallback.onMessageChanged(sb.toString()); |
| } |
| |
| private static EditorInfo cloneEditorInfo(EditorInfo original) { |
| Parcel parcel = null; |
| try { |
| parcel = Parcel.obtain(); |
| original.writeToParcel(parcel, 0); |
| parcel.setDataPosition(0); |
| return EditorInfo.CREATOR.createFromParcel(parcel); |
| } finally { |
| if (parcel != null) { |
| parcel.recycle(); |
| } |
| } |
| } |
| } |