Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 473fffa3 authored by Abel Tesfaye's avatar Abel Tesfaye Committed by Android (Google) Code Review
Browse files

Merge "Add warning message when camera privacy lock is enabled for screen...

Merge "Add warning message when camera privacy lock is enabled for screen attention settings" into sc-dev
parents 1282ff20 5d643839
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -2969,6 +2969,8 @@
    <string name="auto_rotate_camera_lock_title">Camera is locked</string>
    <!-- Description feature's privacy sensitive details to make sure users understand what feature users, what it saves/sends etc [CHAR LIMIT=NONE]-->
    <string name="auto_rotate_camera_lock_summary">Camera must be unlocked for Face Detection</string>
    <!-- screen_timeout settings screen, summary about the camera being disabled [CHAR LIMIT=NONE]-->
    <string name="adaptive_sleep_camera_lock_summary">Camera must be unlocked for Screen Attention</string>
    <!-- auto_rotate settings screen, title about the required permission is missing [CHAR LIMIT=NONE]-->
    <string name="auto_rotate_summary_no_permission">Camera access is required for Face Detection. Tap to manage permissions for Device Personalization Services</string>
    <!-- auto_rotate settings screen, text for the camera permission button [CHAR LIMIT=NONE]-->
+75 −0
Original line number Diff line number Diff line
/*
 * 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.
 */

package com.android.settings.display;

import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;

import android.content.Context;
import android.hardware.SensorPrivacyManager;

import androidx.preference.PreferenceScreen;

import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import com.android.settingslib.widget.BannerMessagePreference;

/**
 * The controller of Screen attention's camera disabled warning preference.
 * The preference appears when the camera access is disabled for Screen Attention feature.
 */
public class AdaptiveSleepCameraStatePreferenceController {
    @VisibleForTesting
    final BannerMessagePreference mPreference;
    private final SensorPrivacyManager mPrivacyManager;

    public AdaptiveSleepCameraStatePreferenceController(Context context) {
        mPreference = new BannerMessagePreference(context);
        mPreference.setTitle(R.string.auto_rotate_camera_lock_title);
        mPreference.setSummary(R.string.adaptive_sleep_camera_lock_summary);
        mPreference.setPositiveButtonText(R.string.allow);
        mPrivacyManager = SensorPrivacyManager.getInstance(context);
        mPrivacyManager.addSensorPrivacyListener(CAMERA,
                enabled -> updateVisibility());
        mPreference.setPositiveButtonOnClickListener(p -> {
            mPrivacyManager.setSensorPrivacy(CAMERA, false);
        });
    }

    /**
     * Adds the controlled preference to the provided preference screen.
     */
    public void addToScreen(PreferenceScreen screen) {
        screen.addPreference(mPreference);
        updateVisibility();
    }

    /**
     * Need this because all controller tests use RoboElectric. No easy way to mock this service,
     * so we mock the call we need
     */
    @VisibleForTesting
    boolean isCameraLocked() {
        return mPrivacyManager.isSensorPrivacyEnabled(CAMERA);
    }

    /**
     * Refreshes the visibility of the preference.
     */
    public void updateVisibility() {
        mPreference.setVisible(isCameraLocked());
    }
}
+18 −3
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.settings.display;

import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;

import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE;
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;

@@ -25,6 +27,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.hardware.SensorPrivacyManager;
import android.os.UserManager;
import android.provider.Settings;
import android.service.attention.AttentionService;
@@ -45,6 +48,7 @@ import com.google.common.annotations.VisibleForTesting;
public class AdaptiveSleepPreferenceController {
    public static final String PREFERENCE_KEY = "adaptive_sleep";
    private static final int DEFAULT_VALUE = 0;
    private final SensorPrivacyManager mPrivacyManager;
    private RestrictionUtils mRestrictionUtils;
    private PackageManager mPackageManager;
    private Context mContext;
@@ -57,6 +61,7 @@ public class AdaptiveSleepPreferenceController {
        mContext = context;
        mRestrictionUtils = restrictionUtils;
        mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
        mPrivacyManager = SensorPrivacyManager.getInstance(context);
        mPreference = new RestrictedSwitchPreference(context);
        mPreference.setTitle(R.string.adaptive_sleep_title);
        mPreference.setSummary(R.string.adaptive_sleep_description);
@@ -94,17 +99,27 @@ public class AdaptiveSleepPreferenceController {
        if (enforcedAdmin != null) {
            mPreference.setDisabledByAdmin(enforcedAdmin);
        } else {
            mPreference.setEnabled(hasSufficientPermission(mPackageManager));
            mPreference.setEnabled(hasSufficientPermission(mPackageManager) && !isCameraLocked());
        }
    }

    @VisibleForTesting
    boolean isChecked() {
        return hasSufficientPermission(mContext.getPackageManager()) && Settings.Secure.getInt(
                mContext.getContentResolver(), Settings.Secure.ADAPTIVE_SLEEP, DEFAULT_VALUE)
        return hasSufficientPermission(mContext.getPackageManager()) && !isCameraLocked()
                && Settings.Secure.getInt(mContext.getContentResolver(),
                Settings.Secure.ADAPTIVE_SLEEP, DEFAULT_VALUE)
                != DEFAULT_VALUE;
    }

    /**
     * Need this because all controller tests use RoboElectric. No easy way to mock this service,
     * so we mock the call we need
     */
    @VisibleForTesting
    boolean isCameraLocked() {
        return mPrivacyManager.isSensorPrivacyEnabled(CAMERA);
    }

    public static int isControllerAvailable(Context context) {
        return context.getResources().getBoolean(
                com.android.internal.R.bool.config_adaptive_sleep_available)
+16 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.settings.display;

import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;

import android.app.admin.DevicePolicyManager;
@@ -23,6 +24,7 @@ import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.hardware.SensorPrivacyManager;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.SpannableString;
@@ -70,6 +72,7 @@ public class ScreenTimeoutSettings extends RadioButtonPickerFragment implements
    private CharSequence[] mInitialValues;
    private FooterPreference mPrivacyPreference;
    private MetricsFeatureProvider mMetricsFeatureProvider;
    private SensorPrivacyManager mPrivacyManager;

    @VisibleForTesting
    RestrictedLockUtils.EnforcedAdmin mAdmin;
@@ -79,6 +82,9 @@ public class ScreenTimeoutSettings extends RadioButtonPickerFragment implements
    @VisibleForTesting
    AdaptiveSleepPermissionPreferenceController mAdaptiveSleepPermissionController;

    @VisibleForTesting
    AdaptiveSleepCameraStatePreferenceController mAdaptiveSleepCameraStatePreferenceController;

    @VisibleForTesting
    AdaptiveSleepPreferenceController mAdaptiveSleepController;

@@ -96,11 +102,18 @@ public class ScreenTimeoutSettings extends RadioButtonPickerFragment implements
        mAdaptiveSleepController = new AdaptiveSleepPreferenceController(context);
        mAdaptiveSleepPermissionController = new AdaptiveSleepPermissionPreferenceController(
                context);
        mAdaptiveSleepCameraStatePreferenceController =
                new AdaptiveSleepCameraStatePreferenceController(context);
        mPrivacyPreference = new FooterPreference(context);
        mPrivacyPreference.setIcon(R.drawable.ic_privacy_shield_24dp);
        mPrivacyPreference.setTitle(R.string.adaptive_sleep_privacy);
        mPrivacyPreference.setSelectable(false);
        mPrivacyPreference.setLayoutResource(R.layout.preference_footer);
        mPrivacyManager = SensorPrivacyManager.getInstance(context);
        mPrivacyManager.addSensorPrivacyListener(CAMERA,
                enabled -> {
                    mAdaptiveSleepController.updatePreference();
                });
    }

    @Override
@@ -124,6 +137,7 @@ public class ScreenTimeoutSettings extends RadioButtonPickerFragment implements
    public void onStart() {
        super.onStart();
        mAdaptiveSleepPermissionController.updateVisibility();
        mAdaptiveSleepCameraStatePreferenceController.updateVisibility();
        mAdaptiveSleepController.updatePreference();
    }

@@ -147,6 +161,7 @@ public class ScreenTimeoutSettings extends RadioButtonPickerFragment implements

        if (isScreenAttentionAvailable(getContext())) {
            mAdaptiveSleepPermissionController.addToScreen(screen);
            mAdaptiveSleepCameraStatePreferenceController.addToScreen(screen);
            mAdaptiveSleepController.addToScreen(screen);
            screen.addPreference(mPrivacyPreference);
        }
+83 −0
Original line number Diff line number Diff line
/*
 * 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.
 */

package com.android.settings.display;

import static androidx.test.core.app.ApplicationProvider.getApplicationContext;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;

import android.content.Context;
import android.content.pm.PackageManager;

import androidx.preference.PreferenceScreen;

import com.android.settings.testutils.shadow.ShadowSensorPrivacyManager;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;

@RunWith(RobolectricTestRunner.class)
@Config(shadows = ShadowSensorPrivacyManager.class)
public class AdaptiveSleepCameraStatePreferenceControllerTest {
    private Context mContext;
    private AdaptiveSleepCameraStatePreferenceController mController;

    @Mock
    private PackageManager mPackageManager;
    @Mock
    private PreferenceScreen mScreen;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        mContext = spy(getApplicationContext());

        doReturn(mPackageManager).when(mContext).getPackageManager();
        when(mPackageManager.getAttentionServicePackageName()).thenReturn("some.package");
        when(mPackageManager.checkPermission(any(), any())).thenReturn(
                PackageManager.PERMISSION_GRANTED);

        mController = new AdaptiveSleepCameraStatePreferenceController(mContext);
        when(mController.isCameraLocked()).thenReturn(false);
    }

    @Test
    public void addToScreen_normalCase_hidePreference() {
        mController.addToScreen(mScreen);

        assertThat(mController.mPreference.isVisible()).isFalse();
    }

    @Test
    public void addToScreen_cameraIsLocked_showPreference() {
        when(mController.isCameraLocked()).thenReturn(true);

        mController.addToScreen(mScreen);

        assertThat(mController.mPreference.isVisible()).isTrue();
    }
}
Loading