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