ViewState.java revision 8697a31d3c32f212cee48b4d0576e8783c6c9d5f
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 17package com.android.server.autofill; 18 19import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST; 20import static com.android.server.autofill.Helper.sDebug; 21import static com.android.server.autofill.Helper.sVerbose; 22 23import android.annotation.Nullable; 24import android.graphics.Rect; 25import android.service.autofill.FillResponse; 26import android.util.DebugUtils; 27import android.util.Slog; 28import android.view.autofill.AutofillId; 29import android.view.autofill.AutofillValue; 30 31import java.io.PrintWriter; 32 33/** 34 * State for a given view with a AutofillId. 35 * 36 * <p>This class holds state about a view and calls its listener when the fill UI is ready to 37 * be displayed for the view. 38 */ 39final class ViewState { 40 interface Listener { 41 /** 42 * Called when the fill UI is ready to be shown for this view. 43 */ 44 void onFillReady(FillResponse fillResponse, AutofillId focusedId, 45 @Nullable AutofillValue value); 46 } 47 48 private static final String TAG = "ViewState"; 49 50 // NOTE: state constants must be public because of flagstoString(). 51 public static final int STATE_UNKNOWN = 0x000; 52 /** Initial state. */ 53 public static final int STATE_INITIAL = 0x001; 54 /** View id is present in a dataset returned by the service. */ 55 public static final int STATE_FILLABLE = 0x002; 56 /** View was autofilled after user selected a dataset. */ 57 public static final int STATE_AUTOFILLED = 0x004; 58 /** View value was changed, but not by the service. */ 59 public static final int STATE_CHANGED = 0x008; 60 /** Set only in the View that started a session. */ 61 public static final int STATE_STARTED_SESSION = 0x010; 62 /** View that started a new partition when focused on. */ 63 public static final int STATE_STARTED_PARTITION = 0x020; 64 /** User select a dataset in this view, but service must authenticate first. */ 65 public static final int STATE_WAITING_DATASET_AUTH = 0x040; 66 /** Service does not care about this view. */ 67 public static final int STATE_IGNORED = 0x080; 68 /** User manually request autofill in this view, after it was already autofilled. */ 69 public static final int STATE_RESTARTED_SESSION = 0x100; 70 71 public final AutofillId id; 72 73 private final Listener mListener; 74 private final Session mSession; 75 76 private FillResponse mResponse; 77 private AutofillValue mInitialValue; 78 private AutofillValue mCurrentValue; 79 private AutofillValue mAutofilledValue; 80 private Rect mVirtualBounds; 81 private int mState; 82 83 ViewState(Session session, AutofillId id, AutofillValue value, Listener listener, int state) { 84 mSession = session; 85 this.id = id; 86 mInitialValue = value; 87 mListener = listener; 88 mState = state; 89 } 90 91 /** 92 * Gets the boundaries of the virtual view, or {@code null} if the the view is not virtual. 93 */ 94 @Nullable 95 Rect getVirtualBounds() { 96 return mVirtualBounds; 97 } 98 99 /** 100 * Gets the current value of the view. 101 */ 102 @Nullable 103 AutofillValue getCurrentValue() { 104 return mCurrentValue; 105 } 106 107 void setCurrentValue(AutofillValue value) { 108 mCurrentValue = value; 109 } 110 111 @Nullable 112 AutofillValue getAutofilledValue() { 113 return mAutofilledValue; 114 } 115 116 void setAutofilledValue(@Nullable AutofillValue value) { 117 mAutofilledValue = value; 118 } 119 120 @Nullable 121 AutofillValue getInitialValue() { 122 return mInitialValue; 123 } 124 125 @Nullable 126 FillResponse getResponse() { 127 return mResponse; 128 } 129 130 void setResponse(FillResponse response) { 131 mResponse = response; 132 } 133 134 CharSequence getServiceName() { 135 return mSession.getServiceName(); 136 } 137 138 int getState() { 139 return mState; 140 } 141 142 String getStateAsString() { 143 return DebugUtils.flagsToString(ViewState.class, "STATE_", mState); 144 } 145 146 void setState(int state) { 147 if (mState == STATE_INITIAL) { 148 mState = state; 149 } else { 150 mState |= state; 151 } 152 } 153 154 void resetState(int state) { 155 mState &= ~state; 156 } 157 158 // TODO: refactor / rename / document this method (and maybeCallOnFillReady) to make it clear 159 // that it can change the value and update the UI; similarly, should replace code that 160 // directly sets mAutofillValue to use encapsulation. 161 void update(@Nullable AutofillValue autofillValue, @Nullable Rect virtualBounds, int flags) { 162 if (autofillValue != null) { 163 mCurrentValue = autofillValue; 164 } 165 if (virtualBounds != null) { 166 mVirtualBounds = virtualBounds; 167 } 168 169 maybeCallOnFillReady(flags); 170 } 171 172 /** 173 * Calls {@link 174 * Listener#onFillReady(FillResponse, AutofillId, AutofillValue)} if the 175 * fill UI is ready to be displayed (i.e. when response and bounds are set). 176 */ 177 void maybeCallOnFillReady(int flags) { 178 if ((mState & STATE_AUTOFILLED) != 0 && (flags & FLAG_MANUAL_REQUEST) == 0) { 179 if (sDebug) Slog.d(TAG, "Ignoring UI for " + id + " on " + getStateAsString()); 180 return; 181 } 182 // First try the current response associated with this View. 183 if (mResponse != null) { 184 if (mResponse.getDatasets() != null || mResponse.getAuthentication() != null) { 185 mListener.onFillReady(mResponse, this.id, mCurrentValue); 186 } 187 } 188 } 189 190 @Override 191 public String toString() { 192 return "ViewState: [id=" + id + ", initialValue=" + mInitialValue 193 + ", currentValue=" + mCurrentValue + ", autofilledValue=" + mAutofilledValue 194 + ", bounds=" + mVirtualBounds + ", state=" + getStateAsString() + "]"; 195 } 196 197 void dump(String prefix, PrintWriter pw) { 198 pw.print(prefix); pw.print("id:" ); pw.println(this.id); 199 pw.print(prefix); pw.print("state:" ); pw.println(getStateAsString()); 200 pw.print(prefix); pw.print("response:"); 201 if (mResponse == null) { 202 pw.println("N/A"); 203 } else { 204 if (sVerbose) { 205 pw.println(mResponse); 206 } else { 207 pw.println(mResponse.getRequestId()); 208 } 209 } 210 pw.print(prefix); pw.print("initialValue:" ); pw.println(mInitialValue); 211 pw.print(prefix); pw.print("currentValue:" ); pw.println(mCurrentValue); 212 pw.print(prefix); pw.print("autofilledValue:" ); pw.println(mAutofilledValue); 213 pw.print(prefix); pw.print("virtualBounds:" ); pw.println(mVirtualBounds); 214 } 215}