diff options
Diffstat (limited to 'packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java')
| -rw-r--r-- | packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java index eedb7d0..00124b0 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java @@ -24,6 +24,7 @@ import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.AlertDialog; +import android.app.PendingIntent; import android.app.SearchManager; import android.app.admin.DevicePolicyManager; import android.appwidget.AppWidgetHost; @@ -40,6 +41,7 @@ import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Rect; import android.media.RemoteControlClient; +import android.os.Bundle; import android.os.Looper; import android.os.Parcel; import android.os.Parcelable; @@ -47,6 +49,9 @@ import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; 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.Log; import android.util.Slog; @@ -63,6 +68,11 @@ import java.util.List; public class KeyguardHostView extends KeyguardViewBase { 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. static final int TRANSPORT_GONE = 0; static final int TRANSPORT_INVISIBLE = 1; @@ -77,6 +87,13 @@ public class KeyguardHostView extends KeyguardViewBase { // Found in KeyguardAppWidgetPickActivity.java 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 AppWidgetHost mAppWidgetHost; @@ -117,6 +134,8 @@ public class KeyguardHostView extends KeyguardViewBase { private KeyguardMultiUserSelectorView mKeyguardMultiUserSelectorView; + private boolean mIsScreenOn; + protected int mClientGeneration; protected boolean mShowSecurityWhenReturn; @@ -198,6 +217,11 @@ public class KeyguardHostView extends KeyguardViewBase { if ((mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0) { 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() { @@ -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) { @@ -778,6 +817,9 @@ public class KeyguardHostView extends KeyguardViewBase { // If the alternate unlock was suppressed, it can now be safely // enabled because the user has left keyguard. KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true); + if (shouldRunHotwordInSecurityMode(mCurrentSecuritySelection)){ + maybeStopHotwordDetector(); + } // If there's a pending runnable because the user interacted with a widget // and we're leaving keyguard, then run it. @@ -942,6 +984,9 @@ public class KeyguardHostView extends KeyguardViewBase { // Emulate Activity life cycle if (oldView != null) { + if (shouldRunHotwordInSecurityMode(mCurrentSecuritySelection)) { + maybeStopHotwordDetector(); + } oldView.onPause(); oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view } @@ -982,6 +1027,7 @@ public class KeyguardHostView extends KeyguardViewBase { @Override public void onScreenTurnedOn() { if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode())); + mIsScreenOn = true; showPrimarySecurityScreen(false); getSecurityView(mCurrentSecuritySelection).onResume(KeyguardSecurityView.SCREEN_ON); @@ -993,6 +1039,12 @@ public class KeyguardHostView extends KeyguardViewBase { if (mViewStateManager != null) { mViewStateManager.showUsabilityHints(); } + + // Start hotword detection on insecure Keyguard. + if (shouldRunHotwordInSecurityMode(mCurrentSecuritySelection)) { + maybeStartHotwordDetector(); + } + requestFocus(); } @@ -1000,6 +1052,7 @@ public class KeyguardHostView extends KeyguardViewBase { public void onScreenTurnedOff() { if (DEBUG) Log.d(TAG, String.format("screen off, instance %s at %s", 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 // biometric unlock to start next time keyguard is shown. KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true); @@ -1013,6 +1066,12 @@ public class KeyguardHostView extends KeyguardViewBase { if (cameraPage != null) { cameraPage.onScreenTurnedOff(); } + + // Stop hotword detection on insecure Keyguard. + if (shouldRunHotwordInSecurityMode(mCurrentSecuritySelection)) { + maybeStopHotwordDetector(); + } + clearFocus(); } @@ -1097,6 +1156,9 @@ public class KeyguardHostView extends KeyguardViewBase { new CameraWidgetFrame.Callbacks() { @Override public void onLaunchingCamera() { + if (shouldRunHotwordInSecurityMode(mCurrentSecuritySelection)) { + maybeStopHotwordDetector(); + } setSliderHandleAlpha(0); } @@ -1626,6 +1688,9 @@ public class KeyguardHostView extends KeyguardViewBase { } public void showAssistant() { + if (shouldRunHotwordInSecurityMode(mCurrentSecuritySelection)) { + maybeStopHotwordDetector(); + } final Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) .getAssistIntent(mContext, true, UserHandle.USER_CURRENT); @@ -1640,4 +1705,130 @@ public class KeyguardHostView extends KeyguardViewBase { mActivityLauncher.launchActivityWithAnimation( 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())); + } } |
