Felipe Leme | 1dfa9a0 | 2018-10-17 17:24:37 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2018 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 | package android.view.intelligence; |
| 17 | |
| 18 | import android.annotation.IntDef; |
Felipe Leme | 88eae3b | 2018-11-07 15:11:56 -0800 | [diff] [blame] | 19 | import android.annotation.NonNull; |
Felipe Leme | 1dfa9a0 | 2018-10-17 17:24:37 -0700 | [diff] [blame] | 20 | import android.annotation.Nullable; |
| 21 | import android.annotation.SystemApi; |
| 22 | import android.os.Parcel; |
| 23 | import android.os.Parcelable; |
Felipe Leme | 88eae3b | 2018-11-07 15:11:56 -0800 | [diff] [blame] | 24 | import android.os.SystemClock; |
Felipe Leme | 1dfa9a0 | 2018-10-17 17:24:37 -0700 | [diff] [blame] | 25 | import android.view.autofill.AutofillId; |
| 26 | |
Felipe Leme | 88eae3b | 2018-11-07 15:11:56 -0800 | [diff] [blame] | 27 | import com.android.internal.util.Preconditions; |
| 28 | |
| 29 | import java.io.PrintWriter; |
Felipe Leme | 1dfa9a0 | 2018-10-17 17:24:37 -0700 | [diff] [blame] | 30 | import java.lang.annotation.Retention; |
| 31 | import java.lang.annotation.RetentionPolicy; |
| 32 | |
| 33 | // TODO(b/111276913): add javadocs / implement Parcelable / implement |
| 34 | /** @hide */ |
| 35 | @SystemApi |
| 36 | public final class ContentCaptureEvent implements Parcelable { |
| 37 | |
Felipe Leme | 7a53408 | 2018-11-05 15:03:04 -0800 | [diff] [blame] | 38 | /** @hide */ |
| 39 | public static final int TYPE_ACTIVITY_DESTROYED = -2; |
| 40 | /** @hide */ |
| 41 | public static final int TYPE_ACTIVITY_CREATED = -1; |
| 42 | |
Felipe Leme | 1dfa9a0 | 2018-10-17 17:24:37 -0700 | [diff] [blame] | 43 | /** |
| 44 | * Called when the activity is started. |
| 45 | */ |
| 46 | public static final int TYPE_ACTIVITY_STARTED = 1; |
| 47 | |
| 48 | /** |
| 49 | * Called when the activity is resumed. |
| 50 | */ |
| 51 | public static final int TYPE_ACTIVITY_RESUMED = 2; |
| 52 | |
| 53 | /** |
| 54 | * Called when the activity is paused. |
| 55 | */ |
| 56 | public static final int TYPE_ACTIVITY_PAUSED = 3; |
| 57 | |
| 58 | /** |
| 59 | * Called when the activity is stopped. |
| 60 | */ |
| 61 | public static final int TYPE_ACTIVITY_STOPPED = 4; |
| 62 | |
| 63 | /** |
| 64 | * Called when a node has been added to the screen and is visible to the user. |
| 65 | * |
| 66 | * <p>The metadata of the node is available through {@link #getViewNode()}. |
| 67 | */ |
Felipe Leme | 88eae3b | 2018-11-07 15:11:56 -0800 | [diff] [blame] | 68 | public static final int TYPE_VIEW_APPEARED = 5; |
Felipe Leme | 1dfa9a0 | 2018-10-17 17:24:37 -0700 | [diff] [blame] | 69 | |
| 70 | /** |
| 71 | * Called when a node has been removed from the screen and is not visible to the user anymore. |
| 72 | * |
| 73 | * <p>The id of the node is available through {@link #getId()}. |
| 74 | */ |
Felipe Leme | 88eae3b | 2018-11-07 15:11:56 -0800 | [diff] [blame] | 75 | public static final int TYPE_VIEW_DISAPPEARED = 6; |
Felipe Leme | 1dfa9a0 | 2018-10-17 17:24:37 -0700 | [diff] [blame] | 76 | |
| 77 | /** |
| 78 | * Called when the text of a node has been changed. |
| 79 | * |
| 80 | * <p>The id of the node is available through {@link #getId()}, and the new text is |
| 81 | * available through {@link #getText()}. |
| 82 | */ |
| 83 | public static final int TYPE_VIEW_TEXT_CHANGED = 7; |
| 84 | |
| 85 | // TODO(b/111276913): add event to indicate when FLAG_SECURE was changed? |
| 86 | |
| 87 | /** @hide */ |
| 88 | @IntDef(prefix = { "TYPE_" }, value = { |
| 89 | TYPE_ACTIVITY_STARTED, |
| 90 | TYPE_ACTIVITY_PAUSED, |
| 91 | TYPE_ACTIVITY_RESUMED, |
| 92 | TYPE_ACTIVITY_STOPPED, |
Felipe Leme | 88eae3b | 2018-11-07 15:11:56 -0800 | [diff] [blame] | 93 | TYPE_VIEW_APPEARED, |
| 94 | TYPE_VIEW_DISAPPEARED, |
Felipe Leme | 1dfa9a0 | 2018-10-17 17:24:37 -0700 | [diff] [blame] | 95 | TYPE_VIEW_TEXT_CHANGED |
| 96 | }) |
| 97 | @Retention(RetentionPolicy.SOURCE) |
Felipe Leme | 7a53408 | 2018-11-05 15:03:04 -0800 | [diff] [blame] | 98 | public @interface EventType{} |
| 99 | |
| 100 | private final int mType; |
| 101 | private final long mEventTime; |
| 102 | private final int mFlags; |
Felipe Leme | 88eae3b | 2018-11-07 15:11:56 -0800 | [diff] [blame] | 103 | private @Nullable AutofillId mId; |
| 104 | private @Nullable ViewNode mNode; |
| 105 | private @Nullable CharSequence mText; |
Felipe Leme | 1dfa9a0 | 2018-10-17 17:24:37 -0700 | [diff] [blame] | 106 | |
| 107 | /** @hide */ |
Felipe Leme | 7a53408 | 2018-11-05 15:03:04 -0800 | [diff] [blame] | 108 | public ContentCaptureEvent(int type, long eventTime, int flags) { |
| 109 | mType = type; |
| 110 | mEventTime = eventTime; |
| 111 | mFlags = flags; |
Felipe Leme | 1dfa9a0 | 2018-10-17 17:24:37 -0700 | [diff] [blame] | 112 | } |
| 113 | |
Felipe Leme | 88eae3b | 2018-11-07 15:11:56 -0800 | [diff] [blame] | 114 | |
| 115 | /** @hide */ |
| 116 | public ContentCaptureEvent(int type, int flags) { |
| 117 | this(type, SystemClock.uptimeMillis(), flags); |
| 118 | } |
| 119 | |
| 120 | /** @hide */ |
| 121 | public ContentCaptureEvent(int type) { |
| 122 | this(type, /* flags= */ 0); |
| 123 | } |
| 124 | |
| 125 | /** @hide */ |
| 126 | public ContentCaptureEvent setAutofillId(@NonNull AutofillId id) { |
| 127 | mId = Preconditions.checkNotNull(id); |
| 128 | return this; |
| 129 | } |
| 130 | |
| 131 | /** @hide */ |
| 132 | public ContentCaptureEvent setViewNode(@NonNull ViewNode node) { |
| 133 | mNode = Preconditions.checkNotNull(node); |
| 134 | return this; |
| 135 | } |
| 136 | |
| 137 | /** @hide */ |
| 138 | public ContentCaptureEvent setText(@Nullable CharSequence text) { |
| 139 | mText = text; |
| 140 | return this; |
| 141 | } |
| 142 | |
Felipe Leme | 1dfa9a0 | 2018-10-17 17:24:37 -0700 | [diff] [blame] | 143 | /** |
| 144 | * Gets the type of the event. |
| 145 | * |
| 146 | * @return one of {@link #TYPE_ACTIVITY_STARTED}, {@link #TYPE_ACTIVITY_RESUMED}, |
| 147 | * {@link #TYPE_ACTIVITY_PAUSED}, {@link #TYPE_ACTIVITY_STOPPED}, |
Felipe Leme | 88eae3b | 2018-11-07 15:11:56 -0800 | [diff] [blame] | 148 | * {@link #TYPE_VIEW_APPEARED}, {@link #TYPE_VIEW_DISAPPEARED}, |
| 149 | * or {@link #TYPE_VIEW_TEXT_CHANGED}. |
Felipe Leme | 1dfa9a0 | 2018-10-17 17:24:37 -0700 | [diff] [blame] | 150 | */ |
| 151 | public @EventType int getType() { |
Felipe Leme | 7a53408 | 2018-11-05 15:03:04 -0800 | [diff] [blame] | 152 | return mType; |
Felipe Leme | 1dfa9a0 | 2018-10-17 17:24:37 -0700 | [diff] [blame] | 153 | } |
| 154 | |
| 155 | /** |
| 156 | * Gets when the event was generated, in ms. |
| 157 | */ |
| 158 | public long getEventTime() { |
Felipe Leme | 7a53408 | 2018-11-05 15:03:04 -0800 | [diff] [blame] | 159 | return mEventTime; |
Felipe Leme | 1dfa9a0 | 2018-10-17 17:24:37 -0700 | [diff] [blame] | 160 | } |
| 161 | |
| 162 | /** |
| 163 | * Gets optional flags associated with the event. |
| 164 | * |
| 165 | * @return either {@code 0} or |
Felipe Leme | ecb08be | 2018-11-27 15:48:47 -0800 | [diff] [blame] | 166 | * {@link android.view.intelligence.ContentCaptureManager#FLAG_USER_INPUT}. |
Felipe Leme | 1dfa9a0 | 2018-10-17 17:24:37 -0700 | [diff] [blame] | 167 | */ |
| 168 | public int getFlags() { |
Felipe Leme | 7a53408 | 2018-11-05 15:03:04 -0800 | [diff] [blame] | 169 | return mFlags; |
Felipe Leme | 1dfa9a0 | 2018-10-17 17:24:37 -0700 | [diff] [blame] | 170 | } |
| 171 | |
| 172 | /** |
| 173 | * Gets the whole metadata of the node associated with the event. |
| 174 | * |
Felipe Leme | 88eae3b | 2018-11-07 15:11:56 -0800 | [diff] [blame] | 175 | * <p>Only set on {@link #TYPE_VIEW_APPEARED} events. |
Felipe Leme | 1dfa9a0 | 2018-10-17 17:24:37 -0700 | [diff] [blame] | 176 | */ |
| 177 | @Nullable |
| 178 | public ViewNode getViewNode() { |
Felipe Leme | 88eae3b | 2018-11-07 15:11:56 -0800 | [diff] [blame] | 179 | return mNode; |
Felipe Leme | 1dfa9a0 | 2018-10-17 17:24:37 -0700 | [diff] [blame] | 180 | } |
| 181 | |
| 182 | /** |
| 183 | * Gets the {@link AutofillId} of the node associated with the event. |
| 184 | * |
Felipe Leme | 88eae3b | 2018-11-07 15:11:56 -0800 | [diff] [blame] | 185 | * <p>Only set on {@link #TYPE_VIEW_DISAPPEARED} and {@link #TYPE_VIEW_TEXT_CHANGED} events. |
Felipe Leme | 1dfa9a0 | 2018-10-17 17:24:37 -0700 | [diff] [blame] | 186 | */ |
| 187 | @Nullable |
| 188 | public AutofillId getId() { |
Felipe Leme | 88eae3b | 2018-11-07 15:11:56 -0800 | [diff] [blame] | 189 | return mId; |
Felipe Leme | 1dfa9a0 | 2018-10-17 17:24:37 -0700 | [diff] [blame] | 190 | } |
| 191 | |
| 192 | /** |
| 193 | * Gets the current text of the node associated with the event. |
| 194 | * |
| 195 | * <p>Only set on {@link #TYPE_VIEW_TEXT_CHANGED} events. |
| 196 | */ |
| 197 | @Nullable |
| 198 | public CharSequence getText() { |
Felipe Leme | 88eae3b | 2018-11-07 15:11:56 -0800 | [diff] [blame] | 199 | return mText; |
| 200 | } |
| 201 | |
| 202 | /** @hide */ |
| 203 | public void dump(@NonNull PrintWriter pw) { |
| 204 | pw.print("type="); pw.print(getTypeAsString(mType)); |
| 205 | pw.print(", time="); pw.print(mEventTime); |
| 206 | if (mFlags > 0) { |
| 207 | pw.print(", flags="); pw.print(mFlags); |
| 208 | } |
| 209 | if (mId != null) { |
| 210 | pw.print(", id="); pw.print(mId); |
| 211 | } |
| 212 | if (mNode != null) { |
| 213 | pw.print(", id="); pw.print(mNode.getAutofillId()); |
| 214 | } |
Felipe Leme | 1dfa9a0 | 2018-10-17 17:24:37 -0700 | [diff] [blame] | 215 | } |
| 216 | |
Felipe Leme | 1dfa9a0 | 2018-10-17 17:24:37 -0700 | [diff] [blame] | 217 | @Override |
Felipe Leme | 7a53408 | 2018-11-05 15:03:04 -0800 | [diff] [blame] | 218 | public String toString() { |
| 219 | final StringBuilder string = new StringBuilder("ContentCaptureEvent[type=") |
Felipe Leme | 88eae3b | 2018-11-07 15:11:56 -0800 | [diff] [blame] | 220 | .append(getTypeAsString(mType)); |
Felipe Leme | 7a53408 | 2018-11-05 15:03:04 -0800 | [diff] [blame] | 221 | if (mFlags > 0) { |
| 222 | string.append(", flags=").append(mFlags); |
| 223 | } |
Felipe Leme | 88eae3b | 2018-11-07 15:11:56 -0800 | [diff] [blame] | 224 | if (mId != null) { |
| 225 | string.append(", id=").append(mId); |
| 226 | } |
| 227 | if (mNode != null) { |
| 228 | final String className = mNode.getClassName(); |
| 229 | if (mNode != null) { |
| 230 | string.append(", class=").append(className); |
| 231 | } |
| 232 | string.append(", id=").append(mNode.getAutofillId()); |
| 233 | } |
Felipe Leme | 7a53408 | 2018-11-05 15:03:04 -0800 | [diff] [blame] | 234 | return string.append(']').toString(); |
| 235 | } |
| 236 | |
| 237 | @Override |
Felipe Leme | 1dfa9a0 | 2018-10-17 17:24:37 -0700 | [diff] [blame] | 238 | public int describeContents() { |
| 239 | return 0; |
| 240 | } |
| 241 | |
| 242 | @Override |
| 243 | public void writeToParcel(Parcel parcel, int flags) { |
Felipe Leme | 7a53408 | 2018-11-05 15:03:04 -0800 | [diff] [blame] | 244 | parcel.writeInt(mType); |
| 245 | parcel.writeLong(mEventTime); |
| 246 | parcel.writeInt(mFlags); |
Felipe Leme | 88eae3b | 2018-11-07 15:11:56 -0800 | [diff] [blame] | 247 | parcel.writeParcelable(mId, flags); |
| 248 | ViewNode.writeToParcel(parcel, mNode, flags); |
| 249 | parcel.writeCharSequence(mText); |
Felipe Leme | 1dfa9a0 | 2018-10-17 17:24:37 -0700 | [diff] [blame] | 250 | } |
| 251 | |
| 252 | public static final Parcelable.Creator<ContentCaptureEvent> CREATOR = |
| 253 | new Parcelable.Creator<ContentCaptureEvent>() { |
| 254 | |
| 255 | @Override |
| 256 | public ContentCaptureEvent createFromParcel(Parcel parcel) { |
Felipe Leme | 7a53408 | 2018-11-05 15:03:04 -0800 | [diff] [blame] | 257 | final int type = parcel.readInt(); |
| 258 | final long eventTime = parcel.readLong(); |
| 259 | final int flags = parcel.readInt(); |
Felipe Leme | 88eae3b | 2018-11-07 15:11:56 -0800 | [diff] [blame] | 260 | final ContentCaptureEvent event = new ContentCaptureEvent(type, eventTime, flags); |
| 261 | final AutofillId id = parcel.readParcelable(null); |
| 262 | if (id != null) { |
| 263 | event.setAutofillId(id); |
| 264 | } |
| 265 | final ViewNode node = ViewNode.readFromParcel(parcel); |
| 266 | if (node != null) { |
| 267 | event.setViewNode(node); |
| 268 | } |
| 269 | event.setText(parcel.readCharSequence()); |
| 270 | return event; |
Felipe Leme | 1dfa9a0 | 2018-10-17 17:24:37 -0700 | [diff] [blame] | 271 | } |
| 272 | |
| 273 | @Override |
| 274 | public ContentCaptureEvent[] newArray(int size) { |
| 275 | return new ContentCaptureEvent[size]; |
| 276 | } |
| 277 | }; |
Felipe Leme | 7a53408 | 2018-11-05 15:03:04 -0800 | [diff] [blame] | 278 | |
Felipe Leme | 7a53408 | 2018-11-05 15:03:04 -0800 | [diff] [blame] | 279 | /** @hide */ |
| 280 | public static String getTypeAsString(@EventType int type) { |
| 281 | switch (type) { |
| 282 | case TYPE_ACTIVITY_STARTED: |
| 283 | return "ACTIVITY_STARTED"; |
| 284 | case TYPE_ACTIVITY_RESUMED: |
| 285 | return "ACTIVITY_RESUMED"; |
| 286 | case TYPE_ACTIVITY_PAUSED: |
| 287 | return "ACTIVITY_PAUSED"; |
| 288 | case TYPE_ACTIVITY_STOPPED: |
| 289 | return "ACTIVITY_STOPPED"; |
Felipe Leme | 88eae3b | 2018-11-07 15:11:56 -0800 | [diff] [blame] | 290 | case TYPE_VIEW_APPEARED: |
| 291 | return "VIEW_APPEARED"; |
| 292 | case TYPE_VIEW_DISAPPEARED: |
| 293 | return "VIEW_DISAPPEARED"; |
Felipe Leme | 7a53408 | 2018-11-05 15:03:04 -0800 | [diff] [blame] | 294 | case TYPE_VIEW_TEXT_CHANGED: |
| 295 | return "VIEW_TEXT_CHANGED"; |
| 296 | default: |
| 297 | return "UKNOWN_TYPE: " + type; |
| 298 | } |
| 299 | } |
Felipe Leme | 1dfa9a0 | 2018-10-17 17:24:37 -0700 | [diff] [blame] | 300 | } |