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

Commit 4725fbe6 authored by Shawn Pearce's avatar Shawn Pearce Committed by Android (Google) Code Review
Browse files

Merge "Clean up info and callback architecture in KeyguardUpdateMonitor."

parents ea56e5ca bbf1a743
Loading
Loading
Loading
Loading
+22 −34
Original line number Diff line number Diff line
@@ -21,8 +21,7 @@ import com.android.internal.telephony.IccCardConstants;
import com.android.internal.widget.DigitalClock;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.TransportControlView;
import com.android.internal.policy.impl.KeyguardUpdateMonitor.InfoCallbackImpl;
import com.android.internal.policy.impl.KeyguardUpdateMonitor.SimStateCallback;
import com.android.internal.policy.impl.KeyguardUpdateMonitor.BatteryStatus;

import java.util.ArrayList;
import java.util.Date;
@@ -107,6 +106,8 @@ class KeyguardStatusViewManager implements OnClickListener {
    private CharSequence mSpn;
    protected int mPhoneState;
    private DigitalClock mDigitalClock;
    protected boolean mBatteryCharged;
    protected boolean mBatteryIsLow;

    private class TransientTextManager {
        private TextView mTextView;
@@ -198,8 +199,8 @@ class KeyguardStatusViewManager implements OnClickListener {

        mTransientTextManager = new TransientTextManager(mCarrierView);

        mUpdateMonitor.registerInfoCallback(mInfoCallback);
        mUpdateMonitor.registerSimStateCallback(mSimStateCallback);
        // Registering this callback immediately updates the battery state, among other things.
        mUpdateMonitor.registerCallback(mInfoCallback);

        resetStatusInfo();
        refreshDate();
@@ -287,7 +288,6 @@ class KeyguardStatusViewManager implements OnClickListener {
    public void onPause() {
        if (DEBUG) Log.v(TAG, "onPause()");
        mUpdateMonitor.removeCallback(mInfoCallback);
        mUpdateMonitor.removeCallback(mSimStateCallback);
    }

    /** {@inheritDoc} */
@@ -299,8 +299,7 @@ class KeyguardStatusViewManager implements OnClickListener {
            mDigitalClock.updateTime();
        }

        mUpdateMonitor.registerInfoCallback(mInfoCallback);
        mUpdateMonitor.registerSimStateCallback(mSimStateCallback);
        mUpdateMonitor.registerCallback(mInfoCallback);
        resetStatusInfo();
        // Issue the biometric unlock failure message in a centralized place
        // TODO: we either need to make the Face Unlock multiple failures string a more general
@@ -312,9 +311,6 @@ class KeyguardStatusViewManager implements OnClickListener {

    void resetStatusInfo() {
        mInstructionText = null;
        mShowingBatteryInfo = mUpdateMonitor.shouldShowBatteryInfo();
        mPluggedIn = mUpdateMonitor.isDevicePluggedIn();
        mBatteryLevel = mUpdateMonitor.getBatteryLevel();
        updateStatusLines(true);
    }

@@ -379,14 +375,11 @@ class KeyguardStatusViewManager implements OnClickListener {
        if (mShowingBatteryInfo) {
            // Battery status
            if (mPluggedIn) {
                // Charging or charged
                if (mUpdateMonitor.isDeviceCharged()) {
                    string = getContext().getString(R.string.lockscreen_charged);
                } else {
                    string = getContext().getString(R.string.lockscreen_plugged_in, mBatteryLevel);
                }
                // Charging, charged or waiting to charge.
                string = getContext().getString(mBatteryCharged ? R.string.lockscreen_charged
                        :R.string.lockscreen_plugged_in, mBatteryLevel);
                icon.value = CHARGING_ICON;
            } else if (mBatteryLevel < KeyguardUpdateMonitor.LOW_BATTERY_THRESHOLD) {
            } else if (mBatteryIsLow) {
                // Battery is low
                string = getContext().getString(R.string.lockscreen_low_battery);
                icon.value = BATTERY_LOW_ICON;
@@ -406,14 +399,11 @@ class KeyguardStatusViewManager implements OnClickListener {
        } else if (mShowingBatteryInfo) {
            // Battery status
            if (mPluggedIn) {
                // Charging or charged
                if (mUpdateMonitor.isDeviceCharged()) {
                    string = getContext().getString(R.string.lockscreen_charged);
                } else {
                    string = getContext().getString(R.string.lockscreen_plugged_in, mBatteryLevel);
                }
                // Charging, charged or waiting to charge.
                string = getContext().getString(mBatteryCharged ? R.string.lockscreen_charged
                        :R.string.lockscreen_plugged_in, mBatteryLevel);
                icon.value = CHARGING_ICON;
            } else if (mBatteryLevel < KeyguardUpdateMonitor.LOW_BATTERY_THRESHOLD) {
            } else if (mBatteryIsLow) {
                // Battery is low
                string = getContext().getString(R.string.lockscreen_low_battery);
                icon.value = BATTERY_LOW_ICON;
@@ -629,14 +619,15 @@ class KeyguardStatusViewManager implements OnClickListener {
        }
    }

    private InfoCallbackImpl mInfoCallback = new InfoCallbackImpl() {
    private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {

        @Override
        public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn,
                int batteryLevel) {
            mShowingBatteryInfo = showBatteryInfo;
            mPluggedIn = pluggedIn;
            mBatteryLevel = batteryLevel;
        public void onRefreshBatteryInfo(BatteryStatus status) {
            mShowingBatteryInfo = status.isPluggedIn() || status.isBatteryLow();
            mPluggedIn = status.isPluggedIn();
            mBatteryLevel = status.level;
            mBatteryCharged = status.isCharged();
            mBatteryIsLow = status.isBatteryLow();
            final MutableInt tmpIcon = new MutableInt(0);
            update(BATTERY_INFO, getAltTextMessage(tmpIcon));
        }
@@ -659,10 +650,7 @@ class KeyguardStatusViewManager implements OnClickListener {
            updateEmergencyCallButtonState(phoneState);
        }

    };

    private SimStateCallback mSimStateCallback = new SimStateCallback() {

        @Override
        public void onSimStateChanged(IccCardConstants.State simState) {
            updateCarrierStateWithSimStatus(simState);
        }
+238 −322

File changed.

Preview size limit exceeded, changes collapsed.

+97 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2012 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.internal.policy.impl;

import android.app.admin.DevicePolicyManager;
import android.media.AudioManager;

import com.android.internal.policy.impl.KeyguardUpdateMonitor.BatteryStatus;
import com.android.internal.telephony.IccCardConstants;

/**
 * Callback for general information relevant to lock screen.
 */
class KeyguardUpdateMonitorCallback {
    /**
     * Called when the battery status changes, e.g. when plugged in or unplugged, charge
     * level, etc. changes.
     *
     * @param status current battery status
     */
    void onRefreshBatteryInfo(BatteryStatus status) { }

    /**
     * Called once per minute or when the time changes.
     */
    void onTimeChanged() { }

    /**
     * Called when the carrier PLMN or SPN changes.
     *
     * @param plmn The operator name of the registered network.  May be null if it shouldn't
     *   be displayed.
     * @param spn The service provider name.  May be null if it shouldn't be displayed.
     */
    void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) { }

    /**
     * Called when the ringer mode changes.
     * @param state the current ringer state, as defined in
     * {@link AudioManager#RINGER_MODE_CHANGED_ACTION}
     */
    void onRingerModeChanged(int state) { }

    /**
     * Called when the phone state changes. String will be one of:
     * {@link TelephonyManager#EXTRA_STATE_IDLE}
     * {@link TelephonyManager@EXTRA_STATE_RINGING}
     * {@link TelephonyManager#EXTRA_STATE_OFFHOOK
     */
    void onPhoneStateChanged(int phoneState) { }

    /**
     * Called when visibility of lockscreen clock changes, such as when
     * obscured by a widget.
     */
    void onClockVisibilityChanged() { }

    /**
     * Called when the device becomes provisioned
     */
    void onDeviceProvisioned() { }

    /**
     * Called when the device policy changes.
     * See {@link DevicePolicyManager#ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED}
     */
    void onDevicePolicyManagerStateChanged() { }

    /**
     * Called when the user changes.
     */
    void onUserSwitched(int userId) { }

    /**
     * Called when the SIM state changes.
     * @param simState
     */
    void onSimStateChanged(IccCardConstants.State simState) { }

    /**
     * Called when a user is removed.
     */
    void onUserRemoved(int userId) { }
}
+101 −132
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@ package com.android.internal.policy.impl;

import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;

import com.android.internal.policy.impl.KeyguardUpdateMonitor.InfoCallbackImpl;
import com.android.internal.telephony.IccCardConstants;
import com.android.internal.widget.LockPatternUtils;

@@ -90,8 +89,7 @@ import android.view.WindowManagerPolicy;
 * directly to the keyguard UI is posted to a {@link Handler} to ensure it is taken on the UI
 * thread of the keyguard.
 */
public class KeyguardViewMediator implements KeyguardViewCallback,
        KeyguardUpdateMonitor.SimStateCallback {
public class KeyguardViewMediator implements KeyguardViewCallback {
    private static final int KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT = 30000;
    private final static boolean DEBUG = false;
    private final static boolean DBG_WAKE = false;
@@ -257,7 +255,38 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
     */
    private final float mLockSoundVolume;

    InfoCallbackImpl mInfoCallback = new InfoCallbackImpl() {
    KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {

        @Override
        public void onUserSwitched(int userId) {
            mLockPatternUtils.setCurrentUser(userId);
            synchronized (KeyguardViewMediator.this) {
                resetStateLocked();
            }
        }

        @Override
        public void onUserRemoved(int userId) {
            mLockPatternUtils.removeUser(userId);
        }

        @Override
        void onPhoneStateChanged(int phoneState) {
            synchronized (KeyguardViewMediator.this) {
                if (TelephonyManager.CALL_STATE_IDLE == phoneState  // call ending
                        && !mScreenOn                           // screen off
                        && mExternallyEnabled) {                // not disabled by any app

                    // note: this is a way to gracefully reenable the keyguard when the call
                    // ends and the screen is off without always reenabling the keyguard
                    // each time the screen turns off while in call (and having an occasional ugly
                    // flicker while turning back on the screen and disabling the keyguard again).
                    if (DEBUG) Log.d(TAG, "screen is off and call ended, let's make sure the "
                            + "keyguard is showing");
                    doKeyguardLocked();
                }
            }
        };

        @Override
        public void onClockVisibilityChanged() {
@@ -269,39 +298,85 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
            mContext.sendBroadcast(mUserPresentIntent);
        }

        @Override
        public void onSimStateChanged(IccCardConstants.State simState) {
            if (DEBUG) Log.d(TAG, "onSimStateChanged: " + simState);

            switch (simState) {
                case NOT_READY:
                case ABSENT:
                    // only force lock screen in case of missing sim if user hasn't
                    // gone through setup wizard
                    synchronized (this) {
                        if (!mUpdateMonitor.isDeviceProvisioned()) {
                            if (!isShowing()) {
                                if (DEBUG) Log.d(TAG, "ICC_ABSENT isn't showing,"
                                        + " we need to show the keyguard since the "
                                        + "device isn't provisioned yet.");
                                doKeyguardLocked();
                            } else {
                                resetStateLocked();
                            }
                        }
                    }
                    break;
                case PIN_REQUIRED:
                case PUK_REQUIRED:
                    synchronized (this) {
                        if (!isShowing()) {
                            if (DEBUG) Log.d(TAG, "INTENT_VALUE_ICC_LOCKED and keygaurd isn't "
                                    + "showing; need to show keyguard so user can enter sim pin");
                            doKeyguardLocked();
                        } else {
                            resetStateLocked();
                        }
                    }
                    break;
                case PERM_DISABLED:
                    synchronized (this) {
                        if (!isShowing()) {
                            if (DEBUG) Log.d(TAG, "PERM_DISABLED and "
                                  + "keygaurd isn't showing.");
                            doKeyguardLocked();
                        } else {
                            if (DEBUG) Log.d(TAG, "PERM_DISABLED, resetStateLocked to"
                                  + "show permanently disabled message in lockscreen.");
                            resetStateLocked();
                        }
                    }
                    break;
                case READY:
                    synchronized (this) {
                        if (isShowing()) {
                            resetStateLocked();
                        }
                    }
                    break;
            }
        }

    };

    public KeyguardViewMediator(Context context, PhoneWindowManager callback,
            LocalPowerManager powerManager) {
        mContext = context;

        mCallback = callback;
        mRealPowerManager = powerManager;
        mPM = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        mWakeLock = mPM.newWakeLock(
                PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP,
                "keyguard");
                PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "keyguard");
        mWakeLock.setReferenceCounted(false);
        mShowKeyguardWakeLock = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "show keyguard");
        mShowKeyguardWakeLock.setReferenceCounted(false);

        mWakeAndHandOff = mPM.newWakeLock(
                PowerManager.PARTIAL_WAKE_LOCK,
                "keyguardWakeAndHandOff");
        mWakeAndHandOff = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "keyguardWakeAndHandOff");
        mWakeAndHandOff.setReferenceCounted(false);

        IntentFilter filter = new IntentFilter();
        filter.addAction(DELAYED_KEYGUARD_ACTION);
        filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
        context.registerReceiver(mBroadCastReceiver, filter);
        mAlarmManager = (AlarmManager) context
                .getSystemService(Context.ALARM_SERVICE);
        mCallback = callback;

        mUpdateMonitor = new KeyguardUpdateMonitor(context);
        mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(DELAYED_KEYGUARD_ACTION));

        mUpdateMonitor.registerInfoCallback(mInfoCallback);
        mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);

        mUpdateMonitor.registerSimStateCallback(this);
        mUpdateMonitor = new KeyguardUpdateMonitor(context);

        mLockPatternUtils = new LockPatternUtils(mContext);
        mKeyguardViewProperties
@@ -336,10 +411,6 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
        int lockSoundDefaultAttenuation = context.getResources().getInteger(
                com.android.internal.R.integer.config_lockSoundVolumeDb);
        mLockSoundVolume = (float)Math.pow(10, (float)lockSoundDefaultAttenuation/20);
        IntentFilter userFilter = new IntentFilter();
        userFilter.addAction(Intent.ACTION_USER_SWITCHED);
        userFilter.addAction(Intent.ACTION_USER_REMOVED);
        mContext.registerReceiver(mUserChangeReceiver, userFilter);
    }

    /**
@@ -349,6 +420,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
        synchronized (this) {
            if (DEBUG) Log.d(TAG, "onSystemReady");
            mSystemReady = true;
            mUpdateMonitor.registerCallback(mUpdateCallback);
            doKeyguardLocked();
        }
    }
@@ -726,123 +798,21 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
        mHandler.sendMessage(msg);
    }

    /** {@inheritDoc} */
    public void onSimStateChanged(IccCardConstants.State simState) {
        if (DEBUG) Log.d(TAG, "onSimStateChanged: " + simState);

        switch (simState) {
            case ABSENT:
                // only force lock screen in case of missing sim if user hasn't
                // gone through setup wizard
                synchronized (this) {
                    if (!mUpdateMonitor.isDeviceProvisioned()) {
                        if (!isShowing()) {
                            if (DEBUG) Log.d(TAG, "ICC_ABSENT isn't showing,"
                                    + " we need to show the keyguard since the "
                                    + "device isn't provisioned yet.");
                            doKeyguardLocked();
                        } else {
                            resetStateLocked();
                        }
                    }
                }
                break;
            case PIN_REQUIRED:
            case PUK_REQUIRED:
                synchronized (this) {
                    if (!isShowing()) {
                        if (DEBUG) Log.d(TAG, "INTENT_VALUE_ICC_LOCKED and keygaurd isn't showing, "
                                + "we need to show keyguard so user can enter their sim pin");
                        doKeyguardLocked();
                    } else {
                        resetStateLocked();
                    }
                }
                break;
            case PERM_DISABLED:
                synchronized (this) {
                    if (!isShowing()) {
                        if (DEBUG) Log.d(TAG, "PERM_DISABLED and "
                              + "keygaurd isn't showing.");
                        doKeyguardLocked();
                    } else {
                        if (DEBUG) Log.d(TAG, "PERM_DISABLED, resetStateLocked to"
                              + "show permanently disabled message in lockscreen.");
                        resetStateLocked();
                    }
                }
                break;
            case READY:
                synchronized (this) {
                    if (isShowing()) {
                        resetStateLocked();
                    }
                }
                break;
        }
    }

    public boolean isSecure() {
        return mKeyguardViewProperties.isSecure();
    }

    private void onUserSwitched(int userId) {
        mLockPatternUtils.setCurrentUser(userId);
        synchronized (KeyguardViewMediator.this) {
            resetStateLocked();
        }
    }

    private void onUserRemoved(int userId) {
        mLockPatternUtils.removeUser(userId);
    }

    private BroadcastReceiver mUserChangeReceiver = new BroadcastReceiver() {
    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (Intent.ACTION_USER_SWITCHED.equals(action)) {
                onUserSwitched(intent.getIntExtra(Intent.EXTRA_USERID, 0));
            } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
                onUserRemoved(intent.getIntExtra(Intent.EXTRA_USERID, 0));
            }
        }
    };

    private BroadcastReceiver mBroadCastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            if (action.equals(DELAYED_KEYGUARD_ACTION)) {

                int sequence = intent.getIntExtra("seq", 0);

            if (DELAYED_KEYGUARD_ACTION.equals(intent.getAction())) {
                final int sequence = intent.getIntExtra("seq", 0);
                if (DEBUG) Log.d(TAG, "received DELAYED_KEYGUARD_ACTION with seq = "
                        + sequence + ", mDelayedShowingSequence = " + mDelayedShowingSequence);

                synchronized (KeyguardViewMediator.this) {
                    if (mDelayedShowingSequence == sequence) {
                        // Don't play lockscreen SFX if the screen went off due to
                        // timeout.
                        // Don't play lockscreen SFX if the screen went off due to timeout.
                        mSuppressNextLockSound = true;

                        doKeyguardLocked();
                    }
                }
            } else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) {
                mPhoneState = intent.getStringExtra(TelephonyManager.EXTRA_STATE);

                synchronized (KeyguardViewMediator.this) {
                    if (TelephonyManager.EXTRA_STATE_IDLE.equals(mPhoneState)  // call ending
                            && !mScreenOn                           // screen off
                            && mExternallyEnabled) {                // not disabled by any app

                        // note: this is a way to gracefully reenable the keyguard when the call
                        // ends and the screen is off without always reenabling the keyguard
                        // each time the screen turns off while in call (and having an occasional ugly
                        // flicker while turning back on the screen and disabling the keyguard again).
                        if (DEBUG) Log.d(TAG, "screen is off and call ended, let's make sure the "
                                + "keyguard is showing");
                        doKeyguardLocked();
                    }
                }
@@ -850,7 +820,6 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
        }
    };


    /**
     * When a key is received when the screen is off and the keyguard is showing,
     * we need to decide whether to actually turn on the screen, and if so, tell
+6 −12
Original line number Diff line number Diff line
@@ -17,13 +17,10 @@
package com.android.internal.policy.impl;

import com.android.internal.R;
import com.android.internal.policy.impl.KeyguardUpdateMonitor.InfoCallback;
import com.android.internal.policy.impl.KeyguardUpdateMonitor.InfoCallbackImpl;
import com.android.internal.policy.impl.LockPatternKeyguardView.UnlockMode;
import com.android.internal.policy.impl.KeyguardUpdateMonitor.BatteryStatus;
import com.android.internal.telephony.IccCardConstants;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockScreenWidgetCallback;
import com.android.internal.widget.LockScreenWidgetInterface;
import com.android.internal.widget.TransportControlView;

import android.accounts.Account;
@@ -40,10 +37,8 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.PixelFormat;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Parcelable;
@@ -449,9 +444,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
        mWindowController = controller;
        mSuppressBiometricUnlock = sIsFirstAppearanceAfterBoot;
        sIsFirstAppearanceAfterBoot = false;
        mPluggedIn = mUpdateMonitor.isDevicePluggedIn();
        mScreenOn = ((PowerManager)context.getSystemService(Context.POWER_SERVICE)).isScreenOn();
        mUpdateMonitor.registerInfoCallback(mInfoCallback);
        mUpdateMonitor.registerCallback(mInfoCallback);

        /**
         * We'll get key events the current screen doesn't use. see
@@ -692,17 +686,17 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
        post(mRecreateRunnable);
    }

    InfoCallbackImpl mInfoCallback = new InfoCallbackImpl() {
    KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {

        @Override
        public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn,
                int batteryLevel) {
        public void onRefreshBatteryInfo(BatteryStatus status) {
            // When someone plugs in or unplugs the device, we hide the biometric sensor area and
            // suppress its startup for the next onScreenTurnedOn().  Since plugging/unplugging
            // causes the screen to turn on, the biometric unlock would start if it wasn't
            // suppressed.
            //
            // However, if the biometric unlock is already running, we do not want to interrupt it.
            final boolean pluggedIn = status.isPluggedIn();
            if (mBiometricUnlock != null && mPluggedIn != pluggedIn
                    && !mBiometricUnlock.isRunning()) {
                mBiometricUnlock.stop();
@@ -732,7 +726,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
        }

        @Override
        public void onUserChanged(int userId) {
        public void onUserSwitched(int userId) {
            if (mBiometricUnlock != null) {
                mBiometricUnlock.stop();
            }
Loading