• 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.TestApi;
21 import android.app.ActivityThread;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 import android.util.ArraySet;
25 import android.util.Log;
26 import android.view.contentcapture.ContentCaptureManager;
27 import android.view.contentcapture.ContentCaptureManager.ContentCaptureClient;
28 
29 import com.android.internal.annotations.VisibleForTesting;
30 
31 import 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
42 public 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 
78     /**
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 
84     /**
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      */
ContentCaptureOptions(int loggingLevel)88     public ContentCaptureOptions(int loggingLevel) {
89         this(/* lite= */ true, loggingLevel, /* maxBufferSize= */ 0,
90                 /* idleFlushingFrequencyMs= */ 0, /* textChangeFlushingFrequencyMs= */ 0,
91                 /* logHistorySize= */ 0, /* whitelistedComponents= */ null);
92     }
93 
94     /**
95      * Default constructor.
96      */
ContentCaptureOptions(int loggingLevel, int maxBufferSize, int idleFlushingFrequencyMs, int textChangeFlushingFrequencyMs, int logHistorySize, @Nullable ArraySet<ComponentName> whitelistedComponents)97     public ContentCaptureOptions(int loggingLevel, int maxBufferSize, int idleFlushingFrequencyMs,
98             int textChangeFlushingFrequencyMs, int logHistorySize,
99             @Nullable ArraySet<ComponentName> whitelistedComponents) {
100         this(/* lite= */ false, loggingLevel, maxBufferSize, idleFlushingFrequencyMs,
101                 textChangeFlushingFrequencyMs, logHistorySize, whitelistedComponents);
102     }
103 
104     /** @hide */
105     @VisibleForTesting
ContentCaptureOptions(@ullable ArraySet<ComponentName> whitelistedComponents)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 
ContentCaptureOptions(boolean lite, int loggingLevel, int maxBufferSize, int idleFlushingFrequencyMs, int textChangeFlushingFrequencyMs, int logHistorySize, @Nullable ArraySet<ComponentName> whitelistedComponents)114     private ContentCaptureOptions(boolean lite, int loggingLevel, int maxBufferSize,
115             int idleFlushingFrequencyMs, int textChangeFlushingFrequencyMs, int logHistorySize,
116             @Nullable ArraySet<ComponentName> whitelistedComponents) {
117         this.lite = lite;
118         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 
forWhitelistingItself()126     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 
139         final ContentCaptureOptions options =
140                 new ContentCaptureOptions(/* whitelistedComponents= */ null);
141         // Always log, as it's used by test only
142         Log.i(TAG, "forWhitelistingItself(" + packageName + "): " + options);
143 
144         return options;
145     }
146 
147     /** @hide */
148     @VisibleForTesting
isWhitelisted(@onNull Context context)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 
160     @Override
toString()161     public String toString() {
162         if (lite) {
163             return "ContentCaptureOptions [loggingLevel=" + loggingLevel + " (lite)]";
164         }
165         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();
175     }
176 
177     /** @hide */
dumpShort(@onNull PrintWriter pw)178     public void dumpShort(@NonNull PrintWriter pw) {
179         pw.print("logLvl="); pw.print(loggingLevel);
180         if (lite) {
181             pw.print(", lite");
182             return;
183         }
184         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
describeContents()194     public int describeContents() {
195         return 0;
196     }
197 
198     @Override
writeToParcel(Parcel parcel, int flags)199     public void writeToParcel(Parcel parcel, int flags) {
200         parcel.writeBoolean(lite);
201         parcel.writeInt(loggingLevel);
202         if (lite) return;
203 
204         parcel.writeInt(maxBufferSize);
205         parcel.writeInt(idleFlushingFrequencyMs);
206         parcel.writeInt(textChangeFlushingFrequencyMs);
207         parcel.writeInt(logHistorySize);
208         parcel.writeArraySet(whitelistedComponents);
209     }
210 
211     public static final @android.annotation.NonNull Parcelable.Creator<ContentCaptureOptions> CREATOR =
212             new Parcelable.Creator<ContentCaptureOptions>() {
213 
214                 @Override
215                 public ContentCaptureOptions createFromParcel(Parcel parcel) {
216                     final boolean lite = parcel.readBoolean();
217                     final int loggingLevel = parcel.readInt();
218                     if (lite) {
219                         return new ContentCaptureOptions(loggingLevel);
220                     }
221                     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                 }
237     };
238 }
239