如何为Android Studio开发的智能助手添加唤醒词激活功能
Hey there! Adding a wake word feature like Alexa to your existing assistant is totally doable. Since Android doesn’t have a built-in wake word listener, we’ll use CMU PocketSphinx—a popular open-source library for offline speech recognition that works great for wake word detection. Here’s how to integrate it into your current code:
Step 1: Add PocketSphinx Dependency
First, add the library to your app-level build.gradle file:
dependencies { implementation 'edu.cmu.pocketsphinx:pocketsphinx-android:5.0.0' }
Step 2: Request Required Permissions
You’ll need the RECORD_AUDIO permission (and INTERNET if you want to download language models automatically). Add these to your AndroidManifest.xml:
<uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.INTERNET" />
Don’t forget to request the RECORD_AUDIO permission dynamically at runtime—it’s a dangerous permission that requires explicit user approval on Android 6.0+.
Step 3: Integrate Wake Word Detection into Your Code
Here’s your modified homescreen.java with wake word support. I’ve added comments to highlight new sections:
import android.Manifest; import android.content.pm.PackageManager; import android.os.Bundle; import android.speech.RecognizerIntent; import android.util.Log; import android.view.View; import android.view.WindowManager; import android.widget.ImageView; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import com.cameronmacleod.pocketsphinx.RecognitionListener; import com.cameronmacleod.pocketsphinx.SpeechRecognizer; import com.cameronmacleod.pocketsphinx.SpeechRecognizerSetup; import java.io.File; import java.util.ArrayList; import java.util.Locale; private TextToSpeech tts; private ArrayList<String> questions; private String name, surname, age, asName; private SharedPreferences preferences; private SharedPreferences.Editor editor; private static final String PREFS = "prefs"; private static final String NEW = "new"; private static final String NAME = "name"; private static final String AGE = "age"; private static final String AS_NAME = "as_name"; private static final String SURNAME = "surname"; private static final String COLOUR = "colour"; private ImageView imgbtnTorF, imgbtnQuizzes; private FirebaseAuth firebaseAuth; // PocketSphinx wake word variables private SpeechRecognizer recognizer; private static final String WAKE_WORD = "alexa"; // Customize this to your preferred wake phrase private static final String KWS_SEARCH = "wakeup"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(R.layout.activity_homescreen); imgbtnQuizzes = findViewById(R.id.imgBtnQuizzes); imgbtnTorF = findViewById(R.id.imgBtnTorF); preferences = getSharedPreferences(PREFS, 0); editor = preferences.edit(); // Keep click listener as a fallback option findViewById(R.id.imgSpeech).setOnClickListener(v -> listen()); loadQuestions(); initTTS(); // Initialize wake word detection initWakeWordDetector(); } private void initTTS() { tts = new TextToSpeech(this, status -> { if (status == TextToSpeech.SUCCESS) { int result = tts.setLanguage(Locale.UK); if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) { Log.e("TTS", "This language is not supported"); } speak("Hello"); } else { Log.e("TTS", "Initialization failed!"); } }); } private void initWakeWordDetector() { // Check for record audio permission first if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, 101); return; } // Set up PocketSphinx recognizer with offline models try { recognizer = SpeechRecognizerSetup.defaultSetup() .setAcousticModel(new File(getAssets(), "en-us-ptm")) .setDictionary(new File(getAssets(), "cmudict-en-us.dict")) .getRecognizer(); } catch (Exception e) { Log.e("WakeWord", "Failed to initialize recognizer: " + e.getMessage()); return; } // Attach listener to detect wake word recognizer.addListener(new RecognitionListener() { @Override public void onBeginningOfSpeech() {} @Override public void onEndOfSpeech() {} @Override public void onPartialResult(com.cameronmacleod.pocketsphinx.Hypothesis hypothesis) { if (hypothesis != null) { String detectedPhrase = hypothesis.getHypstr(); if (detectedPhrase.equals(WAKE_WORD)) { // Wake word detected! Trigger assistant interaction speak("Yes? How can I help you?"); listen(); // Pause wake word detection during active interaction recognizer.stop(); } } } @Override public void onResult(com.cameronmacleod.pocketsphinx.Hypothesis hypothesis) {} @Override public void onError(Exception e) {} @Override public void onTimeout() {} }); // Configure keyword search for our wake word recognizer.addKeyphraseSearch(KWS_SEARCH, WAKE_WORD); // Start listening for the wake word recognizer.startListening(KWS_SEARCH); } // Handle permission request result @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == 101) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { initWakeWordDetector(); } else { Toast.makeText(this, "Record audio permission is required for wake word feature", Toast.LENGTH_LONG).show(); } } } private void loadQuestions() { questions = new ArrayList<>(); questions.clear(); questions.add("Hello, what is your name?"); questions.add("What is your surname?"); questions.add("How old are you?"); questions.add("Where do you live?"); questions.add("What is your favourite colour?"); questions.add("What is your favourite password you use?"); questions.add("Remember if you are wondering what you can ask me, you can say the word information and i will help you"); questions.add("That's all I had, thank you "); } private void listen() { Intent i = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); i.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); i.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault()); i.putExtra(RecognizerIntent.EXTRA_PROMPT, "Say something"); try { startActivityForResult(i, 100); } catch (Exception a) { Toast.makeText(homescreen.this, "Your device doesn't support Speech Recognition", Toast.LENGTH_SHORT).show(); // Resume wake word detection if speech recognition fails if (recognizer != null) recognizer.startListening(KWS_SEARCH); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 100) { if (resultCode == RESULT_OK && data != null) { ArrayList<String> res = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); String inSpeech = res.get(0); recognition(inSpeech); } // Resume wake word detection after interaction ends if (recognizer != null) recognizer.startListening(KWS_SEARCH); } } private void recognition(String text) { Log.e("Speech", "" + text); String[] speech = text.split(" "); if (text.contains("hello")) { speak(questions.get(0)); } // Uncomment and adjust this logic if needed (currently runs on every input) // if (text.contains("my name is")) { name = speech[speech.length - 1]; Log.e("THIS", "" + name); editor.putString(NAME, name).apply(); speak(questions.get(1)); // } if (text.contains("my last name is")) { surname = speech[speech.length - 1]; Log.e("THIS", "" + surname); editor.putString(SURNAME, surname).apply(); speak(questions.get(2)); } // Handle age input if (text.contains("years") && text.contains("old")) { String age = speech[speech.length - 3]; Log.e("THIS", "" + age); editor.putString(AGE, age).apply(); speak(questions.get(3)); } } private void speak(String text) { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { tts.speak(text, TextToSpeech.QUEUE_FLUSH, null, null); } else { tts.speak(text, TextToSpeech.QUEUE_FLUSH, null); } } @Override protected void onDestroy() { if (tts != null) { tts.stop(); tts.shutdown(); } // Clean up PocketSphinx resources if (recognizer != null) { recognizer.cancel(); recognizer.shutdown(); } super.onDestroy(); } @Override protected void onPause() { super.onPause(); // Stop listening to save battery when app is in background if (recognizer != null) recognizer.stop(); } @Override protected void onResume() { super.onResume(); // Resume wake word detection when app is foreground if (recognizer != null && ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) { recognizer.startListening(KWS_SEARCH); } }
Key Notes & Improvements
- Custom Wake Word: Change the
WAKE_WORDconstant to any short, distinct phrase you prefer (e.g., "Hey Assistant"). For better accuracy, avoid common words. - Battery Efficiency: The code pauses wake word detection when the app is in the background and resumes it when foregrounded to minimize battery drain.
- Offline Support: PocketSphinx works entirely offline, which is perfect for users without internet access. The acoustic model and dictionary files will be auto-added to your app’s assets folder during build.
- Interaction Flow: After detecting the wake word, the assistant speaks a prompt and starts listening for the user’s query. Once the interaction finishes, it automatically resumes listening for the wake word.
- Permission Safety: The code properly checks for and requests the
RECORD_AUDIOpermission, ensuring compliance with Android’s security rules.
Alternative: Using Google Assistant's Wake Word
If you want to leverage the system’s built-in wake word (like "Hey Google"), you can use the VoiceInteractionService, but this requires more setup and only works on devices with Google Assistant enabled. The PocketSphinx approach gives you full control over the wake word and assistant behavior within your app.
内容的提问来源于stack exchange,提问作者bob

