chromium/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordReauthenticationFragment.java

// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.chrome.browser.password_manager.settings;

import static org.chromium.chrome.browser.password_manager.settings.PasswordAccessReauthenticationHelper.SETTINGS_REAUTHENTICATION_HISTOGRAM;

import android.app.Activity;
import android.app.KeyguardManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;

import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;

import org.chromium.base.metrics.RecordHistogram;
import org.chromium.chrome.browser.device_reauth.ReauthResult;

/** Show the lock screen confirmation and lock the screen. */
public class PasswordReauthenticationFragment extends Fragment {
    /**
     * The key for the description argument, which is used to retrieve an explanation of the
     * reauthentication prompt to the user.
     */
    public static final String DESCRIPTION_ID = "description";

    /**
     * The key for the scope, with values from {@link ReauthenticationManager.ReauthScope}. The
     * scope enum value corresponds to what is indicated in the description message for the user
     * (e.g., if the message mentions "export passwords", the scope should be BULK, but for "view
     * password" it should be ONE_AT_A_TIME).
     */
    public static final String SCOPE_ID = "scope";

    protected static final int CONFIRM_DEVICE_CREDENTIAL_REQUEST_CODE = 2;

    protected static final String HAS_BEEN_SUSPENDED_KEY = "has_been_suspended";

    private static boolean sPreventLockDevice;

    private FragmentManager mFragmentManager;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mFragmentManager = getFragmentManager();
        boolean isFirstTime = savedInstanceState == null;
        if (!sPreventLockDevice && isFirstTime) {
            lockDevice();
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        // On Android L, an empty |outState| would degrade to null in |onCreate|, making Chrome
        // unable to distinguish the first time launch. Insert a value into |outState| to prevent
        // that.
        outState.putBoolean(HAS_BEEN_SUSPENDED_KEY, true);
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == CONFIRM_DEVICE_CREDENTIAL_REQUEST_CODE) {
            if (resultCode == Activity.RESULT_OK) {
                RecordHistogram.recordEnumeratedHistogram(
                        SETTINGS_REAUTHENTICATION_HISTOGRAM,
                        ReauthResult.SUCCESS,
                        ReauthResult.MAX_VALUE + 1);
                ReauthenticationManager.recordLastReauth(
                        System.currentTimeMillis(), getArguments().getInt(SCOPE_ID));
            } else {
                RecordHistogram.recordEnumeratedHistogram(
                        SETTINGS_REAUTHENTICATION_HISTOGRAM,
                        ReauthResult.FAILURE,
                        ReauthResult.MAX_VALUE + 1);
                ReauthenticationManager.resetLastReauth();
            }
            mFragmentManager.popBackStack();
        }
    }

    /** Prevent calling the {@link #lockDevice} method in {@link #onCreate}. */
    public static void preventLockingForTesting() {
        sPreventLockDevice = true;
    }

    private void lockDevice() {
        KeyguardManager keyguardManager =
                (KeyguardManager) getActivity().getSystemService(Context.KEYGUARD_SERVICE);
        final int resourceId = getArguments().getInt(DESCRIPTION_ID, 0);
        // Forgetting to set the DESCRIPTION_ID is an error on the callsite.
        assert resourceId != 0;
        // Set title to null to use the system default title which is adapted to the particular type
        // of device lock which the user set up.
        Intent intent =
                keyguardManager.createConfirmDeviceCredentialIntent(null, getString(resourceId));
        if (intent != null) {
            startActivityForResult(intent, CONFIRM_DEVICE_CREDENTIAL_REQUEST_CODE);
            return;
        }
        mFragmentManager.popBackStackImmediate();
    }
}