Home | History | Annotate | Download | only in autofill
      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 android.service.autofill;
     18 
     19 import static android.view.autofill.Helper.sDebug;
     20 
     21 import android.annotation.NonNull;
     22 import android.os.Parcel;
     23 import android.view.autofill.Helper;
     24 
     25 import com.android.internal.util.Preconditions;
     26 
     27 import java.util.ArrayList;
     28 import java.util.Collections;
     29 import java.util.Comparator;
     30 import java.util.List;
     31 
     32 /**
     33  * Represents the <a href="AutofillService.html#FieldClassification">field classification</a>
     34  * results for a given field.
     35  */
     36 public 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     public static final class Match {
    110 
    111         private final String mCategoryId;
    112         private final float mScore;
    113 
    114         /** @hide */
    115         public Match(String categoryId, float score) {
    116             mCategoryId = Preconditions.checkNotNull(categoryId);
    117             mScore = score;
    118         }
    119 
    120         /**
    121          * Gets the category id of the {@link UserData} entry.
    122          */
    123         @NonNull
    124         public String getCategoryId() {
    125             return mCategoryId;
    126         }
    127 
    128         /**
    129          * Gets a classification score for the value of this field compared to the value of the
    130          * {@link UserData} entry.
    131          *
    132          * <p>The score is based in a comparison of the field value and the user data entry, and it
    133          * ranges from {@code 0.0F} to {@code 1.0F}:
    134          * <ul>
    135          *   <li>{@code 1.0F} represents a full match ({@code 100%}).
    136          *   <li>{@code 0.0F} represents a full mismatch ({@code 0%}).
    137          *   <li>Any other value is a partial match.
    138          * </ul>
    139          *
    140          * <p>How the score is calculated depends on the
    141          * {@link UserData.Builder#setFieldClassificationAlgorithm(String, android.os.Bundle)
    142          * algorithm} used.
    143          */
    144         public float getScore() {
    145             return mScore;
    146         }
    147 
    148         @Override
    149         public String toString() {
    150             if (!sDebug) return super.toString();
    151 
    152             final StringBuilder string = new StringBuilder("Match: categoryId=");
    153             Helper.appendRedacted(string, mCategoryId);
    154             return string.append(", score=").append(mScore).toString();
    155         }
    156 
    157         private void writeToParcel(@NonNull Parcel parcel) {
    158             parcel.writeString(mCategoryId);
    159             parcel.writeFloat(mScore);
    160         }
    161 
    162         private static Match readFromParcel(@NonNull Parcel parcel) {
    163             return new Match(parcel.readString(), parcel.readFloat());
    164         }
    165     }
    166 }
    167