FieldClassification.java revision 27f4573d136949abeacb00f7246ff9911e9cb105
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.os.Parcel; 23import android.view.autofill.Helper; 24 25import com.android.internal.util.Preconditions; 26 27import java.util.ArrayList; 28import java.util.Collections; 29import java.util.Comparator; 30import java.util.List; 31 32/** 33 * Represents the <a href="AutofillService.html#FieldClassification">field classification</a> 34 * results for a given field. 35 */ 36public final class FieldClassification { 37 38 private final ArrayList<Match> mMatches; 39 40 /** @hide */ 41 public FieldClassification(@NonNull ArrayList<Match> matches) { 42 mMatches = Preconditions.checkNotNull(matches); 43 Collections.sort(mMatches, new Comparator<Match>() { 44 @Override 45 public int compare(Match o1, Match o2) { 46 if (o1.mScore > o2.mScore) return -1; 47 if (o1.mScore < o2.mScore) return 1; 48 return 0; 49 }} 50 ); 51 } 52 53 /** 54 * Gets the {@link Match matches} with the highest {@link Match#getScore() scores} (sorted in 55 * descending order). 56 * 57 * <p><b>Note:</b> There's no guarantee of how many matches will be returned. In fact, 58 * the Android System might return just the top match to minimize the impact of field 59 * classification in the device's health. 60 */ 61 @NonNull 62 public List<Match> getMatches() { 63 return mMatches; 64 } 65 66 @Override 67 public String toString() { 68 if (!sDebug) return super.toString(); 69 70 return "FieldClassification: " + mMatches; 71 } 72 73 private void writeToParcel(Parcel parcel) { 74 parcel.writeInt(mMatches.size()); 75 for (int i = 0; i < mMatches.size(); i++) { 76 mMatches.get(i).writeToParcel(parcel); 77 } 78 } 79 80 private static FieldClassification readFromParcel(Parcel parcel) { 81 final int size = parcel.readInt(); 82 final ArrayList<Match> matches = new ArrayList<>(); 83 for (int i = 0; i < size; i++) { 84 matches.add(i, Match.readFromParcel(parcel)); 85 } 86 87 return new FieldClassification(matches); 88 } 89 90 static FieldClassification[] readArrayFromParcel(Parcel parcel) { 91 final int length = parcel.readInt(); 92 final FieldClassification[] fcs = new FieldClassification[length]; 93 for (int i = 0; i < length; i++) { 94 fcs[i] = readFromParcel(parcel); 95 } 96 return fcs; 97 } 98 99 static void writeArrayToParcel(@NonNull Parcel parcel, @NonNull FieldClassification[] fcs) { 100 parcel.writeInt(fcs.length); 101 for (int i = 0; i < fcs.length; i++) { 102 fcs[i].writeToParcel(parcel); 103 } 104 } 105 106 /** 107 * Represents the score of a {@link UserData} entry for the field. 108 * 109 * <p>The score is calculated by the given {@link #getAlgorithm() algorithm} and 110 * the entry is identified by {@link #getRemoteId()}. 111 */ 112 public static final class Match { 113 114 private final String mRemoteId; 115 private final float mScore; 116 private final String mAlgorithm; 117 118 /** @hide */ 119 public Match(String remoteId, float score, String algorithm) { 120 mRemoteId = Preconditions.checkNotNull(remoteId); 121 mScore = score; 122 mAlgorithm = algorithm; 123 } 124 125 /** 126 * Gets the remote id of the {@link UserData} entry. 127 */ 128 @NonNull 129 public String getRemoteId() { 130 return mRemoteId; 131 } 132 133 /** 134 * Gets a classification score for the value of this field compared to the value of the 135 * {@link UserData} entry. 136 * 137 * <p>The score is based in a comparison of the field value and the user data entry, and it 138 * ranges from {@code 0.0F} to {@code 1.0F}: 139 * <ul> 140 * <li>{@code 1.0F} represents a full match ({@code 100%}). 141 * <li>{@code 0.0F} represents a full mismatch ({@code 0%}). 142 * <li>Any other value is a partial match. 143 * </ul> 144 * 145 * <p>How the score is calculated depends on the 146 * {@link UserData.Builder#setFieldClassificationAlgorithm(String, android.os.Bundle) 147 * algorithm} used. 148 */ 149 public float getScore() { 150 return mScore; 151 } 152 153 /** 154 * Gets the algorithm used to calculate this score. 155 * 156 * <p>Typically, this is either the algorithm set by 157 * {@link UserData.Builder#setFieldClassificationAlgorithm(String, android.os.Bundle)}, 158 * or the 159 * {@link android.view.autofill.AutofillManager#getDefaultFieldClassificationAlgorithm()}. 160 */ 161 @NonNull 162 public String getAlgorithm() { 163 return mAlgorithm; 164 } 165 166 @Override 167 public String toString() { 168 if (!sDebug) return super.toString(); 169 170 final StringBuilder string = new StringBuilder("Match: remoteId="); 171 Helper.appendRedacted(string, mRemoteId); 172 return string.append(", score=").append(mScore) 173 .append(", algorithm=").append(mAlgorithm) 174 .toString(); 175 } 176 177 private void writeToParcel(@NonNull Parcel parcel) { 178 parcel.writeString(mRemoteId); 179 parcel.writeFloat(mScore); 180 parcel.writeString(mAlgorithm); 181 } 182 183 private static Match readFromParcel(@NonNull Parcel parcel) { 184 return new Match(parcel.readString(), parcel.readFloat(), parcel.readString()); 185 } 186 } 187} 188