blob: 983079073d02f67e2236ea3253aa1940a1807b45 [file] [log] [blame]
Felipe Leme1dfa9a02018-10-17 17:24:37 -07001/*
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 */
Felipe Leme749b8892018-12-03 16:30:30 -080016package android.view.contentcapture;
Felipe Leme1dfa9a02018-10-17 17:24:37 -070017
18import android.annotation.NonNull;
19import android.annotation.Nullable;
Felipe Lemee348dc32018-11-05 12:35:29 -080020import android.annotation.SystemService;
Felipe Leme87a9dc92018-12-18 14:28:07 -080021import android.annotation.UiThread;
Felipe Leme1dfa9a02018-10-17 17:24:37 -070022import android.content.ComponentName;
23import android.content.Context;
Felipe Leme88eae3b2018-11-07 15:11:56 -080024import android.os.Handler;
25import android.os.HandlerThread;
Felipe Lemee348dc32018-11-05 12:35:29 -080026import android.os.IBinder;
Felipe Lemee348dc32018-11-05 12:35:29 -080027import android.util.Log;
Felipe Leme1dfa9a02018-10-17 17:24:37 -070028
29import com.android.internal.util.Preconditions;
30
Felipe Lemee348dc32018-11-05 12:35:29 -080031import java.io.PrintWriter;
Felipe Lemeb18e3172018-11-27 10:33:41 -080032import java.util.concurrent.atomic.AtomicBoolean;
Felipe Leme1dfa9a02018-10-17 17:24:37 -070033
Felipe Lemeb18e3172018-11-27 10:33:41 -080034/*
35 * NOTE: all methods in this class should return right away, or do the real work in a handler
36 * thread.
37 *
38 * Hence, the only field that must be thread-safe is mEnabled, which is called at the beginning
39 * of every method.
40 */
Felipe Lemeecb08be2018-11-27 15:48:47 -080041/**
42 * TODO(b/111276913): add javadocs / implement
43 */
44@SystemService(Context.CONTENT_CAPTURE_MANAGER_SERVICE)
45public final class ContentCaptureManager {
Felipe Leme1dfa9a02018-10-17 17:24:37 -070046
Felipe Leme749b8892018-12-03 16:30:30 -080047 private static final String TAG = ContentCaptureManager.class.getSimpleName();
Felipe Lemee348dc32018-11-05 12:35:29 -080048
Felipe Leme88eae3b2018-11-07 15:11:56 -080049 private static final String BG_THREAD_NAME = "intel_svc_streamer_thread";
50
Felipe Lemeaa5088e2018-12-10 14:53:58 -080051 // TODO(b/121044306): define a way to dynamically set them(for example, using settings?)
52 static final boolean VERBOSE = false;
53 static final boolean DEBUG = true; // STOPSHIP if not set to false
Felipe Leme4017b202018-12-10 12:13:31 -080054
Felipe Lemeb18e3172018-11-27 10:33:41 -080055 @NonNull
56 private final AtomicBoolean mDisabled = new AtomicBoolean();
57
58 @NonNull
Felipe Lemee348dc32018-11-05 12:35:29 -080059 private final Context mContext;
60
61 @Nullable
Felipe Leme749b8892018-12-03 16:30:30 -080062 private final IContentCaptureManager mService;
Felipe Lemee348dc32018-11-05 12:35:29 -080063
Felipe Lemeaa5088e2018-12-10 14:53:58 -080064 // TODO(b/119220549): use UI Thread directly (as calls are one-way) or a shared thread / handler
Felipe Lemeb18e3172018-11-27 10:33:41 -080065 // held at the Application level
Felipe Lemeaa5088e2018-12-10 14:53:58 -080066 @NonNull
Felipe Leme88eae3b2018-11-07 15:11:56 -080067 private final Handler mHandler;
68
Felipe Leme87a9dc92018-12-18 14:28:07 -080069 private MainContentCaptureSession mMainSession;
Felipe Leme4017b202018-12-10 12:13:31 -080070
Felipe Lemee348dc32018-11-05 12:35:29 -080071 /** @hide */
Felipe Leme749b8892018-12-03 16:30:30 -080072 public ContentCaptureManager(@NonNull Context context,
73 @Nullable IContentCaptureManager service) {
Felipe Leme1dfa9a02018-10-17 17:24:37 -070074 mContext = Preconditions.checkNotNull(context, "context cannot be null");
Felipe Lemeb18e3172018-11-27 10:33:41 -080075 if (VERBOSE) {
76 Log.v(TAG, "Constructor for " + context.getPackageName());
77 }
Felipe Lemee348dc32018-11-05 12:35:29 -080078 mService = service;
Felipe Lemeaa5088e2018-12-10 14:53:58 -080079 // TODO(b/119220549): use an existing bg thread instead...
Felipe Leme88eae3b2018-11-07 15:11:56 -080080 final HandlerThread bgThread = new HandlerThread(BG_THREAD_NAME);
81 bgThread.start();
82 mHandler = Handler.createAsync(bgThread.getLooper());
Felipe Lemee348dc32018-11-05 12:35:29 -080083 }
84
Felipe Lemeaa5088e2018-12-10 14:53:58 -080085 @NonNull
86 private static Handler newHandler() {
87 // TODO(b/119220549): use an existing bg thread instead...
88 // TODO(b/119220549): use UI Thread directly (as calls are one-way) or an existing bgThread
89 // or a shared thread / handler held at the Application level
90 final HandlerThread bgThread = new HandlerThread(BG_THREAD_NAME);
91 bgThread.start();
92 return Handler.createAsync(bgThread.getLooper());
Felipe Leme88eae3b2018-11-07 15:11:56 -080093 }
94
Felipe Leme7a534082018-11-05 15:03:04 -080095 /**
Felipe Lemeaa5088e2018-12-10 14:53:58 -080096 * Gets the main session associated with the context.
Felipe Leme88eae3b2018-11-07 15:11:56 -080097 *
Felipe Lemeaa5088e2018-12-10 14:53:58 -080098 * <p>By default there's just one (associated with the activity lifecycle), but apps could
Felipe Leme87a9dc92018-12-18 14:28:07 -080099 * explicitly add more using
100 * {@link ContentCaptureSession#createContentCaptureSession(ContentCaptureContext)}.
Felipe Leme88eae3b2018-11-07 15:11:56 -0800101 *
102 * @hide
103 */
104 @NonNull
Felipe Leme87a9dc92018-12-18 14:28:07 -0800105 @UiThread
106 public MainContentCaptureSession getMainContentCaptureSession() {
Felipe Lemeaa5088e2018-12-10 14:53:58 -0800107 if (mMainSession == null) {
Felipe Leme87a9dc92018-12-18 14:28:07 -0800108 mMainSession = new MainContentCaptureSession(mContext, mHandler, mService,
109 mDisabled);
Felipe Lemeaa5088e2018-12-10 14:53:58 -0800110 if (VERBOSE) {
111 Log.v(TAG, "getDefaultContentCaptureSession(): created " + mMainSession);
112 }
113 }
114 return mMainSession;
115 }
116
117 /** @hide */
118 public void onActivityStarted(@NonNull IBinder applicationToken,
119 @NonNull ComponentName activityComponent) {
120 // TODO(b/121033016): must start all sessions
121 getMainContentCaptureSession().start(applicationToken, activityComponent);
122 }
123
124 /** @hide */
125 public void onActivityStopped() {
126 // TODO(b/121033016): must finish all sessions
127 getMainContentCaptureSession().destroy();
Felipe Leme88eae3b2018-11-07 15:11:56 -0800128 }
129
130 /**
Felipe Lemeaa5088e2018-12-10 14:53:58 -0800131 * Flushes the content of all sessions.
Felipe Leme88eae3b2018-11-07 15:11:56 -0800132 *
Felipe Lemeaa5088e2018-12-10 14:53:58 -0800133 * <p>Typically called by {@code Activity} when it's paused / resumed.
Felipe Leme88eae3b2018-11-07 15:11:56 -0800134 *
Felipe Lemeaa5088e2018-12-10 14:53:58 -0800135 * @hide
Felipe Leme88eae3b2018-11-07 15:11:56 -0800136 */
Felipe Lemeaa5088e2018-12-10 14:53:58 -0800137 public void flush() {
138 // TODO(b/121033016): must flush all sessions
139 getMainContentCaptureSession().flush();
Felipe Leme88eae3b2018-11-07 15:11:56 -0800140 }
141
Felipe Leme1dfa9a02018-10-17 17:24:37 -0700142 /**
Felipe Lemeecb08be2018-11-27 15:48:47 -0800143 * Returns the component name of the system service that is consuming the captured events for
144 * the current user.
Felipe Leme1dfa9a02018-10-17 17:24:37 -0700145 */
146 @Nullable
Felipe Lemeecb08be2018-11-27 15:48:47 -0800147 public ComponentName getServiceComponentName() {
Felipe Lemeaa5088e2018-12-10 14:53:58 -0800148 //TODO(b/121047489): implement
Felipe Leme1dfa9a02018-10-17 17:24:37 -0700149 return null;
150 }
151
152 /**
Felipe Lemee348dc32018-11-05 12:35:29 -0800153 * Checks whether content capture is enabled for this activity.
Felipe Leme1dfa9a02018-10-17 17:24:37 -0700154 */
155 public boolean isContentCaptureEnabled() {
Felipe Lemeb18e3172018-11-27 10:33:41 -0800156 return mService != null && !mDisabled.get();
Felipe Leme1dfa9a02018-10-17 17:24:37 -0700157 }
158
159 /**
Felipe Leme284ad1c2018-11-15 18:16:12 -0800160 * Called by apps to explicitly enable or disable content capture.
Felipe Leme1dfa9a02018-10-17 17:24:37 -0700161 *
162 * <p><b>Note: </b> this call is not persisted accross reboots, so apps should typically call
163 * it on {@link android.app.Activity#onCreate(android.os.Bundle, android.os.PersistableBundle)}.
164 */
Felipe Leme6b3a55c2018-11-13 17:14:03 -0800165 public void setContentCaptureEnabled(boolean enabled) {
Felipe Lemeaa5088e2018-12-10 14:53:58 -0800166 //TODO(b/111276913): implement (need to finish / disable all sessions)
167 }
168
169 /**
170 * Called by the ap to request the Content Capture service to remove user-data associated with
171 * some context.
172 *
173 * @param request object specifying what user data should be removed.
174 */
175 public void removeUserData(@NonNull UserDataRemovalRequest request) {
Felipe Lemee348dc32018-11-05 12:35:29 -0800176 //TODO(b/111276913): implement
Felipe Leme1dfa9a02018-10-17 17:24:37 -0700177 }
178
Felipe Lemee348dc32018-11-05 12:35:29 -0800179 /** @hide */
180 public void dump(String prefix, PrintWriter pw) {
Felipe Lemeb718e032018-12-10 09:44:23 -0800181 pw.print(prefix); pw.println("ContentCaptureManager");
Felipe Lemeaa5088e2018-12-10 14:53:58 -0800182
183 pw.print(prefix); pw.print("Disabled: "); pw.println(mDisabled.get());
184 pw.print(prefix); pw.print("Context: "); pw.println(mContext);
185 pw.print(prefix); pw.print("User: "); pw.println(mContext.getUserId());
Felipe Lemeb18e3172018-11-27 10:33:41 -0800186 if (mService != null) {
Felipe Lemeaa5088e2018-12-10 14:53:58 -0800187 pw.print(prefix); pw.print("Service: "); pw.println(mService);
Felipe Lemeb18e3172018-11-27 10:33:41 -0800188 }
Felipe Lemeaa5088e2018-12-10 14:53:58 -0800189 if (mMainSession != null) {
190 final String prefix2 = prefix + " ";
191 pw.print(prefix); pw.println("Main session:");
192 mMainSession.dump(prefix2, pw);
193 } else {
194 pw.print(prefix); pw.println("No sessions");
Felipe Lemee348dc32018-11-05 12:35:29 -0800195 }
196 }
Felipe Leme1dfa9a02018-10-17 17:24:37 -0700197}