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

Commit 75ada354 authored by Olivier Nshimiye's avatar Olivier Nshimiye Committed by Android (Google) Code Review
Browse files

Merge "Add a toggle for enabling/disabling sensitive lockscreen notifications...

Merge "Add a toggle for enabling/disabling sensitive lockscreen notifications for Private Space" into main
parents f515a0a4 baecaee2
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -1372,6 +1372,12 @@
    <string name="private_space_choose_your_password_header">Set a password for your private space</string>
    <!-- Header for private space choose your pattern screen [CHAR LIMIT=40] -->
    <string name="private_space_choose_your_pattern_header">Set a pattern for your private space</string>
    <!-- Header for private space apps and notifications section [CHAR LIMIT=40] -->
    <string name="private_space_apps_and_notifications_header">Apps and notifications</string>
    <!-- Title for private space sensitive notifications toggle [CHAR LIMIT=80] -->
    <string name="private_space_notifications_title">Sensitive notifications on lock screen</string>
    <!-- Summary description for private space sensitive notifications toggle [CHAR LIMIT=200] -->
    <string name="private_space_sensitive_notifications_description">Show sensitive content when private space is unlocked</string>
    <!-- Text shown when "Add fingerprint" button is disabled -->
    <string name="fingerprint_add_max">You can add up to <xliff:g id="count" example="5">%d</xliff:g> fingerprints</string>
+11 −0
Original line number Diff line number Diff line
@@ -59,6 +59,17 @@

    </PreferenceCategory>

    <PreferenceCategory
        android:title="@string/private_space_apps_and_notifications_header">

        <com.android.settingslib.RestrictedSwitchPreference
            android:key="private_space_sensitive_notifications"
            android:title="@string/private_space_notifications_title"
            android:summary="@string/private_space_sensitive_notifications_description"
            settings:controller="com.android.settings.privatespace.HidePrivateSpaceSensitiveNotificationsController" />

    </PreferenceCategory>

    <PreferenceCategory
        android:title="@string/private_space_category_system">

+105 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.privatespace;

import static android.provider.Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS;

import android.content.Context;
import android.os.UserHandle;
import android.provider.Settings;

import androidx.annotation.NonNull;

import com.android.settings.core.TogglePreferenceController;

import java.util.Objects;

/**
 * A controller object for sensitive notifications in Private Space settings page.
 */
public class HidePrivateSpaceSensitiveNotificationsController extends TogglePreferenceController {
    private final PrivateSpaceMaintainer mPrivateSpaceMaintainer;
    private final UserHandle mPrivateProfileId;
    public static final int ENABLED = 1;
    public static final int DISABLED = 0;
    private static final int DEVICE_SENSITIVE_NOTIFICATIONS_DEFAULT = ENABLED;
    private static final int DEVICE_LOCK_SCREEN_NOTIFICATIONS_DEFAULT = ENABLED;
    private static final int PRIVATE_SPACE_SENSITIVE_NOTIFICATIONS_DEFAULT = DISABLED;

    public HidePrivateSpaceSensitiveNotificationsController(@NonNull Context context,
            @NonNull String preferenceKey) {
        super(context, preferenceKey);
        mPrivateSpaceMaintainer = PrivateSpaceMaintainer.getInstance(context);
        mPrivateProfileId = Objects.requireNonNull(
                mPrivateSpaceMaintainer.getPrivateProfileHandle());
    }

    @Override
    public int getAvailabilityStatus() {
        if (!android.os.Flags.allowPrivateProfile()
                || !android.multiuser.Flags.enablePsSensitiveNotificationsToggle()
                || !mPrivateSpaceMaintainer.doesPrivateSpaceExist()) {
            return UNSUPPORTED_ON_DEVICE;
        }
        if (!getLockscreenNotificationsEnabled(mContext)
                || !getLockscreenSensitiveNotificationsEnabledOnDevice(mContext)) {
            return DISABLED_DEPENDENT_SETTING;
        }
        return AVAILABLE;
    }

    @Override
    public boolean isChecked() {
        return Settings.Secure.getIntForUser(mContext.getContentResolver(),
                LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
                PRIVATE_SPACE_SENSITIVE_NOTIFICATIONS_DEFAULT, mPrivateProfileId.getIdentifier())
                != DISABLED;
    }

    @Override
    public boolean setChecked(boolean isChecked) {
        Settings.Secure.putIntForUser(mContext.getContentResolver(),
                Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
                isChecked ? ENABLED : DISABLED, mPrivateProfileId.getIdentifier());
        return true;
    }

    @Override
    public int getSliceHighlightMenuRes() {
        return 0;
    }

    /**
     * If notifications are disabled on the device, the toggle for private space sensitive
     * notifications should be unavailable.
     */
    private static boolean getLockscreenNotificationsEnabled(Context context) {
        return Settings.Secure.getInt(context.getContentResolver(),
                Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
                DEVICE_LOCK_SCREEN_NOTIFICATIONS_DEFAULT) != DISABLED;
    }

    /**
     * If sensitive notifications are hidden on the device, they should be hidden for private space
     * also.
     */
    private static boolean getLockscreenSensitiveNotificationsEnabledOnDevice(Context context) {
        return Settings.Secure.getInt(context.getContentResolver(),
                Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
                DEVICE_SENSITIVE_NOTIFICATIONS_DEFAULT) != DISABLED;
    }
}
+19 −5
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ import com.android.internal.annotations.GuardedBy;
import java.util.List;

// TODO(b/293569406): Update the javadoc when we have the setup flow in place to create PS

/** A class to help with the creation / deletion of Private Space */
public class PrivateSpaceMaintainer {
    private static final String TAG = "PrivateSpaceMaintainer";
@@ -117,7 +118,8 @@ public class PrivateSpaceMaintainer {
        return true;
    }

    /** Returns the {@link ErrorDeletingPrivateSpace} enum representing the result of operation.
    /**
     * Returns the {@link ErrorDeletingPrivateSpace} enum representing the result of operation.
     *
     * <p> This method should be used ONLY by the delete-PS controller in the PS Settings page.
     */
@@ -212,6 +214,7 @@ public class PrivateSpaceMaintainer {


    // TODO(b/307281644): Remove this method once new auth change is merged

    /**
     * Returns true if private space exists and a separate private profile lock is set
     * otherwise false when the private space does not exit or exists but does not have a
@@ -290,9 +293,20 @@ public class PrivateSpaceMaintainer {
        return false;
    }

    @GuardedBy("this")
    private void resetPrivateSpaceSettings() {
        setHidePrivateSpaceEntryPointSetting(HIDE_PRIVATE_SPACE_ENTRY_POINT_DISABLED_VAL);
        setPrivateSpaceAutoLockSetting(PRIVATE_SPACE_AUTO_LOCK_DEFAULT_VAL);
        setPrivateSpaceSensitiveNotificationsDefaultValue();
    }

    /** Sets private space sensitive notifications hidden on lockscreen by default */
    @GuardedBy("this")
    private void setPrivateSpaceSensitiveNotificationsDefaultValue() {
        Settings.Secure.putIntForUser(mContext.getContentResolver(),
                Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
                HidePrivateSpaceSensitiveNotificationsController.DISABLED,
                mUserHandle.getIdentifier());
    }

    /**
+162 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.privatespace;

import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING;
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;

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

import static org.junit.Assume.assumeTrue;
import static org.mockito.Mockito.spy;

import android.content.ContentResolver;
import android.content.Context;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;

import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;

/**
 * Tests for HidePrivateSpaceSensitiveNotificationsController.
 * Run as {@code atest SettingsUnitTests:HidePrivateSpaceSensitiveNotificationsControllerTest}
 */
@RunWith(AndroidJUnit4.class)
public class HidePrivateSpaceSensitiveNotificationsControllerTest {
    @Rule
    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();

    private Context mContext;
    private HidePrivateSpaceSensitiveNotificationsController
            mHidePrivateSpaceSensitiveNotificationsController;
    @Mock
    private ContentResolver mContentResolver;
    private int mOriginalDeviceSensitiveNotifValue;
    private int mOriginalDeviceNotifValue;
    private int mOriginalPsSensitiveNotifValue;
    private int mPrivateProfileId;

    @Before
    public void setUp() {
        mContext = spy(ApplicationProvider.getApplicationContext());
        mContentResolver = mContext.getContentResolver();
        assumeTrue(PrivateSpaceMaintainer.getInstance(mContext).doesPrivateSpaceExist());

        mSetFlagsRule.enableFlags(
                android.multiuser.Flags.FLAG_ENABLE_PS_SENSITIVE_NOTIFICATIONS_TOGGLE);
        mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE);

        mPrivateProfileId = PrivateSpaceMaintainer.getInstance(
                mContext).getPrivateProfileHandle().getIdentifier();

        mOriginalDeviceSensitiveNotifValue = Settings.Secure.getInt(mContentResolver,
                Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 1);
        mOriginalDeviceNotifValue = Settings.Secure.getInt(mContentResolver,
                Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1);
        mOriginalPsSensitiveNotifValue = Settings.Secure.getIntForUser(mContentResolver,
                Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, mPrivateProfileId);

        final String preferenceKey = "private_space_sensitive_notifications";
        mHidePrivateSpaceSensitiveNotificationsController =
                new HidePrivateSpaceSensitiveNotificationsController(mContext, preferenceKey);
    }

    @After
    public void tearDown() {
        Settings.Secure.putInt(mContentResolver,
                Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
                mOriginalDeviceSensitiveNotifValue
        );
        Settings.Secure.putInt(mContext.getContentResolver(),
                Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, mOriginalDeviceNotifValue);
        Settings.Secure.putIntForUser(mContext.getContentResolver(),
                Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
                mOriginalPsSensitiveNotifValue, mPrivateProfileId);
    }

    /**
     * Tests that the controller is unavailable if lockscreen sensitive notifications are disabled
     * on the device.
     */
    @Test
    public void getAvailabilityStatus_lockScreenPrivateNotificationsOff() {
        Settings.Secure.putInt(mContext.getContentResolver(),
                Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
        assertThat(mHidePrivateSpaceSensitiveNotificationsController.getAvailabilityStatus())
                .isEqualTo(DISABLED_DEPENDENT_SETTING);
    }

    /**
     * Tests that the controller is unavailable if lockscreen notifications are disabled on the
     * device.
     */
    @Test
    public void getAvailabilityStatus_lockScreenNotificationsOff() {
        Settings.Secure.putInt(mContext.getContentResolver(),
                Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0);
        assertThat(mHidePrivateSpaceSensitiveNotificationsController.getAvailabilityStatus())
                .isEqualTo(DISABLED_DEPENDENT_SETTING);
    }

    /**
     * Tests that the controller is available if lockscreen notifications and lockscreen private
     * notifications are enabled on the device.
     */
    @Test
    public void getAvailabilityStatus_returnAvailable() {
        Settings.Secure.putInt(mContext.getContentResolver(),
                Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1);
        Settings.Secure.putInt(mContext.getContentResolver(),
                Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 1);
        assertThat(mHidePrivateSpaceSensitiveNotificationsController.getAvailabilityStatus())
                .isEqualTo(AVAILABLE);
    }


    /**
     * Tests that toggle is not available if the flag for this feature and MVP flag are disabled.
     */
    @Test
    public void getAvailabilityStatus_flagDisabled() {
        mSetFlagsRule.disableFlags(
                android.multiuser.Flags.FLAG_ENABLE_PS_SENSITIVE_NOTIFICATIONS_TOGGLE);
        mSetFlagsRule.disableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE);
        Settings.Secure.putInt(mContext.getContentResolver(),
                Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1);
        Settings.Secure.putInt(mContext.getContentResolver(),
                Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 1);
        assertThat(mHidePrivateSpaceSensitiveNotificationsController.getAvailabilityStatus())
                .isEqualTo(UNSUPPORTED_ON_DEVICE);
    }

    @Test
    public void testSetChecked() {
        assertThat(mHidePrivateSpaceSensitiveNotificationsController.setChecked(true)).isTrue();
        assertThat(mHidePrivateSpaceSensitiveNotificationsController.isChecked()).isEqualTo(true);
        assertThat(mHidePrivateSpaceSensitiveNotificationsController.setChecked(false)).isTrue();
        assertThat(mHidePrivateSpaceSensitiveNotificationsController.isChecked()).isEqualTo(false);
    }
}
Loading