blob: cb2142c356b264ebdb503347a91617ede60ef6d6 [file] [log] [blame]
Felipe Leme326f15a2019-02-19 09:42:24 -08001/*
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 */
16package android.content;
17
18import android.annotation.NonNull;
19import android.annotation.Nullable;
20import android.annotation.TestApi;
21import android.app.ActivityThread;
22import android.os.Parcel;
23import android.os.Parcelable;
24import android.util.ArraySet;
25import android.util.Log;
26import android.view.contentcapture.ContentCaptureManager;
Felipe Leme41e9eb02019-04-17 13:57:59 -070027import android.view.contentcapture.ContentCaptureManager.ContentCaptureClient;
28
29import com.android.internal.annotations.VisibleForTesting;
Felipe Leme326f15a2019-02-19 09:42:24 -080030
31import java.io.PrintWriter;
32
33/**
34 * Content capture options for a given package.
35 *
36 * <p>This object is created by the Content Capture System Service and passed back to the app when
37 * the application is created.
38 *
39 * @hide
40 */
41@TestApi
42public final class ContentCaptureOptions implements Parcelable {
43
44 private static final String TAG = ContentCaptureOptions.class.getSimpleName();
45
46 /**
47 * Logging level for {@code logcat} statements.
48 */
49 public final int loggingLevel;
50
51 /**
52 * Maximum number of events that are buffered before sent to the app.
53 */
54 public final int maxBufferSize;
55
56 /**
57 * Frequency the buffer is flushed if idle.
58 */
59 public final int idleFlushingFrequencyMs;
60
61 /**
62 * Frequency the buffer is flushed if last event is a text change.
63 */
64 public final int textChangeFlushingFrequencyMs;
65
66 /**
67 * Size of events that are logging on {@code dump}.
68 */
69 public final int logHistorySize;
70
71 /**
72 * List of activities explicitly whitelisted for content capture (or {@code null} if whitelisted
73 * for all acitivites in the package).
74 */
75 @Nullable
76 public final ArraySet<ComponentName> whitelistedComponents;
77
Felipe Leme5001b3b2019-03-20 18:25:28 -070078 /**
79 * Used to enable just a small set of APIs so it can used by activities belonging to the
80 * content capture service APK.
81 */
82 public final boolean lite;
83
Felipe Leme41e9eb02019-04-17 13:57:59 -070084 /**
85 * Constructor for "lite" objects that are just used to enable a {@link ContentCaptureManager}
86 * for contexts belonging to the content capture service app.
87 */
Felipe Leme5001b3b2019-03-20 18:25:28 -070088 public ContentCaptureOptions(int loggingLevel) {
89 this(/* lite= */ true, loggingLevel, /* maxBufferSize= */ 0,
90 /* idleFlushingFrequencyMs= */ 0, /* textChangeFlushingFrequencyMs= */ 0,
91 /* logHistorySize= */ 0, /* whitelistedComponents= */ null);
92 }
93
Felipe Leme41e9eb02019-04-17 13:57:59 -070094 /**
95 * Default constructor.
96 */
Felipe Leme326f15a2019-02-19 09:42:24 -080097 public ContentCaptureOptions(int loggingLevel, int maxBufferSize, int idleFlushingFrequencyMs,
98 int textChangeFlushingFrequencyMs, int logHistorySize,
99 @Nullable ArraySet<ComponentName> whitelistedComponents) {
Felipe Leme5001b3b2019-03-20 18:25:28 -0700100 this(/* lite= */ false, loggingLevel, maxBufferSize, idleFlushingFrequencyMs,
101 textChangeFlushingFrequencyMs, logHistorySize, whitelistedComponents);
102 }
103
Felipe Leme41e9eb02019-04-17 13:57:59 -0700104 /** @hide */
105 @VisibleForTesting
106 public ContentCaptureOptions(@Nullable ArraySet<ComponentName> whitelistedComponents) {
107 this(ContentCaptureManager.LOGGING_LEVEL_VERBOSE,
108 ContentCaptureManager.DEFAULT_MAX_BUFFER_SIZE,
109 ContentCaptureManager.DEFAULT_IDLE_FLUSHING_FREQUENCY_MS,
110 ContentCaptureManager.DEFAULT_TEXT_CHANGE_FLUSHING_FREQUENCY_MS,
111 ContentCaptureManager.DEFAULT_LOG_HISTORY_SIZE, whitelistedComponents);
112 }
113
Felipe Leme5001b3b2019-03-20 18:25:28 -0700114 private ContentCaptureOptions(boolean lite, int loggingLevel, int maxBufferSize,
115 int idleFlushingFrequencyMs, int textChangeFlushingFrequencyMs, int logHistorySize,
116 @Nullable ArraySet<ComponentName> whitelistedComponents) {
117 this.lite = lite;
Felipe Leme326f15a2019-02-19 09:42:24 -0800118 this.loggingLevel = loggingLevel;
119 this.maxBufferSize = maxBufferSize;
120 this.idleFlushingFrequencyMs = idleFlushingFrequencyMs;
121 this.textChangeFlushingFrequencyMs = textChangeFlushingFrequencyMs;
122 this.logHistorySize = logHistorySize;
123 this.whitelistedComponents = whitelistedComponents;
124 }
125
Felipe Leme326f15a2019-02-19 09:42:24 -0800126 public static ContentCaptureOptions forWhitelistingItself() {
127 final ActivityThread at = ActivityThread.currentActivityThread();
128 if (at == null) {
129 throw new IllegalStateException("No ActivityThread");
130 }
131
132 final String packageName = at.getApplication().getPackageName();
133
134 if (!"android.contentcaptureservice.cts".equals(packageName)) {
135 Log.e(TAG, "forWhitelistingItself(): called by " + packageName);
136 throw new SecurityException("Thou shall not pass!");
137 }
138
Felipe Leme41e9eb02019-04-17 13:57:59 -0700139 final ContentCaptureOptions options =
140 new ContentCaptureOptions(/* whitelistedComponents= */ null);
Felipe Leme326f15a2019-02-19 09:42:24 -0800141 // Always log, as it's used by test only
142 Log.i(TAG, "forWhitelistingItself(" + packageName + "): " + options);
143
144 return options;
145 }
146
Felipe Leme41e9eb02019-04-17 13:57:59 -0700147 /** @hide */
148 @VisibleForTesting
149 public boolean isWhitelisted(@NonNull Context context) {
150 if (whitelistedComponents == null) return true; // whole package is whitelisted
151 final ContentCaptureClient client = context.getContentCaptureClient();
152 if (client == null) {
153 // Shouldn't happen, but it doesn't hurt to check...
154 Log.w(TAG, "isWhitelisted(): no ContentCaptureClient on " + context);
155 return false;
156 }
157 return whitelistedComponents.contains(client.contentCaptureClientGetComponentName());
158 }
159
Felipe Leme326f15a2019-02-19 09:42:24 -0800160 @Override
161 public String toString() {
Felipe Leme5001b3b2019-03-20 18:25:28 -0700162 if (lite) {
Felipe Lemea8d33c22019-03-25 16:36:09 -0700163 return "ContentCaptureOptions [loggingLevel=" + loggingLevel + " (lite)]";
Felipe Leme5001b3b2019-03-20 18:25:28 -0700164 }
Felipe Lemea8d33c22019-03-25 16:36:09 -0700165 final StringBuilder string = new StringBuilder("ContentCaptureOptions [");
166 string.append("loggingLevel=").append(loggingLevel)
167 .append(", maxBufferSize=").append(maxBufferSize)
168 .append(", idleFlushingFrequencyMs=").append(idleFlushingFrequencyMs)
169 .append(", textChangeFlushingFrequencyMs=").append(textChangeFlushingFrequencyMs)
170 .append(", logHistorySize=").append(logHistorySize);
171 if (whitelistedComponents != null) {
172 string.append(", whitelisted=").append(whitelistedComponents);
173 }
174 return string.append(']').toString();
Felipe Leme326f15a2019-02-19 09:42:24 -0800175 }
176
177 /** @hide */
178 public void dumpShort(@NonNull PrintWriter pw) {
179 pw.print("logLvl="); pw.print(loggingLevel);
Felipe Leme5001b3b2019-03-20 18:25:28 -0700180 if (lite) {
181 pw.print(", lite");
182 return;
183 }
Felipe Leme326f15a2019-02-19 09:42:24 -0800184 pw.print(", bufferSize="); pw.print(maxBufferSize);
185 pw.print(", idle="); pw.print(idleFlushingFrequencyMs);
186 pw.print(", textIdle="); pw.print(textChangeFlushingFrequencyMs);
187 pw.print(", logSize="); pw.print(logHistorySize);
188 if (whitelistedComponents != null) {
189 pw.print(", whitelisted="); pw.print(whitelistedComponents);
190 }
191 }
192
193 @Override
194 public int describeContents() {
195 return 0;
196 }
197
198 @Override
199 public void writeToParcel(Parcel parcel, int flags) {
Felipe Leme5001b3b2019-03-20 18:25:28 -0700200 parcel.writeBoolean(lite);
Felipe Leme326f15a2019-02-19 09:42:24 -0800201 parcel.writeInt(loggingLevel);
Felipe Leme5001b3b2019-03-20 18:25:28 -0700202 if (lite) return;
203
Felipe Leme326f15a2019-02-19 09:42:24 -0800204 parcel.writeInt(maxBufferSize);
205 parcel.writeInt(idleFlushingFrequencyMs);
206 parcel.writeInt(textChangeFlushingFrequencyMs);
207 parcel.writeInt(logHistorySize);
208 parcel.writeArraySet(whitelistedComponents);
209 }
210
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700211 public static final @android.annotation.NonNull Parcelable.Creator<ContentCaptureOptions> CREATOR =
Felipe Leme326f15a2019-02-19 09:42:24 -0800212 new Parcelable.Creator<ContentCaptureOptions>() {
213
214 @Override
215 public ContentCaptureOptions createFromParcel(Parcel parcel) {
Felipe Leme5001b3b2019-03-20 18:25:28 -0700216 final boolean lite = parcel.readBoolean();
Felipe Leme326f15a2019-02-19 09:42:24 -0800217 final int loggingLevel = parcel.readInt();
Felipe Leme5001b3b2019-03-20 18:25:28 -0700218 if (lite) {
219 return new ContentCaptureOptions(loggingLevel);
220 }
Felipe Leme326f15a2019-02-19 09:42:24 -0800221 final int maxBufferSize = parcel.readInt();
222 final int idleFlushingFrequencyMs = parcel.readInt();
223 final int textChangeFlushingFrequencyMs = parcel.readInt();
224 final int logHistorySize = parcel.readInt();
225 @SuppressWarnings("unchecked")
226 final ArraySet<ComponentName> whitelistedComponents =
227 (ArraySet<ComponentName>) parcel.readArraySet(null);
228 return new ContentCaptureOptions(loggingLevel, maxBufferSize,
229 idleFlushingFrequencyMs, textChangeFlushingFrequencyMs, logHistorySize,
230 whitelistedComponents);
231 }
232
233 @Override
234 public ContentCaptureOptions[] newArray(int size) {
235 return new ContentCaptureOptions[size];
236 }
Felipe Leme326f15a2019-02-19 09:42:24 -0800237 };
238}