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.content; 17 18 import android.annotation.NonNull; 19 import android.annotation.Nullable; 20 import android.annotation.SuppressLint; 21 import android.annotation.TestApi; 22 import android.app.ActivityThread; 23 import android.os.Parcel; 24 import android.os.Parcelable; 25 import android.os.SystemClock; 26 import android.util.ArrayMap; 27 import android.util.ArraySet; 28 import android.util.Log; 29 import android.view.autofill.AutofillManager; 30 import android.view.autofill.AutofillManager.AutofillClient; 31 32 import java.io.PrintWriter; 33 34 /** 35 * Autofill options for a given package. 36 * 37 * <p>This object is created by the Autofill System Service and passed back to the app when the 38 * application is created. 39 * 40 * @hide 41 */ 42 @TestApi 43 public final class AutofillOptions implements Parcelable { 44 45 private static final String TAG = AutofillOptions.class.getSimpleName(); 46 47 /** 48 * Logging level for {@code logcat} statements. 49 */ 50 public final int loggingLevel; 51 52 /** 53 * Whether compatibility mode is enabled for the package. 54 */ 55 public final boolean compatModeEnabled; 56 57 /** 58 * Whether package is allowlisted for augmented autofill. 59 */ 60 public boolean augmentedAutofillEnabled; 61 62 /** 63 * List of allowlisted activities. 64 */ 65 @Nullable 66 @SuppressLint("NullableCollection") 67 public ArraySet<ComponentName> whitelistedActivitiesForAugmentedAutofill; 68 69 /** 70 * The package disable expiration by autofill service. 71 */ 72 public long appDisabledExpiration; 73 74 /** 75 * The disabled Activities of the package. key is component name string, value is when they 76 * will be enabled. 77 */ 78 @SuppressLint("NullableCollection") 79 @Nullable 80 public ArrayMap<String, Long> disabledActivities; 81 AutofillOptions(int loggingLevel, boolean compatModeEnabled)82 public AutofillOptions(int loggingLevel, boolean compatModeEnabled) { 83 this.loggingLevel = loggingLevel; 84 this.compatModeEnabled = compatModeEnabled; 85 } 86 87 /** 88 * Returns whether activity is allowlisted for augmented autofill. 89 */ isAugmentedAutofillEnabled(@onNull Context context)90 public boolean isAugmentedAutofillEnabled(@NonNull Context context) { 91 if (!augmentedAutofillEnabled) return false; 92 93 final AutofillClient autofillClient = context.getAutofillClient(); 94 if (autofillClient == null) return false; 95 96 final ComponentName component = autofillClient.autofillClientGetComponentName(); 97 return whitelistedActivitiesForAugmentedAutofill == null 98 || whitelistedActivitiesForAugmentedAutofill.contains(component); 99 } 100 101 /** 102 * Returns if autofill is disabled by service to the given activity. 103 * 104 * @hide 105 */ isAutofillDisabledLocked(@onNull ComponentName componentName)106 public boolean isAutofillDisabledLocked(@NonNull ComponentName componentName) { 107 final long elapsedTime = SystemClock.elapsedRealtime(); 108 final String component = componentName.flattenToString(); 109 // Check app first. 110 if (appDisabledExpiration >= elapsedTime) return true; 111 112 // Then check activities. 113 if (disabledActivities != null) { 114 final Long expiration = disabledActivities.get(component); 115 if (expiration != null) { 116 if (expiration >= elapsedTime) return true; 117 disabledActivities.remove(component); 118 } 119 } 120 appDisabledExpiration = 0; 121 return false; 122 } 123 124 /** 125 * @hide 126 */ 127 @TestApi forWhitelistingItself()128 public static AutofillOptions forWhitelistingItself() { 129 final ActivityThread at = ActivityThread.currentActivityThread(); 130 if (at == null) { 131 throw new IllegalStateException("No ActivityThread"); 132 } 133 134 final String packageName = at.getApplication().getPackageName(); 135 136 if (!"android.autofillservice.cts".equals(packageName)) { 137 Log.e(TAG, "forWhitelistingItself(): called by " + packageName); 138 throw new SecurityException("Thou shall not pass!"); 139 } 140 141 final AutofillOptions options = new AutofillOptions( 142 AutofillManager.FLAG_ADD_CLIENT_VERBOSE, /* compatModeAllowed= */ true); 143 options.augmentedAutofillEnabled = true; 144 // Always log, as it's used by test only 145 Log.i(TAG, "forWhitelistingItself(" + packageName + "): " + options); 146 147 return options; 148 } 149 150 @Override toString()151 public String toString() { 152 return "AutofillOptions [loggingLevel=" + loggingLevel + ", compatMode=" + compatModeEnabled 153 + ", augmentedAutofillEnabled=" + augmentedAutofillEnabled 154 + ", appDisabledExpiration=" + appDisabledExpiration + "]"; 155 } 156 157 /** @hide */ dumpShort(@onNull PrintWriter pw)158 public void dumpShort(@NonNull PrintWriter pw) { 159 pw.print("logLvl="); pw.print(loggingLevel); 160 pw.print(", compatMode="); pw.print(compatModeEnabled); 161 pw.print(", augmented="); pw.print(augmentedAutofillEnabled); 162 if (whitelistedActivitiesForAugmentedAutofill != null) { 163 pw.print(", whitelistedActivitiesForAugmentedAutofill="); 164 pw.print(whitelistedActivitiesForAugmentedAutofill); 165 } 166 pw.print(", appDisabledExpiration="); pw.print(appDisabledExpiration); 167 if (disabledActivities != null) { 168 pw.print(", disabledActivities="); 169 pw.print(disabledActivities); 170 } 171 } 172 173 @Override describeContents()174 public int describeContents() { 175 return 0; 176 } 177 178 @Override writeToParcel(Parcel parcel, int flags)179 public void writeToParcel(Parcel parcel, int flags) { 180 parcel.writeInt(loggingLevel); 181 parcel.writeBoolean(compatModeEnabled); 182 parcel.writeBoolean(augmentedAutofillEnabled); 183 parcel.writeArraySet(whitelistedActivitiesForAugmentedAutofill); 184 parcel.writeLong(appDisabledExpiration); 185 final int size = disabledActivities != null ? disabledActivities.size() : 0; 186 parcel.writeInt(size); 187 if (size > 0) { 188 for (int i = 0; i < size; i++) { 189 final String key = disabledActivities.keyAt(i); 190 parcel.writeString(key); 191 parcel.writeLong(disabledActivities.get(key)); 192 } 193 } 194 } 195 196 public static final @android.annotation.NonNull Parcelable.Creator<AutofillOptions> CREATOR = 197 new Parcelable.Creator<AutofillOptions>() { 198 199 @Override 200 public AutofillOptions createFromParcel(Parcel parcel) { 201 final int loggingLevel = parcel.readInt(); 202 final boolean compatMode = parcel.readBoolean(); 203 final AutofillOptions options = new AutofillOptions(loggingLevel, compatMode); 204 options.augmentedAutofillEnabled = parcel.readBoolean(); 205 options.whitelistedActivitiesForAugmentedAutofill = 206 (ArraySet<ComponentName>) parcel.readArraySet(null); 207 options.appDisabledExpiration = parcel.readLong(); 208 final int size = parcel.readInt(); 209 if (size > 0) { 210 options.disabledActivities = new ArrayMap<>(); 211 for (int i = 0; i < size; i++) { 212 options.disabledActivities.put(parcel.readString(), parcel.readLong()); 213 } 214 } 215 return options; 216 } 217 218 @Override 219 public AutofillOptions[] newArray(int size) { 220 return new AutofillOptions[size]; 221 } 222 }; 223 } 224