• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.util.ArraySet;
26 import android.util.Log;
27 import android.view.contentcapture.ContentCaptureManager;
28 import android.view.contentcapture.ContentCaptureManager.ContentCaptureClient;
29 
30 import com.android.internal.annotations.VisibleForTesting;
31 
32 import java.io.PrintWriter;
33 
34 /**
35  * Content capture options for a given package.
36  *
37  * <p>This object is created by the Content Capture System Service and passed back to the app when
38  * the application is created.
39  *
40  * @hide
41  */
42 @TestApi
43 public final class ContentCaptureOptions implements Parcelable {
44 
45     private static final String TAG = ContentCaptureOptions.class.getSimpleName();
46 
47     /**
48      * Logging level for {@code logcat} statements.
49      */
50     public final int loggingLevel;
51 
52     /**
53      * Maximum number of events that are buffered before sent to the app.
54      */
55     public final int maxBufferSize;
56 
57     /**
58      * Frequency the buffer is flushed if idle.
59      */
60     public final int idleFlushingFrequencyMs;
61 
62     /**
63      * Frequency the buffer is flushed if last event is a text change.
64      */
65     public final int textChangeFlushingFrequencyMs;
66 
67     /**
68      * Size of events that are logging on {@code dump}.
69      */
70     public final int logHistorySize;
71 
72     /**
73      * Disable flush when receiving a VIEW_TREE_APPEARING event.
74      * @hide
75      */
76     public final boolean disableFlushForViewTreeAppearing;
77 
78     /**
79      * List of activities explicitly allowlisted for content capture (or {@code null} if allowlisted
80      * for all acitivites in the package).
81      */
82     @Nullable
83     @SuppressLint("NullableCollection")
84     public final ArraySet<ComponentName> whitelistedComponents;
85 
86     /**
87      * Used to enable just a small set of APIs so it can used by activities belonging to the
88      * content capture service APK.
89      */
90     public final boolean lite;
91 
92     /**
93      * Constructor for "lite" objects that are just used to enable a {@link ContentCaptureManager}
94      * for contexts belonging to the content capture service app.
95      */
ContentCaptureOptions(int loggingLevel)96     public ContentCaptureOptions(int loggingLevel) {
97         this(/* lite= */ true, loggingLevel, /* maxBufferSize= */ 0,
98                 /* idleFlushingFrequencyMs= */ 0, /* textChangeFlushingFrequencyMs= */ 0,
99                 /* logHistorySize= */ 0, /* disableFlushForViewTreeAppearing= */ false,
100                 /* whitelistedComponents= */ null);
101     }
102 
103     /**
104      * Default constructor.
105      */
ContentCaptureOptions(int loggingLevel, int maxBufferSize, int idleFlushingFrequencyMs, int textChangeFlushingFrequencyMs, int logHistorySize, @SuppressLint({"ConcreteCollection", "NullableCollection"}) @Nullable ArraySet<ComponentName> whitelistedComponents)106     public ContentCaptureOptions(int loggingLevel, int maxBufferSize, int idleFlushingFrequencyMs,
107             int textChangeFlushingFrequencyMs, int logHistorySize,
108             @SuppressLint({"ConcreteCollection", "NullableCollection"})
109             @Nullable ArraySet<ComponentName> whitelistedComponents) {
110         this(/* lite= */ false, loggingLevel, maxBufferSize, idleFlushingFrequencyMs,
111                 textChangeFlushingFrequencyMs, logHistorySize,
112                 ContentCaptureManager.DEFAULT_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING,
113                 whitelistedComponents);
114     }
115 
116     /** @hide */
ContentCaptureOptions(int loggingLevel, int maxBufferSize, int idleFlushingFrequencyMs, int textChangeFlushingFrequencyMs, int logHistorySize, boolean disableFlushForViewTreeAppearing, @SuppressLint({"ConcreteCollection", "NullableCollection"}) @Nullable ArraySet<ComponentName> whitelistedComponents)117     public ContentCaptureOptions(int loggingLevel, int maxBufferSize, int idleFlushingFrequencyMs,
118             int textChangeFlushingFrequencyMs, int logHistorySize,
119             boolean disableFlushForViewTreeAppearing,
120             @SuppressLint({"ConcreteCollection", "NullableCollection"})
121             @Nullable ArraySet<ComponentName> whitelistedComponents) {
122         this(/* lite= */ false, loggingLevel, maxBufferSize, idleFlushingFrequencyMs,
123                 textChangeFlushingFrequencyMs, logHistorySize, disableFlushForViewTreeAppearing,
124                 whitelistedComponents);
125     }
126 
127     /** @hide */
128     @VisibleForTesting
ContentCaptureOptions(@ullable ArraySet<ComponentName> whitelistedComponents)129     public ContentCaptureOptions(@Nullable ArraySet<ComponentName> whitelistedComponents) {
130         this(ContentCaptureManager.LOGGING_LEVEL_VERBOSE,
131                 ContentCaptureManager.DEFAULT_MAX_BUFFER_SIZE,
132                 ContentCaptureManager.DEFAULT_IDLE_FLUSHING_FREQUENCY_MS,
133                 ContentCaptureManager.DEFAULT_TEXT_CHANGE_FLUSHING_FREQUENCY_MS,
134                 ContentCaptureManager.DEFAULT_LOG_HISTORY_SIZE,
135                 ContentCaptureManager.DEFAULT_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING,
136                 whitelistedComponents);
137     }
138 
ContentCaptureOptions(boolean lite, int loggingLevel, int maxBufferSize, int idleFlushingFrequencyMs, int textChangeFlushingFrequencyMs, int logHistorySize, boolean disableFlushForViewTreeAppearing, @Nullable ArraySet<ComponentName> whitelistedComponents)139     private ContentCaptureOptions(boolean lite, int loggingLevel, int maxBufferSize,
140             int idleFlushingFrequencyMs, int textChangeFlushingFrequencyMs, int logHistorySize,
141             boolean disableFlushForViewTreeAppearing,
142             @Nullable ArraySet<ComponentName> whitelistedComponents) {
143         this.lite = lite;
144         this.loggingLevel = loggingLevel;
145         this.maxBufferSize = maxBufferSize;
146         this.idleFlushingFrequencyMs = idleFlushingFrequencyMs;
147         this.textChangeFlushingFrequencyMs = textChangeFlushingFrequencyMs;
148         this.logHistorySize = logHistorySize;
149         this.disableFlushForViewTreeAppearing = disableFlushForViewTreeAppearing;
150         this.whitelistedComponents = whitelistedComponents;
151     }
152 
forWhitelistingItself()153     public static ContentCaptureOptions forWhitelistingItself() {
154         final ActivityThread at = ActivityThread.currentActivityThread();
155         if (at == null) {
156             throw new IllegalStateException("No ActivityThread");
157         }
158 
159         final String packageName = at.getApplication().getPackageName();
160 
161         if (!"android.contentcaptureservice.cts".equals(packageName)
162                 && !"android.translation.cts".equals(packageName)) {
163             Log.e(TAG, "forWhitelistingItself(): called by " + packageName);
164             throw new SecurityException("Thou shall not pass!");
165         }
166 
167         final ContentCaptureOptions options =
168                 new ContentCaptureOptions(/* whitelistedComponents= */ null);
169         // Always log, as it's used by test only
170         Log.i(TAG, "forWhitelistingItself(" + packageName + "): " + options);
171 
172         return options;
173     }
174 
175     /** @hide */
176     @VisibleForTesting
isWhitelisted(@onNull Context context)177     public boolean isWhitelisted(@NonNull Context context) {
178         if (whitelistedComponents == null) return true; // whole package is allowlisted
179         final ContentCaptureClient client = context.getContentCaptureClient();
180         if (client == null) {
181             // Shouldn't happen, but it doesn't hurt to check...
182             Log.w(TAG, "isWhitelisted(): no ContentCaptureClient on " + context);
183             return false;
184         }
185         return whitelistedComponents.contains(client.contentCaptureClientGetComponentName());
186     }
187 
188     @Override
toString()189     public String toString() {
190         if (lite) {
191             return "ContentCaptureOptions [loggingLevel=" + loggingLevel + " (lite)]";
192         }
193         final StringBuilder string = new StringBuilder("ContentCaptureOptions [");
194         string.append("loggingLevel=").append(loggingLevel)
195             .append(", maxBufferSize=").append(maxBufferSize)
196             .append(", idleFlushingFrequencyMs=").append(idleFlushingFrequencyMs)
197             .append(", textChangeFlushingFrequencyMs=").append(textChangeFlushingFrequencyMs)
198             .append(", logHistorySize=").append(logHistorySize)
199             .append(", disableFlushForViewTreeAppearing=").append(disableFlushForViewTreeAppearing);
200         if (whitelistedComponents != null) {
201             string.append(", whitelisted=").append(whitelistedComponents);
202         }
203         return string.append(']').toString();
204     }
205 
206     /** @hide */
dumpShort(@onNull PrintWriter pw)207     public void dumpShort(@NonNull PrintWriter pw) {
208         pw.print("logLvl="); pw.print(loggingLevel);
209         if (lite) {
210             pw.print(", lite");
211             return;
212         }
213         pw.print(", bufferSize="); pw.print(maxBufferSize);
214         pw.print(", idle="); pw.print(idleFlushingFrequencyMs);
215         pw.print(", textIdle="); pw.print(textChangeFlushingFrequencyMs);
216         pw.print(", logSize="); pw.print(logHistorySize);
217         pw.print(", disableFlushForViewTreeAppearing="); pw.print(disableFlushForViewTreeAppearing);
218         if (whitelistedComponents != null) {
219             pw.print(", whitelisted="); pw.print(whitelistedComponents);
220         }
221     }
222 
223     @Override
describeContents()224     public int describeContents() {
225         return 0;
226     }
227 
228     @Override
writeToParcel(Parcel parcel, int flags)229     public void writeToParcel(Parcel parcel, int flags) {
230         parcel.writeBoolean(lite);
231         parcel.writeInt(loggingLevel);
232         if (lite) return;
233 
234         parcel.writeInt(maxBufferSize);
235         parcel.writeInt(idleFlushingFrequencyMs);
236         parcel.writeInt(textChangeFlushingFrequencyMs);
237         parcel.writeInt(logHistorySize);
238         parcel.writeBoolean(disableFlushForViewTreeAppearing);
239         parcel.writeArraySet(whitelistedComponents);
240     }
241 
242     public static final @android.annotation.NonNull Parcelable.Creator<ContentCaptureOptions> CREATOR =
243             new Parcelable.Creator<ContentCaptureOptions>() {
244 
245                 @Override
246                 public ContentCaptureOptions createFromParcel(Parcel parcel) {
247                     final boolean lite = parcel.readBoolean();
248                     final int loggingLevel = parcel.readInt();
249                     if (lite) {
250                         return new ContentCaptureOptions(loggingLevel);
251                     }
252                     final int maxBufferSize = parcel.readInt();
253                     final int idleFlushingFrequencyMs = parcel.readInt();
254                     final int textChangeFlushingFrequencyMs = parcel.readInt();
255                     final int logHistorySize = parcel.readInt();
256                     final boolean disableFlushForViewTreeAppearing = parcel.readBoolean();
257                     @SuppressWarnings("unchecked")
258                     final ArraySet<ComponentName> whitelistedComponents =
259                             (ArraySet<ComponentName>) parcel.readArraySet(null);
260                     return new ContentCaptureOptions(loggingLevel, maxBufferSize,
261                             idleFlushingFrequencyMs, textChangeFlushingFrequencyMs, logHistorySize,
262                             disableFlushForViewTreeAppearing, whitelistedComponents);
263                 }
264 
265                 @Override
266                 public ContentCaptureOptions[] newArray(int size) {
267                     return new ContentCaptureOptions[size];
268                 }
269     };
270 }
271