FillContext.java revision 22567d3415c88b2d054a1540dd868e60d274aac8
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 android.service.autofill; 18 19import static android.view.autofill.Helper.sDebug; 20 21import android.annotation.NonNull; 22import android.annotation.Nullable; 23import android.app.assist.AssistStructure; 24import android.app.assist.AssistStructure.ViewNode; 25import android.os.Bundle; 26import android.os.CancellationSignal; 27import android.os.Parcel; 28import android.os.Parcelable; 29import android.util.ArrayMap; 30import android.util.SparseIntArray; 31import android.view.autofill.AutofillId; 32 33import java.util.ArrayList; 34import java.util.LinkedList; 35 36/** 37 * This class represents a context for each fill request made via {@link 38 * AutofillService#onFillRequest(FillRequest, CancellationSignal, FillCallback)}. 39 * It contains a snapshot of the UI state, the view ids that were returned by 40 * the {@link AutofillService autofill service} as both required to trigger a save 41 * and optional that can be saved, and the id of the corresponding {@link 42 * FillRequest}. 43 * <p> 44 * This context allows you to inspect the values for the interesting views 45 * in the context they appeared. Also a reference to the corresponding fill 46 * request is useful to store meta-data in the client state bundle passed 47 * to {@link FillResponse.Builder#setClientState(Bundle)} to avoid interpreting 48 * the UI state again while saving. 49 */ 50public final class FillContext implements Parcelable { 51 private final int mRequestId; 52 private final @NonNull AssistStructure mStructure; 53 54 /** 55 * Lookup table AutofillId->ViewNode to speed up {@link #findViewNodesByAutofillIds} 56 * This is purely a cache and can be deleted at any time 57 */ 58 @Nullable private ArrayMap<AutofillId, AssistStructure.ViewNode> mViewNodeLookupTable; 59 60 61 /** @hide */ 62 public FillContext(int requestId, @NonNull AssistStructure structure) { 63 mRequestId = requestId; 64 mStructure = structure; 65 } 66 67 private FillContext(Parcel parcel) { 68 this(parcel.readInt(), parcel.readParcelable(null)); 69 } 70 71 /** 72 * Gets the id of the {@link FillRequest fill request} this context 73 * corresponds to. This is useful to associate your custom client 74 * state with every request to avoid reinterpreting the UI when saving 75 * user data. 76 * 77 * @return The request id. 78 */ 79 public int getRequestId() { 80 return mRequestId; 81 } 82 83 /** 84 * @return The screen content. 85 */ 86 public AssistStructure getStructure() { 87 return mStructure; 88 } 89 90 @Override 91 public String toString() { 92 if (!sDebug) return super.toString(); 93 94 return "FillContext [reqId=" + mRequestId + "]"; 95 } 96 97 @Override 98 public int describeContents() { 99 return 0; 100 } 101 102 @Override 103 public void writeToParcel(Parcel parcel, int flags) { 104 parcel.writeInt(mRequestId); 105 parcel.writeParcelable(mStructure, flags); 106 } 107 108 /** 109 * Finds {@link ViewNode}s that have the requested ids. 110 * 111 * @param ids The ids of the node to find 112 * 113 * @return The nodes indexed in the same way as the ids 114 * 115 * @hide 116 */ 117 @NonNull public ViewNode[] findViewNodesByAutofillIds(@NonNull AutofillId[] ids) { 118 final LinkedList<ViewNode> nodesToProcess = new LinkedList<>(); 119 final ViewNode[] foundNodes = new AssistStructure.ViewNode[ids.length]; 120 121 // Indexes of foundNodes that are not found yet 122 final SparseIntArray missingNodeIndexes = new SparseIntArray(ids.length); 123 124 for (int i = 0; i < ids.length; i++) { 125 if (mViewNodeLookupTable != null) { 126 int lookupTableIndex = mViewNodeLookupTable.indexOfKey(ids[i]); 127 128 if (lookupTableIndex >= 0) { 129 foundNodes[i] = mViewNodeLookupTable.valueAt(lookupTableIndex); 130 } else { 131 missingNodeIndexes.put(i, /* ignored */ 0); 132 } 133 } else { 134 missingNodeIndexes.put(i, /* ignored */ 0); 135 } 136 } 137 138 final int numWindowNodes = mStructure.getWindowNodeCount(); 139 for (int i = 0; i < numWindowNodes; i++) { 140 nodesToProcess.add(mStructure.getWindowNodeAt(i).getRootViewNode()); 141 } 142 143 while (missingNodeIndexes.size() > 0 && !nodesToProcess.isEmpty()) { 144 final ViewNode node = nodesToProcess.removeFirst(); 145 146 for (int i = 0; i < missingNodeIndexes.size(); i++) { 147 final int index = missingNodeIndexes.keyAt(i); 148 final AutofillId id = ids[index]; 149 150 if (id.equals(node.getAutofillId())) { 151 foundNodes[index] = node; 152 153 if (mViewNodeLookupTable == null) { 154 mViewNodeLookupTable = new ArrayMap<>(ids.length); 155 } 156 157 mViewNodeLookupTable.put(id, node); 158 159 missingNodeIndexes.removeAt(i); 160 break; 161 } 162 } 163 164 for (int i = 0; i < node.getChildCount(); i++) { 165 nodesToProcess.addLast(node.getChildAt(i)); 166 } 167 } 168 169 // Remember which ids could not be resolved to not search for them again the next time 170 for (int i = 0; i < missingNodeIndexes.size(); i++) { 171 if (mViewNodeLookupTable == null) { 172 mViewNodeLookupTable = new ArrayMap<>(missingNodeIndexes.size()); 173 } 174 175 mViewNodeLookupTable.put(ids[missingNodeIndexes.keyAt(i)], null); 176 } 177 178 return foundNodes; 179 } 180 181 public static final Parcelable.Creator<FillContext> CREATOR = 182 new Parcelable.Creator<FillContext>() { 183 @Override 184 public FillContext createFromParcel(Parcel parcel) { 185 return new FillContext(parcel); 186 } 187 188 @Override 189 public FillContext[] newArray(int size) { 190 return new FillContext[size]; 191 } 192 }; 193} 194