diff options
12 files changed, 135 insertions, 107 deletions
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 17c4d25d82d7..03d4d5e10e64 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -3513,6 +3513,17 @@ public abstract class PackageManager { public static final String FEATURE_TUNER = "android.hardware.tv.tuner"; /** + * Feature for {@link #getSystemAvailableFeatures} and + * {@link #hasSystemFeature}: The device supports a enabling/disabling sensor privacy for + * camera. When sensory privacy for the camera is enabled no camera data is send to clients, + * e.g. the view finder in a camera app would appear blank. + * + * @hide + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_CAMERA_TOGGLE = "android.hardware.camera.toggle"; + + /** * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device has * the necessary changes to support app enumeration. * diff --git a/packages/SystemUI/res/drawable/ic_camera_blocked.xml b/packages/SystemUI/res/drawable/ic_camera_blocked.xml new file mode 100644 index 000000000000..0161bcbd1937 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_camera_blocked.xml @@ -0,0 +1,29 @@ +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="m18,12c-2.75,0 -5,2.25 -5,5 0,2.75 2.25,5 5,5 2.75,0 5,-2.25 5,-5 0,-2.75 -2.1667,-5 -5,-5zM15.5,17.8333h5v-1.6666h-5z" + android:fillColor="#30302a" + android:fillType="evenOdd"/> + <path + android:pathData="m16.4,5.5004h-2.536l-1.464,-1.6H7.6l-1.464,1.6H3.6c-0.88,0 -1.6,0.72 -1.6,1.6v9.6c0,0.88 0.72,1.6 1.6,1.6h8.5413C12.0488,17.8817 12,17.4465 12,17c0,-0.1005 0.0025,-0.2004 0.0073,-0.2996H3.6V7.1004H16.4V11.2157C16.9094,11.0751 17.4459,11 18,11V7.1004c0,-0.88 -0.72,-1.6 -1.6,-1.6zM6.8,11.9004c0,-1.768 1.432,-3.2 3.2,-3.2 1.768,0 3.2,1.432 3.2,3.2 0,1.768 -1.432,3.2 -3.2,3.2 -1.768,0 -3.2,-1.432 -3.2,-3.2z" + android:fillColor="#30302a" + android:fillType="evenOdd"/> +</vector> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 7cdd8b1b80ca..e12342c9d42b 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -821,6 +821,8 @@ <string name="quick_settings_location_label">Location</string> <!-- QuickSettings: Location (Off) [CHAR LIMIT=NONE] --> <string name="quick_settings_location_off_label">Location Off</string> + <!-- QuickSettings: Camera [CHAR LIMIT=NONE] --> + <string name="quick_settings_camera_label">Block Camera</string> <!-- QuickSettings: Media device [CHAR LIMIT=NONE] --> <string name="quick_settings_media_device_label">Media device</string> <!-- QuickSettings: RSSI [CHAR LIMIT=NONE] --> diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java index 7ca8e63bfae1..754879e59dd9 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java @@ -20,6 +20,7 @@ import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME import static com.android.systemui.Dependency.LEAK_REPORT_EMAIL_NAME; import android.content.Context; +import android.hardware.SensorPrivacyManager; import android.os.Handler; import android.os.PowerManager; @@ -62,6 +63,8 @@ import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl; import com.android.systemui.statusbar.policy.HeadsUpManager; +import com.android.systemui.statusbar.policy.SensorPrivacyController; +import com.android.systemui.statusbar.policy.SensorPrivacyControllerImpl; import javax.inject.Named; @@ -116,6 +119,15 @@ public abstract class SystemUIDefaultModule { return bC; } + @Provides + @SysUISingleton + static SensorPrivacyController provideSensorPrivacyController( + SensorPrivacyManager sensorPrivacyManager) { + SensorPrivacyController spC = new SensorPrivacyControllerImpl(sensorPrivacyManager); + spC.init(); + return spC; + } + @Binds @SysUISingleton public abstract QSFactory bindQSFactory(QSFactoryImpl qsFactoryImpl); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java index d719fc3f0d7b..093163070dd5 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java @@ -16,11 +16,12 @@ package com.android.systemui.qs.tiles; -import android.content.Context; +import static com.android.systemui.DejankUtils.whitelistIpcs; + import android.content.Intent; -import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Looper; +import android.provider.DeviceConfig; import android.service.quicksettings.Tile; import android.widget.Switch; @@ -38,7 +39,8 @@ import com.android.systemui.statusbar.policy.CameraToggleController; import javax.inject.Inject; -public class CameraToggleTile extends QSTileImpl<QSTile.BooleanState> { +public class CameraToggleTile extends QSTileImpl<QSTile.BooleanState> implements + CameraToggleController.Callback { private CameraToggleController mCameraToggleController; @@ -54,7 +56,15 @@ public class CameraToggleTile extends QSTileImpl<QSTile.BooleanState> { super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, activityStarter, qsLogger); mCameraToggleController = cameraToggleController; - mCameraToggleController.addCallback((b) -> refreshState()); + mCameraToggleController.observe(getLifecycle(), this); + } + + @Override + public boolean isAvailable() { + return /*getHost().getContext().getPackageManager().hasSystemFeature(FEATURE_CAMERA_TOGGLE) + && */whitelistIpcs(() -> DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, + "camera_toggle_enabled", + false)); } @Override @@ -64,21 +74,18 @@ public class CameraToggleTile extends QSTileImpl<QSTile.BooleanState> { @Override protected void handleClick() { - mCameraToggleController.setCameraEnabled(!mCameraToggleController.isCameraEnabled()); + mCameraToggleController.setCameraBlocked(!mCameraToggleController.isCameraBlocked()); } @Override protected void handleUpdateState(BooleanState state, Object arg) { - state.icon = new CameraToggleTileIcon(); - state.state = mCameraToggleController.isCameraEnabled() - ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE; - state.value = mCameraToggleController.isCameraEnabled(); - state.label = "Camera"; - if (!mCameraToggleController.isCameraAvailable()) { - state.secondaryLabel = "Currently in use"; - } else { - state.secondaryLabel = null; - } + boolean isBlocked = arg == null ? mCameraToggleController.setCameraBlocked() + : (boolean) arg; + + state.icon = ResourceIcon.get(R.drawable.ic_camera_blocked); + state.state = isBlocked ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE; + state.value = isBlocked; + state.label = getTileLabel(); state.handlesLongClick = false; state.contentDescription = state.label; state.expandedAccessibilityClassName = Switch.class.getName(); @@ -96,14 +103,11 @@ public class CameraToggleTile extends QSTileImpl<QSTile.BooleanState> { @Override public CharSequence getTileLabel() { - return "Camera"; + return mContext.getString(R.string.quick_settings_camera_label); } - class CameraToggleTileIcon extends Icon { - - @Override - public Drawable getDrawable(Context context) { - return context.getDrawable(R.drawable.ic_camera); - } + @Override + public void onCameraBlockedChanged(boolean enable) { + refreshState(enable); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CameraToggleController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CameraToggleController.java index 544f0050d352..b9de21c1fb82 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CameraToggleController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CameraToggleController.java @@ -16,18 +16,14 @@ package com.android.systemui.statusbar.policy; -import com.android.systemui.Dumpable; +public interface CameraToggleController extends + CallbackController<CameraToggleController.Callback> { -public interface CameraToggleController extends CallbackController<CameraToggleController.Callback>, - Dumpable { + boolean isCameraBlocked(); - boolean isCameraEnabled(); - void setCameraEnabled(boolean enabled); - - boolean isCameraAvailable(); + void setCameraBlocked(boolean blocked); interface Callback { - void onCameraEnabledChanged(boolean enable); + void onCameraBlockedChanged(boolean blocked); } - } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CameraToggleControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CameraToggleControllerImpl.java index 7496813247c9..3fb1ac56226e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CameraToggleControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CameraToggleControllerImpl.java @@ -16,86 +16,42 @@ package com.android.systemui.statusbar.policy; +import static android.service.SensorPrivacyIndividualEnabledSensorProto.CAMERA; + import android.content.Context; -import android.hardware.camera2.CameraManager; -import android.hardware.camera2.CameraToggleManager; -import android.os.Looper; +import android.hardware.SensorPrivacyManager; import android.util.ArraySet; -import android.widget.Toast; import androidx.annotation.NonNull; -import com.android.systemui.dagger.qualifiers.Background; -import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.dump.DumpManager; - -import java.io.FileDescriptor; -import java.io.PrintWriter; import java.util.Set; import javax.inject.Inject; public class CameraToggleControllerImpl implements CameraToggleController { - private final Context mContext; - private final DumpManager mDumpManager; - private final CameraToggleManager mCameraToggleManager; - - private boolean mState = true; - - Set<Callback> mCallbacks = new ArraySet<>(); + private final @NonNull Context mContext; + private final @NonNull SensorPrivacyManager mSensorPrivacyManager; + private boolean mState; + private Set<Callback> mCallbacks = new ArraySet<>(); - Set<String> mUsedCameras = new ArraySet<>(); - - /** - */ @Inject - public CameraToggleControllerImpl( - Context context, - DumpManager dumpManager, - @Background Looper bgLooper, - @Main Looper mainLooper) { + public CameraToggleControllerImpl(@NonNull Context context) { mContext = context; - mDumpManager = dumpManager; - mCameraToggleManager = context.getSystemService(CameraToggleManager.class); - mCameraToggleManager.addCameraToggleChangeListener(this::onCameraChanged); - mState = mCameraToggleManager.isCameraEnabled(); - mContext.getSystemService(CameraManager.class).registerAvailabilityCallback( - context.getMainExecutor(), new CameraManager.AvailabilityCallback() { - @Override - public void onCameraAvailable(@NonNull String cameraId) { - mUsedCameras.remove(cameraId); - onCameraChanged(mState); - } + mSensorPrivacyManager = context.getSystemService(SensorPrivacyManager.class); + mSensorPrivacyManager.addSensorPrivacyListener(CAMERA, this::onCameraPrivacyChanged); - @Override - public void onCameraUnavailable(@NonNull String cameraId) { - mUsedCameras.add(cameraId); - onCameraChanged(mState); - } - }); + mState = mSensorPrivacyManager.isIndividualSensorPrivacyEnabled(CAMERA); } @Override - public boolean isCameraEnabled() { + public boolean isCameraBlocked() { return mState; } @Override - public void setCameraEnabled(boolean enabled) { - if (!/*mCameraToggleManager.setCameraEnabled(enabled)*/true) { - Toast.makeText(mContext, "Can't disable camera while in use", Toast.LENGTH_LONG); - } - } - - @Override - public boolean isCameraAvailable() { - return false;/*mUsedCameras.isEmpty();*/ - } - - @Override - public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { - + public void setCameraBlocked(boolean blocked) { + mSensorPrivacyManager.setIndividualSensorPrivacyForProfileGroup(CAMERA, blocked); } @Override @@ -108,10 +64,10 @@ public class CameraToggleControllerImpl implements CameraToggleController { mCallbacks.remove(listener); } - private void onCameraChanged(boolean state) { + private void onCameraPrivacyChanged(boolean state) { mState = state; for (Callback callback : mCallbacks) { - callback.onCameraEnabledChanged(state); + callback.onCameraBlockedChanged(mState); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyController.java index 6d5ce60ef621..4a09234325ca 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyController.java @@ -23,6 +23,11 @@ public interface SensorPrivacyController extends CallbackController<SensorPrivacyController.OnSensorPrivacyChangedListener> { /** + * Initialize the controller. Needs to be called after constructing the object + */ + void init(); + + /** * Returns whether sensor privacy is enabled. */ boolean isSensorPrivacyEnabled(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyControllerImpl.java index 20cc46ff6bbd..a2334f3a23d6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyControllerImpl.java @@ -35,20 +35,21 @@ import javax.inject.Inject; public class SensorPrivacyControllerImpl implements SensorPrivacyController, SensorPrivacyManager.OnSensorPrivacyChangedListener { private SensorPrivacyManager mSensorPrivacyManager; - private final List<OnSensorPrivacyChangedListener> mListeners; + private final List<OnSensorPrivacyChangedListener> mListeners = new ArrayList<>(1); private Object mLock = new Object(); private boolean mSensorPrivacyEnabled; /** * Public constructor. */ - @Inject - public SensorPrivacyControllerImpl(Context context) { - mSensorPrivacyManager = (SensorPrivacyManager) context.getSystemService( - Context.SENSOR_PRIVACY_SERVICE); + public SensorPrivacyControllerImpl(@NonNull SensorPrivacyManager sensorPrivacyManager) { + mSensorPrivacyManager = sensorPrivacyManager; + } + + @Override + public void init() { mSensorPrivacyEnabled = mSensorPrivacyManager.isSensorPrivacyEnabled(); mSensorPrivacyManager.addSensorPrivacyListener(this); - mListeners = new ArrayList<>(1); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java index 916a1a8e3582..a6278d689e0f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java @@ -109,11 +109,6 @@ public interface StatusBarPolicyModule { /** */ @Binds - SensorPrivacyController provideSensorPrivacyControllerImpl( - SensorPrivacyControllerImpl controllerImpl); - - /** */ - @Binds UserInfoController provideUserInfoContrller(UserInfoControllerImpl controllerImpl); /** */ diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java index 56a4c203e840..a24f7dd64481 100644 --- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java @@ -20,6 +20,7 @@ import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME import static com.android.systemui.Dependency.LEAK_REPORT_EMAIL_NAME; import android.content.Context; +import android.hardware.SensorPrivacyManager; import android.os.Handler; import android.os.PowerManager; @@ -63,6 +64,8 @@ import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl; import com.android.systemui.statusbar.policy.HeadsUpManager; +import com.android.systemui.statusbar.policy.SensorPrivacyController; +import com.android.systemui.statusbar.policy.SensorPrivacyControllerImpl; import com.android.systemui.statusbar.tv.notifications.TvNotificationHandler; import javax.inject.Named; @@ -109,6 +112,15 @@ public abstract class TvSystemUIModule { return bC; } + @Provides + @SysUISingleton + static SensorPrivacyController provideSensorPrivacyController( + SensorPrivacyManager sensorPrivacyManager) { + SensorPrivacyController spC = new SensorPrivacyControllerImpl(sensorPrivacyManager); + spC.init(); + return spC; + } + @Binds @SysUISingleton abstract QSFactory bindQSFactory(QSFactoryImpl qsFactoryImpl); diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java index 9ba71dc5f4f7..e99bb245a2e0 100644 --- a/services/core/java/com/android/server/SensorPrivacyService.java +++ b/services/core/java/com/android/server/SensorPrivacyService.java @@ -283,11 +283,16 @@ public final class SensorPrivacyService extends SystemService { mIndividualEnabled.put(userId, userIndividualEnabled); if (!enable) { - // Remove any notifications prompting the user to disable sensory privacy - NotificationManager notificationManager = - mContext.getSystemService(NotificationManager.class); - - notificationManager.cancel(sensor); + long token = Binder.clearCallingIdentity(); + try { + // Remove any notifications prompting the user to disable sensory privacy + NotificationManager notificationManager = + mContext.getSystemService(NotificationManager.class); + + notificationManager.cancel(sensor); + } finally { + Binder.restoreCallingIdentity(token); + } } persistSensorPrivacyState(); } |