You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Android Studio开发的智能助手添加唤醒词激活功能

Adding Wake Word Functionality to Your Android Voice Assistant

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_WORD constant 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_AUDIO permission, 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 20:18:13