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

Commit d49f2fa8 authored by Sandeep Siddhartha's avatar Sandeep Siddhartha Committed by Android Git Automerger
Browse files

am 454cf31d: am 228b3510: Merge "Move the hotword code to KeyguardHostView" into klp-dev

* commit '454cf31d':
  Move the hotword code to KeyguardHostView
parents 3facfed9 454cf31d
Loading
Loading
Loading
Loading
+191 −0
Original line number Original line Diff line number Diff line
@@ -24,6 +24,7 @@ import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.ActivityOptions;
import android.app.AlertDialog;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.app.SearchManager;
import android.app.SearchManager;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManager;
import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetHost;
@@ -40,6 +41,7 @@ import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.Rect;
import android.media.RemoteControlClient;
import android.media.RemoteControlClient;
import android.os.Bundle;
import android.os.Looper;
import android.os.Looper;
import android.os.Parcel;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Parcelable;
@@ -47,6 +49,9 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManager;
import android.provider.Settings;
import android.provider.Settings;
import android.speech.hotword.HotwordRecognitionListener;
import android.speech.hotword.HotwordRecognizer;
import android.telephony.TelephonyManager;
import android.util.AttributeSet;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Log;
import android.util.Slog;
import android.util.Slog;
@@ -63,6 +68,11 @@ import java.util.List;


public class KeyguardHostView extends KeyguardViewBase {
public class KeyguardHostView extends KeyguardViewBase {
    private static final String TAG = "KeyguardHostView";
    private static final String TAG = "KeyguardHostView";
    // Don't enable hotword on limited-memory devices.
    private static final boolean ENABLE_HOTWORD = !ActivityManager.isLowRamDeviceStatic();
    // Indicates if hotword is enabled, should it also be available on secure keyguard(s).
    private static final boolean ENABLE_HOTWORD_SECURE = false;

    // Transport control states.
    // Transport control states.
    static final int TRANSPORT_GONE = 0;
    static final int TRANSPORT_GONE = 0;
    static final int TRANSPORT_INVISIBLE = 1;
    static final int TRANSPORT_INVISIBLE = 1;
@@ -77,6 +87,13 @@ public class KeyguardHostView extends KeyguardViewBase {
    // Found in KeyguardAppWidgetPickActivity.java
    // Found in KeyguardAppWidgetPickActivity.java
    static final int APPWIDGET_HOST_ID = 0x4B455947;
    static final int APPWIDGET_HOST_ID = 0x4B455947;


    // TODO: Fix this to be non-static.
    // We need to be careful here to make stopRecognition calls on the same instance
    // that started it. Since KeyguardHostView is a view, it keeps getting
    // recreated every now and then, and unless we figure out a better way,
    // this needs to be a static field.
    private static HotwordRecognizer sHotwordClient;

    private final int MAX_WIDGETS = 5;
    private final int MAX_WIDGETS = 5;


    private AppWidgetHost mAppWidgetHost;
    private AppWidgetHost mAppWidgetHost;
@@ -117,6 +134,8 @@ public class KeyguardHostView extends KeyguardViewBase {


    private KeyguardMultiUserSelectorView mKeyguardMultiUserSelectorView;
    private KeyguardMultiUserSelectorView mKeyguardMultiUserSelectorView;


    private boolean mIsScreenOn;

    protected int mClientGeneration;
    protected int mClientGeneration;


    protected boolean mShowSecurityWhenReturn;
    protected boolean mShowSecurityWhenReturn;
@@ -198,6 +217,11 @@ public class KeyguardHostView extends KeyguardViewBase {
        if ((mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0) {
        if ((mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0) {
            Log.v(TAG, "Keyguard secure camera disabled by DPM");
            Log.v(TAG, "Keyguard secure camera disabled by DPM");
        }
        }

        // Create Hotword recognizer, for the first time.
        if (ENABLE_HOTWORD && sHotwordClient == null) {
            sHotwordClient = HotwordRecognizer.createHotwordRecognizer(getContext());
        }
    }
    }


    private void getInitialTransportState() {
    private void getInitialTransportState() {
@@ -295,6 +319,21 @@ public class KeyguardHostView extends KeyguardViewBase {
                }
                }
            }
            }
        }
        }
        @Override
        public void onPhoneStateChanged(int phoneState) {
            // We need to stop hotword detection when a call state is not idle anymore.
            if (shouldRunHotwordInSecurityMode(mCurrentSecuritySelection)
                    && TelephonyManager.CALL_STATE_IDLE != phoneState) {
                if (DEBUG) Log.d(TAG, "Stopping due to call state not being idle");
                maybeStopHotwordDetector();
            }
        }
        @Override
        public void onUserSwitching(int userId) {
            if (shouldRunHotwordInSecurityMode(mCurrentSecuritySelection)) {
                maybeStopHotwordDetector();
            }
        }
    };
    };


    private static final boolean isMusicPlaying(int playbackState) {
    private static final boolean isMusicPlaying(int playbackState) {
@@ -778,6 +817,9 @@ public class KeyguardHostView extends KeyguardViewBase {
            // If the alternate unlock was suppressed, it can now be safely
            // If the alternate unlock was suppressed, it can now be safely
            // enabled because the user has left keyguard.
            // enabled because the user has left keyguard.
            KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true);
            KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true);
            if (shouldRunHotwordInSecurityMode(mCurrentSecuritySelection)){
                maybeStopHotwordDetector();
            }


            // If there's a pending runnable because the user interacted with a widget
            // If there's a pending runnable because the user interacted with a widget
            // and we're leaving keyguard, then run it.
            // and we're leaving keyguard, then run it.
@@ -942,6 +984,9 @@ public class KeyguardHostView extends KeyguardViewBase {


        // Emulate Activity life cycle
        // Emulate Activity life cycle
        if (oldView != null) {
        if (oldView != null) {
            if (shouldRunHotwordInSecurityMode(mCurrentSecuritySelection)) {
                maybeStopHotwordDetector();
            }
            oldView.onPause();
            oldView.onPause();
            oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view
            oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view
        }
        }
@@ -982,6 +1027,7 @@ public class KeyguardHostView extends KeyguardViewBase {
    @Override
    @Override
    public void onScreenTurnedOn() {
    public void onScreenTurnedOn() {
        if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode()));
        if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode()));
        mIsScreenOn = true;
        showPrimarySecurityScreen(false);
        showPrimarySecurityScreen(false);
        getSecurityView(mCurrentSecuritySelection).onResume(KeyguardSecurityView.SCREEN_ON);
        getSecurityView(mCurrentSecuritySelection).onResume(KeyguardSecurityView.SCREEN_ON);


@@ -993,6 +1039,12 @@ public class KeyguardHostView extends KeyguardViewBase {
        if (mViewStateManager != null) {
        if (mViewStateManager != null) {
            mViewStateManager.showUsabilityHints();
            mViewStateManager.showUsabilityHints();
        }
        }

        // Start hotword detection on insecure Keyguard.
        if (shouldRunHotwordInSecurityMode(mCurrentSecuritySelection)) {
            maybeStartHotwordDetector();
        }

        requestFocus();
        requestFocus();
    }
    }


@@ -1000,6 +1052,7 @@ public class KeyguardHostView extends KeyguardViewBase {
    public void onScreenTurnedOff() {
    public void onScreenTurnedOff() {
        if (DEBUG) Log.d(TAG, String.format("screen off, instance %s at %s",
        if (DEBUG) Log.d(TAG, String.format("screen off, instance %s at %s",
                Integer.toHexString(hashCode()), SystemClock.uptimeMillis()));
                Integer.toHexString(hashCode()), SystemClock.uptimeMillis()));
        mIsScreenOn = false;
        // Once the screen turns off, we no longer consider this to be first boot and we want the
        // Once the screen turns off, we no longer consider this to be first boot and we want the
        // biometric unlock to start next time keyguard is shown.
        // biometric unlock to start next time keyguard is shown.
        KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true);
        KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true);
@@ -1013,6 +1066,12 @@ public class KeyguardHostView extends KeyguardViewBase {
        if (cameraPage != null) {
        if (cameraPage != null) {
            cameraPage.onScreenTurnedOff();
            cameraPage.onScreenTurnedOff();
        }
        }

        // Stop hotword detection on insecure Keyguard.
        if (shouldRunHotwordInSecurityMode(mCurrentSecuritySelection)) {
            maybeStopHotwordDetector();
        }

        clearFocus();
        clearFocus();
    }
    }


@@ -1097,6 +1156,9 @@ public class KeyguardHostView extends KeyguardViewBase {
        new CameraWidgetFrame.Callbacks() {
        new CameraWidgetFrame.Callbacks() {
            @Override
            @Override
            public void onLaunchingCamera() {
            public void onLaunchingCamera() {
                if (shouldRunHotwordInSecurityMode(mCurrentSecuritySelection)) {
                    maybeStopHotwordDetector();
                }
                setSliderHandleAlpha(0);
                setSliderHandleAlpha(0);
            }
            }


@@ -1626,6 +1688,9 @@ public class KeyguardHostView extends KeyguardViewBase {
    }
    }


    public void showAssistant() {
    public void showAssistant() {
        if (shouldRunHotwordInSecurityMode(mCurrentSecuritySelection)) {
            maybeStopHotwordDetector();
        }
        final Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
        final Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
          .getAssistIntent(mContext, true, UserHandle.USER_CURRENT);
          .getAssistIntent(mContext, true, UserHandle.USER_CURRENT);


@@ -1640,4 +1705,130 @@ public class KeyguardHostView extends KeyguardViewBase {
        mActivityLauncher.launchActivityWithAnimation(
        mActivityLauncher.launchActivityWithAnimation(
                intent, false, opts.toBundle(), null, null);
                intent, false, opts.toBundle(), null, null);
    }
    }


    /**
     * Start the hotword detector if:
     * <li> ENABLE_HOTWORD is true and
     * <li> Hotword detection is not already running and
     * <li> TelephonyManager is in CALL_STATE_IDLE
     * <li> and Screen is turned on.
     */
    private void maybeStartHotwordDetector() {
        if (!ENABLE_HOTWORD) return;

        if (sHotwordClient != null) {
            if (DEBUG) Log.d(TAG, "maybeStartHotwordDetector()");
            // Don't start hotword detection if the screen is off.
            if (!mIsScreenOn) {
                if (DEBUG) Log.d(TAG, "screen was off, not starting");
                return;
            }

            KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(getContext());
            if (monitor.getPhoneState() != TelephonyManager.CALL_STATE_IDLE) {
                if (DEBUG) Log.d(TAG, "Call underway, not starting");
                return;
            }

            try {
                sHotwordClient.startRecognition(mHotwordCallback);
            } catch(Exception ex) {
                // Don't allow hotword errors to make the keyguard unusable
                Log.e(TAG, "Failed to start hotword recognition", ex);
                sHotwordClient = null;
            }
        }
    }

    /**
     * Stop hotword detector if:
     * <li> ENABLE_HOTWORD is true
     * <li> and hotword is running.
     */
    private void maybeStopHotwordDetector() {
        if (!ENABLE_HOTWORD) return;

        if (sHotwordClient != null) {
            if (DEBUG) Log.d(TAG, "maybeStopHotwordDetector()");
            try {
                sHotwordClient.stopRecognition();
            } catch(Exception ex) {
                // Don't allow hotword errors to make the keyguard unusable
                Log.e(TAG, "Failed to start hotword recognition", ex);
            } finally {
                sHotwordClient = null;
            }
        }
    }

    private final HotwordRecognitionListener mHotwordCallback = new HotwordRecognitionListener() {
        private static final String TAG = "HotwordRecognitionListener";

        public void onHotwordRecognitionStarted() {
            if (DEBUG) Log.d(TAG, "onHotwordRecognitionStarted()");
        }

        public void onHotwordRecognitionStopped() {
            if (DEBUG) Log.d(TAG, "onHotwordRecognitionStopped()");
        }

        public void onHotwordEvent(int eventType, Bundle eventBundle) {
            if (DEBUG) Log.d(TAG, "onHotwordEvent: " + eventType);
            if (eventType == HotwordRecognizer.EVENT_TYPE_STATE_CHANGED) {
                if (eventBundle != null && eventBundle.containsKey(HotwordRecognizer.PROMPT_TEXT)) {
                    new KeyguardMessageArea.Helper(
                            (View) getSecurityView(mCurrentSecuritySelection))
                        .setMessage(eventBundle.getString(HotwordRecognizer.PROMPT_TEXT),true);
                }
            }
        }

        public void onHotwordRecognized(final PendingIntent intent) {
            if (DEBUG) Log.d(TAG, "onHotwordRecognized");
            maybeStopHotwordDetector();
            if (SecurityMode.None == mCurrentSecuritySelection) {
                if (intent != null) {
                    try {
                        intent.send();
                    } catch (PendingIntent.CanceledException e) {
                        Log.w(TAG, "Failed to launch PendingIntent. Encountered CanceledException");
                    }
                }
                mCallback.userActivity(0);
                mCallback.dismiss(false);
            } else if (ENABLE_HOTWORD_SECURE && mLockPatternUtils.isSecure()) {
                setOnDismissAction(new OnDismissAction() {
                    @Override
                    public boolean onDismiss() {
                        if (intent != null) {
                            try {
                                intent.send();
                            } catch (PendingIntent.CanceledException e) {
                                Log.w(TAG, "Failed to launch PendingIntent."
                                        + "Encountered CanceledException");
                            }
                        }
                        return false;
                    }
                });
                getSecurityView(mCurrentSecuritySelection).showBouncer(0);
            }
        }

        public void onHotwordError(int errorCode) {
            if (DEBUG) Log.d(TAG, "onHotwordError: " + errorCode);
            // TODO: Inspect the error code and handle the errors appropriately
            // instead of blindly failing.
            maybeStopHotwordDetector();
        }
    };

    private boolean shouldRunHotwordInSecurityMode(SecurityMode mode) {
        // Enable hotoword for insecure keyguard,
        // and for pattern unlock if ENABLE_HOTWORD_SECURE is true.
        return ENABLE_HOTWORD
                && ((SecurityMode.None == mode)
                        || (ENABLE_HOTWORD_SECURE && mLockPatternUtils.isSecure()));
    }
}
}
+0 −133
Original line number Original line Diff line number Diff line
@@ -28,8 +28,6 @@ import android.os.Bundle;
import android.os.PowerManager;
import android.os.PowerManager;
import android.os.UserHandle;
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings;
import android.speech.hotword.HotwordRecognitionListener;
import android.speech.hotword.HotwordRecognizer;
import android.telephony.TelephonyManager;
import android.telephony.TelephonyManager;
import android.util.AttributeSet;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Log;
@@ -48,12 +46,6 @@ public class KeyguardSelectorView extends LinearLayout implements KeyguardSecuri
    private static final String ASSIST_ICON_METADATA_NAME =
    private static final String ASSIST_ICON_METADATA_NAME =
        "com.android.systemui.action_assist_icon";
        "com.android.systemui.action_assist_icon";


    // Don't enable hotword on limited-memory devices.
    private static final boolean ENABLE_HOTWORD = !ActivityManager.isLowRamDeviceStatic();

    // TODO: Fix this to be non-static.
    private static HotwordRecognizer sHotwordClient;

    private KeyguardSecurityCallback mCallback;
    private KeyguardSecurityCallback mCallback;
    private GlowPadView mGlowPadView;
    private GlowPadView mGlowPadView;
    private ObjectAnimator mAnim;
    private ObjectAnimator mAnim;
@@ -69,7 +61,6 @@ public class KeyguardSelectorView extends LinearLayout implements KeyguardSecuri


        public void onTrigger(View v, int target) {
        public void onTrigger(View v, int target) {
            final int resId = mGlowPadView.getResourceIdForTarget(target);
            final int resId = mGlowPadView.getResourceIdForTarget(target);
            maybeStopHotwordDetector();


            switch (resId) {
            switch (resId) {
                case R.drawable.ic_action_assist_generic:
                case R.drawable.ic_action_assist_generic:
@@ -129,22 +120,6 @@ public class KeyguardSelectorView extends LinearLayout implements KeyguardSecuri
        public void onSimStateChanged(State simState) {
        public void onSimStateChanged(State simState) {
            updateTargets();
            updateTargets();
        }
        }

        @Override
        public void onPhoneStateChanged(int phoneState) {
            if (ENABLE_HOTWORD) {
                // We need to stop hotword detection when a call state is not idle anymore.
                if (phoneState != TelephonyManager.CALL_STATE_IDLE) {
                    if (DEBUG) Log.d(TAG, "Stopping due to call state not being idle");
                    maybeStopHotwordDetector();
                }
            }
        }

        @Override
        public void onUserSwitching(int userId) {
            maybeStopHotwordDetector();
        }
    };
    };


    private final KeyguardActivityLauncher mActivityLauncher = new KeyguardActivityLauncher() {
    private final KeyguardActivityLauncher mActivityLauncher = new KeyguardActivityLauncher() {
@@ -183,9 +158,6 @@ public class KeyguardSelectorView extends LinearLayout implements KeyguardSecuri
        mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this);
        mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this);
        View bouncerFrameView = findViewById(R.id.keyguard_selector_view_frame);
        View bouncerFrameView = findViewById(R.id.keyguard_selector_view_frame);
        mBouncerFrame = bouncerFrameView.getBackground();
        mBouncerFrame = bouncerFrameView.getBackground();
        if (ENABLE_HOTWORD && sHotwordClient == null) {
            sHotwordClient = HotwordRecognizer.createHotwordRecognizer(getContext());
        }
    }
    }


    public void setCarrierArea(View carrierArea) {
    public void setCarrierArea(View carrierArea) {
@@ -289,20 +261,11 @@ public class KeyguardSelectorView extends LinearLayout implements KeyguardSecuri
    @Override
    @Override
    public void onPause() {
    public void onPause() {
        KeyguardUpdateMonitor.getInstance(getContext()).removeCallback(mUpdateCallback);
        KeyguardUpdateMonitor.getInstance(getContext()).removeCallback(mUpdateCallback);
        maybeStopHotwordDetector();
    }
    }


    @Override
    @Override
    public void onResume(int reason) {
    public void onResume(int reason) {
        KeyguardUpdateMonitor.getInstance(getContext()).registerCallback(mUpdateCallback);
        KeyguardUpdateMonitor.getInstance(getContext()).registerCallback(mUpdateCallback);
        // TODO: Figure out if there's a better way to do it.
        // onResume gets called multiple times, however we are interested in
        // the reason to figure out when to start/stop hotword detection.
        if (reason == SCREEN_ON) {
            if (!KeyguardUpdateMonitor.getInstance(getContext()).isSwitchingUser()) {
                maybeStartHotwordDetector();
            }
        }
    }
    }


    @Override
    @Override
@@ -323,100 +286,4 @@ public class KeyguardSelectorView extends LinearLayout implements KeyguardSecuri
        KeyguardSecurityViewHelper.
        KeyguardSecurityViewHelper.
                hideBouncer(mSecurityMessageDisplay, mFadeView, mBouncerFrame, duration);
                hideBouncer(mSecurityMessageDisplay, mFadeView, mBouncerFrame, duration);
    }
    }

    /**
     * Start the hotword detector if:
     * <li> FLAG_HOTWORD is true and
     * <li> Hotword detection is not already running and
     * <li> TelephonyManager is in CALL_STATE_IDLE
     *
     * If this method is called when the screen is off,
     * it attempts to stop hotword detection if it's running.
     */
    private void maybeStartHotwordDetector() {
        if (ENABLE_HOTWORD && sHotwordClient != null) {
            if (DEBUG) Log.d(TAG, "maybeStartHotwordDetector()");
            // Don't start it if the screen is off or not showing
            PowerManager powerManager = (PowerManager) getContext().getSystemService(
                    Context.POWER_SERVICE);
            if (!powerManager.isScreenOn()) {
                if (DEBUG) Log.d(TAG, "screen was off, not starting");
                return;
            }

            KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(getContext());
            if (monitor.getPhoneState() != TelephonyManager.CALL_STATE_IDLE) {
                if (DEBUG) Log.d(TAG, "Call underway, not starting");
                return;
            }

            try {
                sHotwordClient.startRecognition(mHotwordCallback);
            } catch(Exception ex) {
                // Don't allow hotword errors to make the keyguard unusable
                Log.e(TAG, "Failed to start hotword recognition", ex);
                sHotwordClient = null;
            }
        }
    }

    /**
     * Stop hotword detector if HOTWORDING_ENABLED is true.
     */
    private void maybeStopHotwordDetector() {
        if (ENABLE_HOTWORD && sHotwordClient != null) {
            if (DEBUG) Log.d(TAG, "maybeStopHotwordDetector()");
            try {
                sHotwordClient.stopRecognition();
            } catch(Exception ex) {
                // Don't allow hotword errors to make the keyguard unusable
                Log.e(TAG, "Failed to start hotword recognition", ex);
            } finally {
                sHotwordClient = null;
            }
        }
    }

    private final HotwordRecognitionListener mHotwordCallback = new HotwordRecognitionListener() {
        private static final String TAG = "HotwordRecognitionListener";

        public void onHotwordRecognitionStarted() {
            if (DEBUG) Log.d(TAG, "onHotwordRecognitionStarted()");
        }

        public void onHotwordRecognitionStopped() {
            if (DEBUG) Log.d(TAG, "onHotwordRecognitionStopped()");
        }

        public void onHotwordEvent(int eventType, Bundle eventBundle) {
            if (DEBUG) Log.d(TAG, "onHotwordEvent: " + eventType);
            if (eventType == HotwordRecognizer.EVENT_TYPE_STATE_CHANGED) {
                if (eventBundle != null && eventBundle.containsKey(HotwordRecognizer.PROMPT_TEXT)) {
                    mSecurityMessageDisplay.setMessage(
                            eventBundle.getString(HotwordRecognizer.PROMPT_TEXT), true);
                }
            }
        }

        public void onHotwordRecognized(PendingIntent intent) {
            if (DEBUG) Log.d(TAG, "onHotwordRecognized");
            maybeStopHotwordDetector();
            if (intent != null) {
                try {
                    intent.send();
                } catch (PendingIntent.CanceledException e) {
                    Log.w(TAG, "Failed to launch PendingIntent. Encountered CanceledException");
                }
            }
            mCallback.userActivity(0);
            mCallback.dismiss(false);
        }

        public void onHotwordError(int errorCode) {
            if (DEBUG) Log.d(TAG, "onHotwordError: " + errorCode);
            // TODO: Inspect the error code and handle the errors appropriately
            // instead of blindly failing.
            maybeStopHotwordDetector();
        }
    };
}
}