import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.util.Log;
import android.view.contentcapture.ContentCaptureSession.FlushReason;
private static final String TAG = ContentCaptureManager.class.getSimpleName();
/** @hide */
+ public static final int RESULT_CODE_OK = 0;
+ /** @hide */
public static final int RESULT_CODE_TRUE = 1;
/** @hide */
public static final int RESULT_CODE_FALSE = 2;
/** @hide */
- public static final int RESULT_CODE_NOT_SERVICE = -1;
+ public static final int RESULT_CODE_SECURITY_EXCEPTION = -1;
/**
* Timeout for calls to system_server.
}
/**
+ * Gets the (optional) intent used to launch the service-specific settings.
+ *
+ * <p>This method is static because it's called by Settings, which might not be whitelisted
+ * for content capture (in which case the ContentCaptureManager on its context would be null).
+ *
+ * @hide
+ */
+ @Nullable
+ public static ComponentName getServiceSettingsComponentName() {
+ final IBinder binder = ServiceManager
+ .checkService(Context.CONTENT_CAPTURE_MANAGER_SERVICE);
+ if (binder == null) return null;
+
+ final IContentCaptureManager service = IContentCaptureManager.Stub.asInterface(binder);
+ final SyncResultReceiver resultReceiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
+ try {
+ service.getServiceSettingsActivity(resultReceiver);
+ final int resultCode = resultReceiver.getIntResult();
+ if (resultCode == RESULT_CODE_SECURITY_EXCEPTION) {
+ throw new SecurityException(resultReceiver.getStringResult());
+ }
+ return resultReceiver.getParcelableResult();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Checks whether content capture is enabled for this activity.
*
* <p>There are many reasons it could be disabled, such as:
return true;
case RESULT_CODE_FALSE:
return false;
- case RESULT_CODE_NOT_SERVICE:
+ case RESULT_CODE_SECURITY_EXCEPTION:
throw new SecurityException("caller is not user's ContentCapture service");
default:
Log.wtf(TAG, "received invalid result: " + resultCode);
import static android.Manifest.permission.MANAGE_CONTENT_CAPTURE;
import static android.content.Context.CONTENT_CAPTURE_MANAGER_SERVICE;
+import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_FALSE;
+import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_OK;
+import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_SECURITY_EXCEPTION;
+import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_TRUE;
+
+import static com.android.internal.util.SyncResultReceiver.bundleFor;
import android.annotation.NonNull;
import android.annotation.Nullable;
import com.android.internal.os.IResultReceiver;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
-import com.android.internal.util.SyncResultReceiver;
import com.android.server.LocalServices;
import com.android.server.infra.AbstractMasterSystemService;
import com.android.server.infra.FrameworkResourcesServiceNameResolver;
if (isService) return true;
try {
- result.send(ContentCaptureManager.RESULT_CODE_NOT_SERVICE,
- /* resultData= */ null);
+ result.send(RESULT_CODE_SECURITY_EXCEPTION, /* resultData= */ null);
} catch (RemoteException e) {
Slog.w(mTag, "Unable to send isContentCaptureFeatureEnabled(): " + e);
}
connectedServiceComponentName = service.getServiceComponentName();
}
try {
- result.send(/* resultCode= */ 0,
- SyncResultReceiver.bundleFor(connectedServiceComponentName));
+ result.send(RESULT_CODE_OK, bundleFor(connectedServiceComponentName));
} catch (RemoteException e) {
Slog.w(mTag, "Unable to send service component name: " + e);
}
enabled = !mDisabledByDeviceConfig && !isDisabledBySettingsLocked(userId);
}
try {
- result.send(enabled ? ContentCaptureManager.RESULT_CODE_TRUE
- : ContentCaptureManager.RESULT_CODE_FALSE, /* resultData= */null);
+ result.send(enabled ? RESULT_CODE_TRUE : RESULT_CODE_FALSE, /* resultData= */null);
} catch (RemoteException e) {
Slog.w(mTag, "Unable to send isContentCaptureFeatureEnabled(): " + e);
}
}
@Override
+ public void getServiceSettingsActivity(@NonNull IResultReceiver result) {
+ try {
+ enforceCallingPermissionForManagement();
+ } catch (SecurityException e) {
+ try {
+ result.send(RESULT_CODE_SECURITY_EXCEPTION, bundleFor(e.getMessage()));
+ } catch (RemoteException e2) {
+ Slog.w(mTag, "Unable to send getServiceSettingsIntent() exception: " + e2);
+ return;
+ }
+ }
+
+ final int userId = UserHandle.getCallingUserId();
+ final ComponentName componentName;
+ synchronized (mLock) {
+ final ContentCapturePerUserService service = getServiceForUserLocked(userId);
+ if (service == null) return;
+ componentName = service.getServiceSettingsActivityLocked();
+ }
+ try {
+ result.send(RESULT_CODE_OK, bundleFor(componentName));
+ } catch (RemoteException e) {
+ Slog.w(mTag, "Unable to send getServiceSettingsIntent(): " + e);
+ }
+ }
+
+ @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(getContext(), mTag, pw)) return;