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

Commit 31b044ed authored by josephpv's avatar josephpv
Browse files

Prompt user to Setup a device lock if not set

This add below changes on selecting private space setting:
1. Prompt user to setup device lock if not already set
2. If device lock is set authenticate user first before displaying private space settings page

Screenshot - https://screenshot.googleplex.com/4SrYHbBMJfVuoRy.png
https://screenshot.googleplex.com/6vNWm7Lg83vfnH8.png
RecordingLink - https://drive.google.com/file/d/1r4zb3ILPRqwvP5tlwfjQ9GgnDAW4vZg6/view?usp=drive_link

Bug: 289016927
Test: atest PrivateSpaceSettingsAuthenticatorTest , atest SecuritySettingsTest
Change-Id: I0e5dfb30213843c0dec60a17d01c30cd91db89b0
parent 852ec4e2
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -4986,6 +4986,10 @@
            </intent-filter>
        </provider>

        <activity android:name=".privatespace.PrivateSpaceAuthenticationActivity"
                  android:theme="@*android:style/Theme.DeviceDefault.Settings.Dialog.NoActionBar"
                  android:exported="false"/>

        <activity-alias android:name="UsageStatsActivity"
                        android:exported="true"
                        android:label="@string/testing_usage_stats"
+8 −0
Original line number Diff line number Diff line
@@ -1215,6 +1215,14 @@
    <string name="private_space_deleted">Private Space successfully deleted</string>
    <!-- Toast to show when the private space could not be deleted. [CHAR LIMIT=NONE] -->
    <string name="private_space_delete_failed">Private Space could not be deleted</string>
    <!-- Title of the Alert Dialog when no screen lock is set [CHAR LIMIT=30] -->
    <string name="no_device_lock_title">Set a screen lock</string>
    <!-- Summary of the alert when no screen lock is set [CHAR LIMIT=60] -->
    <string name="no_device_lock_summary">To use Private Space, set a screen lock on this device.</string>
    <!-- Action label for dialog when no screen lock is set [CHAR LIMIT=30] -->
    <string name="no_device_lock_action_label">Set screen lock</string>
    <!-- Action label to cancel Alert dialog when no screen lock is set [CHAR LIMIT=30] -->
    <string name="no_device_lock_cancel">Cancel</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>
+152 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD;

import android.app.AlertDialog;
import android.app.KeyguardManager;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Flags;
import android.util.Log;

import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentActivity;

import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.core.SubSettingLauncher;
import com.android.settingslib.transition.SettingsTransitionHelper;

import com.google.android.setupdesign.util.ThemeHelper;

/**
 * Prompts user to set a device lock if not set with an alert dialog.
 * If a lock is already set then first authenticates user before displaying private space settings
 * page.
 */
public class PrivateSpaceAuthenticationActivity extends FragmentActivity {
    private static final String TAG = "PrivateSpaceAuthCheck";
    private PrivateSpaceMaintainer mPrivateSpaceMaintainer;
    private KeyguardManager mKeyguardManager;

    private final ActivityResultLauncher<Intent> mSetDeviceLock =
            registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
                    this::onSetDeviceLockResult);
    private final ActivityResultLauncher<Intent> mVerifyDeviceLock =
            registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
                    this::onVerifyDeviceLock);

    static class Injector {
        PrivateSpaceMaintainer injectPrivateSpaceMaintainer(Context context) {
            return PrivateSpaceMaintainer.getInstance(context);
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (Flags.allowPrivateProfile()) {
            ThemeHelper.trySetDynamicColor(this);
            mPrivateSpaceMaintainer = new Injector().injectPrivateSpaceMaintainer(
                    getApplicationContext());
            if (getKeyguardManager().isDeviceSecure()) {
                if (savedInstanceState == null) {
                    Intent credentialIntent =
                            mPrivateSpaceMaintainer.getPrivateProfileLockCredentialIntent();
                    if (credentialIntent != null) {
                        mVerifyDeviceLock.launch(credentialIntent);
                    } else {
                        Log.e(TAG, "verifyCredentialIntent is null even though device lock is set");
                        finish();
                    }
                }
            } else {
                promptToSetDeviceLock();
            }
        } else {
            Log.w(TAG, "allowPrivateProfile flag is Off!");
            finish();
        }
    }

    /** Show private space settings page on device lock authentications */
    @VisibleForTesting
    public void onLockAuthentication(Context context) {
        new SubSettingLauncher(context)
                        .setDestination(PrivateSpaceDashboardFragment.class.getName())
                        .setTransitionType(
                                SettingsTransitionHelper.TransitionType.TRANSITION_SLIDE)
                        .setSourceMetricsCategory(SettingsEnums.PRIVATE_SPACE_SETTINGS)
                        .launch();
    }

    @VisibleForTesting
    public void setPrivateSpaceMaintainer(Injector injector) {
        mPrivateSpaceMaintainer = injector.injectPrivateSpaceMaintainer(getApplicationContext());
    }

    private void promptToSetDeviceLock() {
        new AlertDialog.Builder(this)
                .setTitle(R.string.no_device_lock_title)
                .setMessage(R.string.no_device_lock_summary)
                .setPositiveButton(
                        R.string.no_device_lock_action_label,
                        (DialogInterface dialog, int which) -> {
                            mSetDeviceLock.launch(new Intent(ACTION_SET_NEW_PASSWORD));
                        })
                .setNegativeButton(
                        R.string.no_device_lock_cancel,
                        (DialogInterface dialog, int which) -> finish())
                .setOnCancelListener(
                        (DialogInterface dialog) -> {
                            finish();
                        })
                .show();
    }

    private KeyguardManager getKeyguardManager() {
        if (mKeyguardManager == null) {
            mKeyguardManager = getSystemService(KeyguardManager.class);
        }
        return  mKeyguardManager;
    }

    private void onSetDeviceLockResult(@Nullable ActivityResult result) {
        if (result != null) {
            if (getKeyguardManager().isDeviceSecure()) {
                onLockAuthentication(this);
            }
            finish();
        }
    }

    private void onVerifyDeviceLock(@Nullable ActivityResult result) {
        if (result != null && result.getResultCode() == RESULT_OK) {
            onLockAuthentication(this);
        }
        finish();
    }
}
+36 −0
Original line number Diff line number Diff line
@@ -20,7 +20,9 @@ import static android.os.UserManager.USER_TYPE_PROFILE_PRIVATE;

import android.app.ActivityManager;
import android.app.IActivityManager;
import android.app.KeyguardManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.UserInfo;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -28,6 +30,8 @@ import android.os.UserManager;
import android.util.ArraySet;
import android.util.Log;

import androidx.annotation.Nullable;

import com.android.internal.annotations.GuardedBy;

import java.util.List;
@@ -43,6 +47,7 @@ public class PrivateSpaceMaintainer {
    private final UserManager mUserManager;
    @GuardedBy("this")
    private UserHandle mUserHandle;
    private final KeyguardManager mKeyguardManager;

    public enum ErrorDeletingPrivateSpace {
            DELETE_PS_ERROR_NONE,
@@ -140,6 +145,23 @@ public class PrivateSpaceMaintainer {
        return mUserManager.isQuietModeEnabled(mUserHandle);
    }

    /**
     * Returns an intent to prompt the user to confirm private profile credentials if it is set
     * otherwise returns intent to confirm device credentials.
     */
    @Nullable
    public synchronized Intent getPrivateProfileLockCredentialIntent() {
        //TODO(b/307281644): To replace with check for doesPrivateSpaceExist() method once Auth
        // changes are merged.
        if (isPrivateProfileLockSet()) {
            return mKeyguardManager.createConfirmDeviceCredentialIntent(
                    /* title= */ null,  /* description= */null, mUserHandle.getIdentifier());
        }
        // TODO(b/304796434) Need to try changing this intent to use BiometricPrompt
        return mKeyguardManager.createConfirmDeviceCredentialIntent(
                /* title= */ null, /* description= */ null);
    }

    /** Returns the instance of {@link PrivateSpaceMaintainer} */
    public static synchronized PrivateSpaceMaintainer getInstance(Context context) {
        if (sPrivateSpaceMaintainer == null) {
@@ -151,5 +173,19 @@ public class PrivateSpaceMaintainer {
    private PrivateSpaceMaintainer(Context context) {
        mContext = context.getApplicationContext();
        mUserManager = mContext.getSystemService(UserManager.class);
        mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
    }


    // 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
     * separate profile lock.
     */
    @GuardedBy("this")
    private boolean isPrivateProfileLockSet() {
        return doesPrivateSpaceExist()
                && mKeyguardManager.isDeviceSecure(mUserHandle.getIdentifier());
    }
}
+4 −10
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@
package com.android.settings.privatespace;

import android.app.PendingIntent;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.Intent;
import android.os.Flags;
@@ -28,9 +27,7 @@ import android.safetycenter.SafetySourceStatus;
import android.util.Log;

import com.android.settings.R;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.safetycenter.SafetyCenterManagerWrapper;
import com.android.settingslib.transition.SettingsTransitionHelper;

/** Private Space safety source for the Safety Center */
public final class PrivateSpaceSafetySource {
@@ -86,18 +83,15 @@ public final class PrivateSpaceSafetySource {
    }

    private static PendingIntent getPendingIntentForPsDashboard(Context context) {
        Intent privateSpaceDashboardIntent = new SubSettingLauncher(context)
                .setDestination(PrivateSpaceDashboardFragment.class.getName())
                .setTransitionType(SettingsTransitionHelper.TransitionType.TRANSITION_SLIDE)
                .setSourceMetricsCategory(SettingsEnums.PRIVATE_SPACE_SETTINGS)
                .toIntent()
        Intent privateSpaceAuthenticationIntent =
                new Intent(context, PrivateSpaceAuthenticationActivity.class)
                        .setIdentifier(SAFETY_SOURCE_ID);

        return PendingIntent
                .getActivity(
                        context,
                        /* requestCode */ 0,
                        privateSpaceDashboardIntent,
                        privateSpaceAuthenticationIntent,
                        PendingIntent.FLAG_IMMUTABLE);
    }
}
Loading