Merge changes from topics "dsiable_settings_2", "disable_cc_settings"
* changes: Added new APIs to let ContentCaptureService enable / disable the feature. Added new APIs to let Settings enable / disable ContentCapture
This commit is contained in:
@@ -6028,6 +6028,7 @@ package android.provider {
|
||||
field public static final String AUTOFILL_USER_DATA_MAX_VALUE_LENGTH = "autofill_user_data_max_value_length";
|
||||
field public static final String AUTOFILL_USER_DATA_MIN_VALUE_LENGTH = "autofill_user_data_min_value_length";
|
||||
field public static final String COMPLETED_CATEGORY_PREFIX = "suggested.completed_category.";
|
||||
field public static final String CONTENT_CAPTURE_ENABLED = "content_capture_enabled";
|
||||
field public static final String DOZE_ALWAYS_ON = "doze_always_on";
|
||||
field public static final String HUSH_GESTURE_USED = "hush_gesture_used";
|
||||
field public static final String INSTANT_APPS_ENABLED = "instant_apps_enabled";
|
||||
@@ -9365,6 +9366,11 @@ package android.view.contentcapture {
|
||||
field public static final int TYPE_VIEW_TEXT_CHANGED = 3; // 0x3
|
||||
}
|
||||
|
||||
public final class ContentCaptureManager {
|
||||
method public boolean isContentCaptureFeatureEnabled();
|
||||
method public void setContentCaptureFeatureEnabled(boolean);
|
||||
}
|
||||
|
||||
public final class UserDataRemovalRequest implements android.os.Parcelable {
|
||||
method @NonNull public String getPackageName();
|
||||
method @NonNull public java.util.List<android.view.contentcapture.UserDataRemovalRequest.UriRequest> getUriRequests();
|
||||
|
||||
@@ -1698,6 +1698,7 @@ package android.provider {
|
||||
field public static final String AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE = "autofill_user_data_max_user_data_size";
|
||||
field public static final String AUTOFILL_USER_DATA_MAX_VALUE_LENGTH = "autofill_user_data_max_value_length";
|
||||
field public static final String AUTOFILL_USER_DATA_MIN_VALUE_LENGTH = "autofill_user_data_min_value_length";
|
||||
field public static final String CONTENT_CAPTURE_ENABLED = "content_capture_enabled";
|
||||
field public static final String DISABLED_PRINT_SERVICES = "disabled_print_services";
|
||||
field @Deprecated public static final String ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES = "enabled_notification_policy_access_packages";
|
||||
field public static final String LOCATION_ACCESS_CHECK_DELAY_MILLIS = "location_access_check_delay_millis";
|
||||
|
||||
@@ -5687,6 +5687,14 @@ public final class Settings {
|
||||
public static final String AUTOFILL_USER_DATA_MIN_VALUE_LENGTH =
|
||||
"autofill_user_data_min_value_length";
|
||||
|
||||
/**
|
||||
* Defines whether Content Capture is enabled for the user.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@TestApi
|
||||
public static final String CONTENT_CAPTURE_ENABLED = "content_capture_enabled";
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link android.provider.Settings.Global#DEVICE_PROVISIONED} instead
|
||||
*/
|
||||
|
||||
@@ -15,10 +15,12 @@
|
||||
*/
|
||||
package android.view.contentcapture;
|
||||
|
||||
import static android.view.contentcapture.ContentCaptureHelper.DEBUG;
|
||||
import static android.view.contentcapture.ContentCaptureHelper.VERBOSE;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.annotation.SystemService;
|
||||
import android.annotation.UiThread;
|
||||
import android.content.ComponentName;
|
||||
@@ -51,6 +53,13 @@ public final class ContentCaptureManager {
|
||||
|
||||
private static final String TAG = ContentCaptureManager.class.getSimpleName();
|
||||
|
||||
/** @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;
|
||||
|
||||
/**
|
||||
* Timeout for calls to system_server.
|
||||
*/
|
||||
@@ -108,9 +117,7 @@ public final class ContentCaptureManager {
|
||||
if (mMainSession == null) {
|
||||
mMainSession = new MainContentCaptureSession(mContext, mHandler, mService,
|
||||
mDisabled);
|
||||
if (VERBOSE) {
|
||||
Log.v(TAG, "getDefaultContentCaptureSession(): created " + mMainSession);
|
||||
}
|
||||
if (VERBOSE) Log.v(TAG, "getMainContentCaptureSession(): created " + mMainSession);
|
||||
}
|
||||
return mMainSession;
|
||||
}
|
||||
@@ -147,13 +154,9 @@ public final class ContentCaptureManager {
|
||||
*/
|
||||
@Nullable
|
||||
public ComponentName getServiceComponentName() {
|
||||
if (!isContentCaptureEnabled()) {
|
||||
return null;
|
||||
}
|
||||
// Wait for system server to return the component name.
|
||||
if (!isContentCaptureEnabled()) return null;
|
||||
|
||||
final SyncResultReceiver resultReceiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
|
||||
|
||||
|
||||
try {
|
||||
mService.getServiceComponentName(resultReceiver);
|
||||
return resultReceiver.getParcelableResult();
|
||||
@@ -164,6 +167,17 @@ public final class ContentCaptureManager {
|
||||
|
||||
/**
|
||||
* Checks whether content capture is enabled for this activity.
|
||||
*
|
||||
* <p>There are many reasons it could be disabled, such as:
|
||||
* <ul>
|
||||
* <li>App itself disabled content capture through {@link #setContentCaptureEnabled(boolean)}.
|
||||
* <li>Service disabled content capture for this specific activity.
|
||||
* <li>Service disabled content capture for all activities of this package.
|
||||
* <li>Service disabled content capture globally.
|
||||
* <li>User disabled content capture globally (through Settings).
|
||||
* <li>OEM disabled content capture globally.
|
||||
* <li>Transient errors.
|
||||
* </ul>
|
||||
*/
|
||||
public boolean isContentCaptureEnabled() {
|
||||
synchronized (mLock) {
|
||||
@@ -178,11 +192,81 @@ public final class ContentCaptureManager {
|
||||
* it on {@link android.app.Activity#onCreate(android.os.Bundle, android.os.PersistableBundle)}.
|
||||
*/
|
||||
public void setContentCaptureEnabled(boolean enabled) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "setContentCaptureEnabled(): setting to " + enabled + " for " + mContext);
|
||||
}
|
||||
|
||||
synchronized (mLock) {
|
||||
mFlags |= enabled ? 0 : ContentCaptureContext.FLAG_DISABLED_BY_APP;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether Content Capture is enabled for the given user.
|
||||
*
|
||||
* <p>This method is typically used by the Content Capture Service settings page, so it can
|
||||
* provide a toggle to enable / disable it.
|
||||
*
|
||||
* @throws SecurityException if caller is not the app that owns the Content Capture service
|
||||
* associated with the user.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public boolean isContentCaptureFeatureEnabled() {
|
||||
if (mService == null) return false;
|
||||
|
||||
final SyncResultReceiver resultReceiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
|
||||
final int resultCode;
|
||||
try {
|
||||
mService.isContentCaptureFeatureEnabled(resultReceiver);
|
||||
resultCode = resultReceiver.getIntResult();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
switch (resultCode) {
|
||||
case RESULT_CODE_TRUE:
|
||||
return true;
|
||||
case RESULT_CODE_FALSE:
|
||||
return false;
|
||||
case RESULT_CODE_NOT_SERVICE:
|
||||
throw new SecurityException("caller is not user's ContentCapture service");
|
||||
default:
|
||||
throw new IllegalStateException("received invalid result: " + resultCode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether Content Capture is enabled for the given user.
|
||||
*
|
||||
* @throws SecurityException if caller is not the app that owns the Content Capture service
|
||||
* associated with the user.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public void setContentCaptureFeatureEnabled(boolean enabled) {
|
||||
if (DEBUG) Log.d(TAG, "setContentCaptureFeatureEnabled(): setting to " + enabled);
|
||||
|
||||
final SyncResultReceiver resultReceiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
|
||||
final int resultCode;
|
||||
try {
|
||||
mService.setContentCaptureFeatureEnabled(enabled, resultReceiver);
|
||||
resultCode = resultReceiver.getIntResult();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
switch (resultCode) {
|
||||
case RESULT_CODE_TRUE:
|
||||
// Our work is done here, in our void existance...
|
||||
return;
|
||||
case RESULT_CODE_NOT_SERVICE:
|
||||
throw new SecurityException("caller is not user's ContentCapture service");
|
||||
default:
|
||||
throw new IllegalStateException("received invalid result: " + resultCode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the app to request the Content Capture service to remove user-data associated with
|
||||
* some context.
|
||||
|
||||
@@ -99,7 +99,8 @@ public abstract class ContentCaptureSession implements AutoCloseable {
|
||||
public static final int STATE_FLAG_SECURE = 0x20;
|
||||
|
||||
/**
|
||||
* Session is disabled manually by the specific app.
|
||||
* Session is disabled manually by the specific app
|
||||
* (through {@link ContentCaptureManager#setContentCaptureEnabled(boolean)}).
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
|
||||
@@ -62,4 +62,14 @@ oneway interface IContentCaptureManager {
|
||||
* Requests the removal of user data for the calling user.
|
||||
*/
|
||||
void removeUserData(in UserDataRemovalRequest request);
|
||||
|
||||
/**
|
||||
* Returns whether the content capture feature is enabled for the calling user.
|
||||
*/
|
||||
void isContentCaptureFeatureEnabled(in IResultReceiver result);
|
||||
|
||||
/**
|
||||
* Sets whether the content capture feature is enabled for the given user.
|
||||
*/
|
||||
void setContentCaptureFeatureEnabled(boolean enabled, in IResultReceiver result);
|
||||
}
|
||||
|
||||
@@ -608,6 +608,7 @@ public class SettingsBackupTest {
|
||||
Settings.Secure.CMAS_ADDITIONAL_BROADCAST_PKG,
|
||||
Settings.Secure.COMPLETED_CATEGORY_PREFIX,
|
||||
Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS,
|
||||
Settings.Secure.CONTENT_CAPTURE_ENABLED,
|
||||
Settings.Secure.DEFAULT_INPUT_METHOD,
|
||||
Settings.Secure.DEVICE_PAIRED,
|
||||
Settings.Secure.DIALER_DEFAULT_APPLICATION,
|
||||
|
||||
@@ -20,10 +20,16 @@ import static android.Manifest.permission.MANAGE_CONTENT_CAPTURE;
|
||||
import static android.content.Context.CONTENT_CAPTURE_MANAGER_SERVICE;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.ActivityManagerInternal;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.database.ContentObserver;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
@@ -32,8 +38,11 @@ import android.os.ResultReceiver;
|
||||
import android.os.ShellCallback;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.provider.Settings;
|
||||
import android.util.LocalLog;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.view.contentcapture.ContentCaptureManager;
|
||||
import android.view.contentcapture.IContentCaptureManager;
|
||||
import android.view.contentcapture.UserDataRemovalRequest;
|
||||
|
||||
@@ -49,6 +58,7 @@ import com.android.server.infra.FrameworkResourcesServiceNameResolver;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A service used to observe the contents of the screen.
|
||||
@@ -60,23 +70,43 @@ import java.util.ArrayList;
|
||||
public final class ContentCaptureManagerService extends
|
||||
AbstractMasterSystemService<ContentCaptureManagerService, ContentCapturePerUserService> {
|
||||
|
||||
private static final String TAG = ContentCaptureManagerService.class.getSimpleName();
|
||||
|
||||
static final String RECEIVER_BUNDLE_EXTRA_SESSIONS = "sessions";
|
||||
|
||||
private static final int MAX_TEMP_SERVICE_DURATION_MS = 1_000 * 60 * 2; // 2 minutes
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private ActivityManagerInternal mAm;
|
||||
|
||||
private final LocalService mLocalService = new LocalService();
|
||||
|
||||
private final LocalLog mRequestsHistory = new LocalLog(20);
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private ActivityManagerInternal mAm;
|
||||
|
||||
/**
|
||||
* Users disabled by {@link android.provider.Settings.Secure#CONTENT_CAPTURE_ENABLED}.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
@Nullable
|
||||
private SparseBooleanArray mDisabledUsers;
|
||||
|
||||
|
||||
public ContentCaptureManagerService(@NonNull Context context) {
|
||||
super(context, new FrameworkResourcesServiceNameResolver(context,
|
||||
com.android.internal.R.string.config_defaultContentCaptureService),
|
||||
UserManager.DISALLOW_CONTENT_CAPTURE);
|
||||
// Sets which serviecs are disabled
|
||||
final UserManager um = getContext().getSystemService(UserManager.class);
|
||||
final List<UserInfo> users = um.getUsers();
|
||||
for (int i = 0; i < users.size(); i++) {
|
||||
final int userId = users.get(i).id;
|
||||
final boolean disabled = isDisabledBySettings(userId);
|
||||
if (disabled) {
|
||||
Slog.i(mTag, "user " + userId + " disabled by settings");
|
||||
if (mDisabledUsers == null) {
|
||||
mDisabledUsers = new SparseBooleanArray(1);
|
||||
}
|
||||
mDisabledUsers.put(userId, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override // from AbstractMasterSystemService
|
||||
@@ -100,7 +130,7 @@ public final class ContentCaptureManagerService extends
|
||||
|
||||
@Override // from AbstractMasterSystemService
|
||||
protected void enforceCallingPermissionForManagement() {
|
||||
getContext().enforceCallingPermission(MANAGE_CONTENT_CAPTURE, TAG);
|
||||
getContext().enforceCallingPermission(MANAGE_CONTENT_CAPTURE, mTag);
|
||||
}
|
||||
|
||||
@Override // from AbstractMasterSystemService
|
||||
@@ -108,9 +138,86 @@ public final class ContentCaptureManagerService extends
|
||||
return MAX_TEMP_SERVICE_DURATION_MS;
|
||||
}
|
||||
|
||||
@Override // from AbstractMasterSystemService
|
||||
protected void registerForExtraSettingsChanges(@NonNull ContentResolver resolver,
|
||||
@NonNull ContentObserver observer) {
|
||||
resolver.registerContentObserver(Settings.Secure.getUriFor(
|
||||
Settings.Secure.CONTENT_CAPTURE_ENABLED), false, observer,
|
||||
UserHandle.USER_ALL);
|
||||
}
|
||||
|
||||
@Override // from AbstractMasterSystemService
|
||||
protected void onSettingsChanged(@UserIdInt int userId, @NonNull String property) {
|
||||
switch (property) {
|
||||
case Settings.Secure.CONTENT_CAPTURE_ENABLED:
|
||||
setContentCaptureFeatureEnabledFromSettings(userId);
|
||||
return;
|
||||
default:
|
||||
Slog.w(mTag, "Unexpected property (" + property + "); updating cache instead");
|
||||
}
|
||||
}
|
||||
|
||||
@Override // from AbstractMasterSystemService
|
||||
protected boolean isDisabledLocked(@UserIdInt int userId) {
|
||||
return isDisabledBySettingsLocked(userId) || super.isDisabledLocked(userId);
|
||||
}
|
||||
|
||||
private boolean isDisabledBySettingsLocked(@UserIdInt int userId) {
|
||||
return mDisabledUsers != null && mDisabledUsers.get(userId);
|
||||
}
|
||||
|
||||
private void setContentCaptureFeatureEnabledFromSettings(@UserIdInt int userId) {
|
||||
setContentCaptureFeatureEnabledForUser(userId, !isDisabledBySettings(userId));
|
||||
}
|
||||
|
||||
private boolean isDisabledBySettings(@UserIdInt int userId) {
|
||||
final String property = Settings.Secure.CONTENT_CAPTURE_ENABLED;
|
||||
final String value = Settings.Secure.getStringForUser(getContext().getContentResolver(),
|
||||
property, userId);
|
||||
if (value == null) {
|
||||
if (verbose) {
|
||||
Slog.v(mTag, "isDisabledBySettings(): assuming false as '" + property
|
||||
+ "' is not set");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
return !Boolean.valueOf(value);
|
||||
} catch (Exception e) {
|
||||
Slog.w(mTag, "Invalid value for property " + property + ": " + value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void setContentCaptureFeatureEnabledForUser(@UserIdInt int userId, boolean enabled) {
|
||||
synchronized (mLock) {
|
||||
if (mDisabledUsers == null) {
|
||||
mDisabledUsers = new SparseBooleanArray();
|
||||
}
|
||||
final boolean alreadyEnabled = !mDisabledUsers.get(userId);
|
||||
if (!(enabled ^ alreadyEnabled)) {
|
||||
if (debug) {
|
||||
Slog.d(mTag, "setContentCaptureFeatureEnabledForUser(): already " + enabled);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (enabled) {
|
||||
Slog.i(mTag, "setContentCaptureFeatureEnabled(): enabling service for user "
|
||||
+ userId);
|
||||
mDisabledUsers.delete(userId);
|
||||
} else {
|
||||
Slog.i(mTag, "setContentCaptureFeatureEnabled(): disabling service for user "
|
||||
+ userId);
|
||||
mDisabledUsers.put(userId, true);
|
||||
}
|
||||
updateCachedServiceLocked(userId, !enabled);
|
||||
}
|
||||
}
|
||||
|
||||
// Called by Shell command.
|
||||
void destroySessions(@UserIdInt int userId, @NonNull IResultReceiver receiver) {
|
||||
Slog.i(TAG, "destroySessions() for userId " + userId);
|
||||
Slog.i(mTag, "destroySessions() for userId " + userId);
|
||||
enforceCallingPermissionForManagement();
|
||||
|
||||
synchronized (mLock) {
|
||||
@@ -133,7 +240,7 @@ public final class ContentCaptureManagerService extends
|
||||
|
||||
// Called by Shell command.
|
||||
void listSessions(int userId, IResultReceiver receiver) {
|
||||
Slog.i(TAG, "listSessions() for userId " + userId);
|
||||
Slog.i(mTag, "listSessions() for userId " + userId);
|
||||
enforceCallingPermissionForManagement();
|
||||
|
||||
final Bundle resultData = new Bundle();
|
||||
@@ -174,6 +281,64 @@ public final class ContentCaptureManagerService extends
|
||||
return mAm;
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private boolean assertCalledByServiceLocked(@NonNull String methodName, @UserIdInt int userId,
|
||||
int callingUid, @NonNull IResultReceiver result) {
|
||||
final boolean isService = isCalledByServiceLocked(methodName, userId, callingUid);
|
||||
if (isService) return true;
|
||||
|
||||
try {
|
||||
result.send(ContentCaptureManager.RESULT_CODE_NOT_SERVICE,
|
||||
/* resultData= */ null);
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(mTag, "Unable to send isContentCaptureFeatureEnabled(): " + e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private boolean isCalledByServiceLocked(@NonNull String methodName, @UserIdInt int userId,
|
||||
int callingUid) {
|
||||
|
||||
final String serviceName = mServiceNameResolver.getServiceName(userId);
|
||||
if (serviceName == null) {
|
||||
Slog.e(mTag, methodName + ": called by UID " + callingUid
|
||||
+ ", but there's no service set for user " + userId);
|
||||
return false;
|
||||
}
|
||||
|
||||
final ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName);
|
||||
if (serviceComponent == null) {
|
||||
Slog.w(mTag, methodName + ": invalid service name: " + serviceName);
|
||||
return false;
|
||||
}
|
||||
|
||||
final String servicePackageName = serviceComponent.getPackageName();
|
||||
|
||||
final PackageManager pm = getContext().getPackageManager();
|
||||
final int serviceUid;
|
||||
try {
|
||||
serviceUid = pm.getPackageUidAsUser(servicePackageName, UserHandle.getCallingUserId());
|
||||
} catch (NameNotFoundException e) {
|
||||
Slog.w(mTag, methodName + ": could not verify UID for " + serviceName);
|
||||
return false;
|
||||
}
|
||||
if (callingUid != serviceUid) {
|
||||
Slog.e(mTag, methodName + ": called by UID " + callingUid + ", but service UID is "
|
||||
+ serviceUid);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override // from AbstractMasterSystemService
|
||||
protected void dumpLocked(String prefix, PrintWriter pw) {
|
||||
super.dumpLocked(prefix, pw);
|
||||
|
||||
pw.print(prefix); pw.print("Disabled users: "); pw.println(mDisabledUsers);
|
||||
}
|
||||
|
||||
final class ContentCaptureManagerServiceStub extends IContentCaptureManager.Stub {
|
||||
|
||||
@Override
|
||||
@@ -222,8 +387,7 @@ public final class ContentCaptureManagerService extends
|
||||
result.send(/* resultCode= */ 0,
|
||||
SyncResultReceiver.bundleFor(connectedServiceComponentName));
|
||||
} catch (RemoteException e) {
|
||||
// Ignore exception as we need to be resilient against app behavior.
|
||||
Slog.w(TAG, "Unable to send service component name: " + e);
|
||||
Slog.w(mTag, "Unable to send service component name: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,9 +401,53 @@ public final class ContentCaptureManagerService extends
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void isContentCaptureFeatureEnabled(@NonNull IResultReceiver result) {
|
||||
final int userId = UserHandle.getCallingUserId();
|
||||
boolean enabled;
|
||||
synchronized (mLock) {
|
||||
final boolean isService = assertCalledByServiceLocked(
|
||||
"isContentCaptureFeatureEnabled()", userId, Binder.getCallingUid(), result);
|
||||
if (!isService) return;
|
||||
|
||||
enabled = !isDisabledBySettingsLocked(userId);
|
||||
}
|
||||
try {
|
||||
result.send(enabled ? ContentCaptureManager.RESULT_CODE_TRUE
|
||||
: ContentCaptureManager.RESULT_CODE_FALSE, /* resultData= */null);
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(mTag, "Unable to send isContentCaptureFeatureEnabled(): " + e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentCaptureFeatureEnabled(boolean enabled,
|
||||
@NonNull IResultReceiver result) {
|
||||
final int userId = UserHandle.getCallingUserId();
|
||||
final boolean isService;
|
||||
synchronized (mLock) {
|
||||
isService = assertCalledByServiceLocked("setContentCaptureFeatureEnabled()", userId,
|
||||
Binder.getCallingUid(), result);
|
||||
}
|
||||
if (!isService) return;
|
||||
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
Settings.Secure.putStringForUser(getContext().getContentResolver(),
|
||||
Settings.Secure.CONTENT_CAPTURE_ENABLED, Boolean.toString(enabled), userId);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
try {
|
||||
result.send(ContentCaptureManager.RESULT_CODE_TRUE, /* resultData= */null);
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(mTag, "Unable to send setContentCaptureFeatureEnabled(): " + e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
|
||||
if (!DumpUtils.checkDumpPermission(getContext(), mTag, pw)) return;
|
||||
|
||||
boolean showHistory = true;
|
||||
if (args != null) {
|
||||
@@ -252,7 +460,7 @@ public final class ContentCaptureManagerService extends
|
||||
pw.println("Usage: dumpsys content_capture [--no-history]");
|
||||
return;
|
||||
default:
|
||||
Slog.w(TAG, "Ignoring invalid dump arg: " + arg);
|
||||
Slog.w(mTag, "Ignoring invalid dump arg: " + arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
@Nullable
|
||||
private final SparseBooleanArray mDisabledUsers;
|
||||
private final SparseBooleanArray mDisabledByUserRestriction;
|
||||
|
||||
/**
|
||||
* Cache of services per user id.
|
||||
@@ -148,9 +148,9 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
|
||||
|
||||
}
|
||||
if (disallowProperty == null) {
|
||||
mDisabledUsers = null;
|
||||
mDisabledByUserRestriction = null;
|
||||
} else {
|
||||
mDisabledUsers = new SparseBooleanArray();
|
||||
mDisabledByUserRestriction = new SparseBooleanArray();
|
||||
// Hookup with UserManager to disable service when necessary.
|
||||
final UserManager um = context.getSystemService(UserManager.class);
|
||||
final UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
|
||||
@@ -159,15 +159,15 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
|
||||
final int userId = users.get(i).id;
|
||||
final boolean disabled = umi.getUserRestriction(userId, disallowProperty);
|
||||
if (disabled) {
|
||||
Slog.i(mTag, "Disabling for user " + userId);
|
||||
mDisabledUsers.put(userId, disabled);
|
||||
Slog.i(mTag, "Disabling by restrictions user " + userId);
|
||||
mDisabledByUserRestriction.put(userId, disabled);
|
||||
}
|
||||
}
|
||||
umi.addUserRestrictionsListener((userId, newRestrictions, prevRestrictions) -> {
|
||||
final boolean disabledNow =
|
||||
newRestrictions.getBoolean(disallowProperty, false);
|
||||
synchronized (mLock) {
|
||||
final boolean disabledBefore = mDisabledUsers.get(userId);
|
||||
final boolean disabledBefore = mDisabledByUserRestriction.get(userId);
|
||||
if (disabledBefore == disabledNow) {
|
||||
// Nothing changed, do nothing.
|
||||
if (debug) {
|
||||
@@ -176,7 +176,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
|
||||
}
|
||||
}
|
||||
Slog.i(mTag, "Updating for user " + userId + ": disabled=" + disabledNow);
|
||||
mDisabledUsers.put(userId, disabledNow);
|
||||
mDisabledByUserRestriction.put(userId, disabledNow);
|
||||
updateCachedServiceLocked(userId, disabledNow);
|
||||
}
|
||||
});
|
||||
@@ -414,7 +414,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
|
||||
* given user.
|
||||
*/
|
||||
protected boolean isDisabledLocked(@UserIdInt int userId) {
|
||||
return mDisabledUsers == null ? false : mDisabledUsers.get(userId);
|
||||
return mDisabledByUserRestriction == null ? false : mDisabledByUserRestriction.get(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -523,7 +523,8 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
|
||||
mServiceNameResolver.dumpShort(pw, userId); pw.println();
|
||||
}
|
||||
}
|
||||
pw.print(prefix); pw.print("Disabled users: "); pw.println(mDisabledUsers);
|
||||
pw.print(prefix); pw.print("Users disabled by restriction: ");
|
||||
pw.println(mDisabledByUserRestriction);
|
||||
pw.print(prefix); pw.print("Allow instant service: "); pw.println(mAllowInstantService);
|
||||
final String settingsProperty = getServiceSettingsProperty();
|
||||
if (settingsProperty != null) {
|
||||
|
||||
Reference in New Issue
Block a user