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.view.contentcapture; 17 18 import android.annotation.IntDef; 19 import android.annotation.NonNull; 20 import android.app.ActivityThread; 21 import android.content.LocusId; 22 import android.os.Parcel; 23 import android.os.Parcelable; 24 import android.util.IntArray; 25 26 import com.android.internal.util.Preconditions; 27 28 import java.lang.annotation.Retention; 29 import java.lang.annotation.RetentionPolicy; 30 import java.util.ArrayList; 31 import java.util.List; 32 import java.util.Objects; 33 34 /** 35 * Class used by apps to request the content capture service to remove data associated with 36 * {@link LocusId LocusIds}. 37 * 38 * <p>An app which has tagged data with a LocusId can therefore delete them later. This is intended 39 * to let apps propagate deletions of user data into the operating system. 40 */ 41 public final class DataRemovalRequest implements Parcelable { 42 43 /** 44 * When set, service should use the {@link LocusId#getId()} as prefix for the data to be 45 * removed. 46 */ 47 public static final int FLAG_IS_PREFIX = 0x1; 48 49 /** @hide */ 50 @IntDef(prefix = { "FLAG" }, flag = true, value = { 51 FLAG_IS_PREFIX 52 }) 53 @Retention(RetentionPolicy.SOURCE) 54 @interface Flags {} 55 56 private final String mPackageName; 57 58 private final boolean mForEverything; 59 private ArrayList<LocusIdRequest> mLocusIdRequests; 60 DataRemovalRequest(@onNull Builder builder)61 private DataRemovalRequest(@NonNull Builder builder) { 62 mPackageName = ActivityThread.currentActivityThread().getApplication().getPackageName(); 63 mForEverything = builder.mForEverything; 64 if (builder.mLocusIds != null) { 65 final int size = builder.mLocusIds.size(); 66 mLocusIdRequests = new ArrayList<>(size); 67 for (int i = 0; i < size; i++) { 68 mLocusIdRequests.add(new LocusIdRequest(builder.mLocusIds.get(i), 69 builder.mFlags.get(i))); 70 } 71 } 72 } 73 DataRemovalRequest(@onNull Parcel parcel)74 private DataRemovalRequest(@NonNull Parcel parcel) { 75 mPackageName = parcel.readString(); 76 mForEverything = parcel.readBoolean(); 77 if (!mForEverything) { 78 final int size = parcel.readInt(); 79 mLocusIdRequests = new ArrayList<>(size); 80 for (int i = 0; i < size; i++) { 81 mLocusIdRequests.add(new LocusIdRequest((LocusId) parcel.readValue(null), 82 parcel.readInt())); 83 } 84 } 85 } 86 87 /** 88 * Gets the name of the app that's making the request. 89 */ 90 @NonNull getPackageName()91 public String getPackageName() { 92 return mPackageName; 93 } 94 95 /** 96 * Checks if app is requesting to remove content capture data associated with its package. 97 */ isForEverything()98 public boolean isForEverything() { 99 return mForEverything; 100 } 101 102 /** 103 * Gets the list of {@code LousId}s the apps is requesting to remove. 104 */ 105 @NonNull getLocusIdRequests()106 public List<LocusIdRequest> getLocusIdRequests() { 107 return mLocusIdRequests; 108 } 109 110 /** 111 * Builder for {@link DataRemovalRequest} objects. 112 */ 113 public static final class Builder { 114 115 private boolean mForEverything; 116 private ArrayList<LocusId> mLocusIds; 117 private IntArray mFlags; 118 119 private boolean mDestroyed; 120 121 /** 122 * Requests servive to remove all content capture data associated with the app's package. 123 * 124 * @return this builder 125 */ 126 @NonNull forEverything()127 public Builder forEverything() { 128 throwIfDestroyed(); 129 Preconditions.checkState(mLocusIds == null, "Already added LocusIds"); 130 131 mForEverything = true; 132 return this; 133 } 134 135 /** 136 * Request service to remove data associated with a given {@link LocusId}. 137 * 138 * @param locusId the {@link LocusId} being requested to be removed. 139 * @param flags either {@link DataRemovalRequest#FLAG_IS_PREFIX} or {@code 0} 140 * 141 * @return this builder 142 */ 143 @NonNull addLocusId(@onNull LocusId locusId, @Flags int flags)144 public Builder addLocusId(@NonNull LocusId locusId, @Flags int flags) { 145 throwIfDestroyed(); 146 Preconditions.checkState(!mForEverything, "Already is for everything"); 147 Objects.requireNonNull(locusId); 148 // felipeal: check flags 149 150 if (mLocusIds == null) { 151 mLocusIds = new ArrayList<>(); 152 mFlags = new IntArray(); 153 } 154 155 mLocusIds.add(locusId); 156 mFlags.add(flags); 157 return this; 158 } 159 160 /** 161 * Builds the {@link DataRemovalRequest}. 162 */ 163 @NonNull build()164 public DataRemovalRequest build() { 165 throwIfDestroyed(); 166 167 Preconditions.checkState(mForEverything || mLocusIds != null, 168 "must call either #forEverything() or add one #addLocusId()"); 169 170 mDestroyed = true; 171 return new DataRemovalRequest(this); 172 } 173 throwIfDestroyed()174 private void throwIfDestroyed() { 175 Preconditions.checkState(!mDestroyed, "Already destroyed!"); 176 } 177 } 178 179 @Override describeContents()180 public int describeContents() { 181 return 0; 182 } 183 184 @Override writeToParcel(Parcel parcel, int flags)185 public void writeToParcel(Parcel parcel, int flags) { 186 parcel.writeString(mPackageName); 187 parcel.writeBoolean(mForEverything); 188 if (!mForEverything) { 189 final int size = mLocusIdRequests.size(); 190 parcel.writeInt(size); 191 for (int i = 0; i < size; i++) { 192 final LocusIdRequest request = mLocusIdRequests.get(i); 193 parcel.writeValue(request.getLocusId()); 194 parcel.writeInt(request.getFlags()); 195 } 196 } 197 } 198 199 public static final @android.annotation.NonNull Parcelable.Creator<DataRemovalRequest> CREATOR = 200 new Parcelable.Creator<DataRemovalRequest>() { 201 202 @Override 203 @NonNull 204 public DataRemovalRequest createFromParcel(Parcel parcel) { 205 return new DataRemovalRequest(parcel); 206 } 207 208 @Override 209 @NonNull 210 public DataRemovalRequest[] newArray(int size) { 211 return new DataRemovalRequest[size]; 212 } 213 }; 214 215 /** 216 * Representation of a request to remove data associated with a {@link LocusId}. 217 */ 218 public final class LocusIdRequest { 219 private final @NonNull LocusId mLocusId; 220 private final @Flags int mFlags; 221 LocusIdRequest(@onNull LocusId locusId, @Flags int flags)222 private LocusIdRequest(@NonNull LocusId locusId, @Flags int flags) { 223 this.mLocusId = locusId; 224 this.mFlags = flags; 225 } 226 227 /** 228 * Gets the {@code LocusId} per se. 229 */ 230 @NonNull getLocusId()231 public LocusId getLocusId() { 232 return mLocusId; 233 } 234 235 /** 236 * Gets the flags associates with request. 237 * 238 * @return either {@link DataRemovalRequest#FLAG_IS_PREFIX} or {@code 0}. 239 */ 240 @NonNull getFlags()241 public @Flags int getFlags() { 242 return mFlags; 243 } 244 } 245 } 246