1 /* 2 * Copyright (C) 2017 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.cts.mockime; 18 19 import android.inputmethodservice.AbstractInputMethodService; 20 import android.os.Bundle; 21 import androidx.annotation.NonNull; 22 import androidx.annotation.Nullable; 23 import android.view.View; 24 25 /** 26 * An immutable object that stores event happened in the {@link MockIme}. 27 */ 28 public final class ImeEvent { 29 30 private enum ReturnType { 31 Null, 32 KnownUnsupportedType, 33 Boolean, 34 } 35 getReturnTypeFromObject(@ullable Object object)36 private static ReturnType getReturnTypeFromObject(@Nullable Object object) { 37 if (object == null) { 38 return ReturnType.Null; 39 } 40 if (object instanceof AbstractInputMethodService.AbstractInputMethodImpl) { 41 return ReturnType.KnownUnsupportedType; 42 } 43 if (object instanceof View) { 44 return ReturnType.KnownUnsupportedType; 45 } 46 if (object instanceof Boolean) { 47 return ReturnType.Boolean; 48 } 49 throw new UnsupportedOperationException("Unsupported return type=" + object); 50 } 51 ImeEvent(@onNull String eventName, int nestLevel, @NonNull String threadName, int threadId, boolean isMainThread, long enterTimestamp, long exitTimestamp, long enterWallTime, long exitWallTime, @NonNull ImeState enterState, @Nullable ImeState exitState, @NonNull Bundle arguments, @Nullable Object returnValue)52 ImeEvent(@NonNull String eventName, int nestLevel, @NonNull String threadName, int threadId, 53 boolean isMainThread, long enterTimestamp, long exitTimestamp, long enterWallTime, 54 long exitWallTime, @NonNull ImeState enterState, @Nullable ImeState exitState, 55 @NonNull Bundle arguments, @Nullable Object returnValue) { 56 this(eventName, nestLevel, threadName, threadId, isMainThread, enterTimestamp, 57 exitTimestamp, enterWallTime, exitWallTime, enterState, exitState, arguments, 58 returnValue, getReturnTypeFromObject(returnValue)); 59 } 60 ImeEvent(@onNull String eventName, int nestLevel, @NonNull String threadName, int threadId, boolean isMainThread, long enterTimestamp, long exitTimestamp, long enterWallTime, long exitWallTime, @NonNull ImeState enterState, @Nullable ImeState exitState, @NonNull Bundle arguments, @Nullable Object returnValue, @NonNull ReturnType returnType)61 private ImeEvent(@NonNull String eventName, int nestLevel, @NonNull String threadName, 62 int threadId, boolean isMainThread, long enterTimestamp, long exitTimestamp, 63 long enterWallTime, long exitWallTime, @NonNull ImeState enterState, 64 @Nullable ImeState exitState, @NonNull Bundle arguments, @Nullable Object returnValue, 65 @NonNull ReturnType returnType) { 66 mEventName = eventName; 67 mNestLevel = nestLevel; 68 mThreadName = threadName; 69 mThreadId = threadId; 70 mIsMainThread = isMainThread; 71 mEnterTimestamp = enterTimestamp; 72 mExitTimestamp = exitTimestamp; 73 mEnterWallTime = enterWallTime; 74 mExitWallTime = exitWallTime; 75 mEnterState = enterState; 76 mExitState = exitState; 77 mArguments = arguments; 78 mReturnValue = returnValue; 79 mReturnType = returnType; 80 } 81 82 @NonNull toBundle()83 Bundle toBundle() { 84 final Bundle bundle = new Bundle(); 85 bundle.putString("mEventName", mEventName); 86 bundle.putInt("mNestLevel", mNestLevel); 87 bundle.putString("mThreadName", mThreadName); 88 bundle.putInt("mThreadId", mThreadId); 89 bundle.putBoolean("mIsMainThread", mIsMainThread); 90 bundle.putLong("mEnterTimestamp", mEnterTimestamp); 91 bundle.putLong("mExitTimestamp", mExitTimestamp); 92 bundle.putLong("mEnterWallTime", mEnterWallTime); 93 bundle.putLong("mExitWallTime", mExitWallTime); 94 bundle.putBundle("mEnterState", mEnterState.toBundle()); 95 bundle.putBundle("mExitState", mExitState != null ? mExitState.toBundle() : null); 96 bundle.putBundle("mArguments", mArguments); 97 bundle.putString("mReturnType", mReturnType.name()); 98 switch (mReturnType) { 99 case Null: 100 case KnownUnsupportedType: 101 break; 102 case Boolean: 103 bundle.putBoolean("mReturnValue", getReturnBooleanValue()); 104 break; 105 default: 106 throw new UnsupportedOperationException("Unsupported type=" + mReturnType); 107 } 108 return bundle; 109 } 110 111 @NonNull fromBundle(@onNull Bundle bundle)112 static ImeEvent fromBundle(@NonNull Bundle bundle) { 113 final String eventName = bundle.getString("mEventName"); 114 final int nestLevel = bundle.getInt("mNestLevel"); 115 final String threadName = bundle.getString("mThreadName"); 116 final int threadId = bundle.getInt("mThreadId"); 117 final boolean isMainThread = bundle.getBoolean("mIsMainThread"); 118 final long enterTimestamp = bundle.getLong("mEnterTimestamp"); 119 final long exitTimestamp = bundle.getLong("mExitTimestamp"); 120 final long enterWallTime = bundle.getLong("mEnterWallTime"); 121 final long exitWallTime = bundle.getLong("mExitWallTime"); 122 final ImeState enterState = ImeState.fromBundle(bundle.getBundle("mEnterState")); 123 final ImeState exitState = ImeState.fromBundle(bundle.getBundle("mExitState")); 124 final Bundle arguments = bundle.getBundle("mArguments"); 125 final Object result; 126 final ReturnType returnType = ReturnType.valueOf(bundle.getString("mReturnType")); 127 switch (returnType) { 128 case Null: 129 case KnownUnsupportedType: 130 result = null; 131 break; 132 case Boolean: 133 result = bundle.getBoolean("mReturnValue"); 134 break; 135 default: 136 throw new UnsupportedOperationException("Unsupported type=" + returnType); 137 } 138 return new ImeEvent(eventName, nestLevel, threadName, 139 threadId, isMainThread, enterTimestamp, exitTimestamp, enterWallTime, exitWallTime, 140 enterState, exitState, arguments, result, returnType); 141 } 142 143 /** 144 * Returns a string that represents the type of this event. 145 * 146 * <p>Examples: "onCreate", "onStartInput", ...</p> 147 * 148 * <p>TODO: Use enum type or something like that instead of raw String type.</p> 149 * @return A string that represents the type of this event. 150 */ 151 @NonNull getEventName()152 public String getEventName() { 153 return mEventName; 154 } 155 156 /** 157 * Returns the nest level of this event. 158 * 159 * <p>For instance, when "showSoftInput" internally calls 160 * "onStartInputView", the event for "onStartInputView" has 1 level higher 161 * nest level than "showSoftInput".</p> 162 */ getNestLevel()163 public int getNestLevel() { 164 return mNestLevel; 165 } 166 167 /** 168 * @return Name of the thread, where the event was consumed. 169 */ 170 @NonNull getThreadName()171 public String getThreadName() { 172 return mThreadName; 173 } 174 175 /** 176 * @return Thread ID (TID) of the thread, where the event was consumed. 177 */ getThreadId()178 public int getThreadId() { 179 return mThreadId; 180 } 181 182 /** 183 * @return {@code true} if the event was being consumed in the main thread. 184 */ isMainThread()185 public boolean isMainThread() { 186 return mIsMainThread; 187 } 188 189 /** 190 * @return Monotonic time measured by {@link android.os.SystemClock#elapsedRealtimeNanos()} when 191 * the corresponding event handler was called back. 192 */ getEnterTimestamp()193 public long getEnterTimestamp() { 194 return mEnterTimestamp; 195 } 196 197 /** 198 * @return Monotonic time measured by {@link android.os.SystemClock#elapsedRealtimeNanos()} when 199 * the corresponding event handler finished. 200 */ getExitTimestamp()201 public long getExitTimestamp() { 202 return mExitTimestamp; 203 } 204 205 /** 206 * @return Wall-clock time measured by {@link System#currentTimeMillis()} when the corresponding 207 * event handler was called back. 208 */ getEnterWallTime()209 public long getEnterWallTime() { 210 return mEnterWallTime; 211 } 212 213 /** 214 * @return Wall-clock time measured by {@link System#currentTimeMillis()} when the corresponding 215 * event handler finished. 216 */ getExitWallTime()217 public long getExitWallTime() { 218 return mExitWallTime; 219 } 220 221 /** 222 * @return IME state snapshot taken when the corresponding event handler was called back. 223 */ 224 @NonNull getEnterState()225 public ImeState getEnterState() { 226 return mEnterState; 227 } 228 229 /** 230 * @return IME state snapshot taken when the corresponding event handler finished. 231 */ 232 @Nullable getExitState()233 public ImeState getExitState() { 234 return mExitState; 235 } 236 237 /** 238 * @return {@link Bundle} that stores parameters passed to the corresponding event handler. 239 */ 240 @NonNull getArguments()241 public Bundle getArguments() { 242 return mArguments; 243 } 244 245 /** 246 * @return result value of this event. 247 * @throws NullPointerException if the return value is {@code null} 248 * @throws ClassCastException if the return value is non-{@code null} object that is different 249 * from {@link Boolean} 250 */ getReturnBooleanValue()251 public boolean getReturnBooleanValue() { 252 if (mReturnType == ReturnType.Null) { 253 throw new NullPointerException(); 254 } 255 if (mReturnType != ReturnType.Boolean) { 256 throw new ClassCastException(); 257 } 258 return (Boolean) mReturnValue; 259 } 260 261 /** 262 * @return {@code true} if the event is issued when the event starts, not when the event 263 * finishes. 264 */ isEnterEvent()265 public boolean isEnterEvent() { 266 return mExitState == null; 267 } 268 269 @NonNull 270 private final String mEventName; 271 private final int mNestLevel; 272 @NonNull 273 private final String mThreadName; 274 private final int mThreadId; 275 private final boolean mIsMainThread; 276 private final long mEnterTimestamp; 277 private final long mExitTimestamp; 278 private final long mEnterWallTime; 279 private final long mExitWallTime; 280 @NonNull 281 private final ImeState mEnterState; 282 @Nullable 283 private final ImeState mExitState; 284 @NonNull 285 private final Bundle mArguments; 286 @Nullable 287 private final Object mReturnValue; 288 @NonNull 289 private final ReturnType mReturnType; 290 } 291