Nhập bằng giọng nói

Tính năng nhập bằng giọng nói giúp bạn tạo ra một giao diện thực sự rảnh tay. Glass cho bạn 3 cách sử dụng tính năng nhập bằng giọng nói.

Các lệnh thoại chính khởi động Glassware từ thẻ Home, các lệnh thoại theo ngữ cảnh có thể thực thi các thao tác trong một hoạt động và hoạt động nhận dạng giọng nói của hệ thống cho phép bạn nhận dữ liệu nhập bằng giọng nói dạng tự do từ người dùng.

Các lệnh thoại chính

Những lệnh thoại này khởi chạy Glassware từ thẻ Home (thẻ Đồng hồ). Khi bạn khai báo một lệnh thoại chính, Glass sẽ tự động tạo một mục trong trình đơn cảm ứng dự phòng nếu người dùng quyết định khởi động Glassware bằng cách nhấn vào thẻ Home.

Để thêm lệnh thoại vào trình đơn chính của giọng nói ok Glass, hãy làm như sau:

  1. Tạo một tài nguyên XML cho lệnh thoại trong res/xml/<my_voice_trigger>.xml bằng cách sử dụng một trong các lệnh thoại hiện có được xác định trong VoiceTriggers.Command. Dưới đây là cách sử dụng tính năng "Bắt đầu chạy bộ".

    <?xml version="1.0" encoding="utf-8"?>
    <trigger command="START_A_RUN" />
    

    Để tạo một lệnh thoại nhắc người dùng nói thêm một cụm từ trước khi bắt đầu hoạt động hoặc dịch vụ, hãy thêm cả một phần tử input. Ví dụ: bạn có thể muốn thực hiện việc này nếu đang sử dụng "Đăng nội dung cập nhật".

    <?xml version="1.0" encoding="utf-8"?>
    <trigger command="POST_AN_UPDATE">
        <input prompt="@string/glass_voice_prompt" />
    </trigger>
    
  2. Đăng ký bộ lọc ý định bằng cách sử dụng thao tác com.google.android.glass.action.VOICE_TRIGGER trong tệp kê khai Android. Bộ lọc ý định sẽ bắt đầu hoạt động hoặc dịch vụ nếu phát hiện người dùng nói lệnh thoại của bạn.

    <?xml version="1.0" encoding="utf-8"?>
    <application ...>
        <activity | service ...>
            <intent-filter>
                <action android:name=
                        "com.google.android.glass.action.VOICE_TRIGGER" />
            </intent-filter>
            <meta-data android:name="com.google.android.glass.VoiceTrigger"
                android:resource="@xml/my_voice_trigger" />
        </activity | service>
        // ...
    </application>
    
  3. Khai báo thuộc tính android:icon cho hoạt động hoặc dịch vụ. Điều này cho phép Glass hiển thị một biểu tượng cho Glassware trong trình đơn cảm ứng OK, Glass.

    <activity |service
        android:icon="@drawable/my_icon" ...>
      ...
    </activity | service>
    
  4. Nếu lệnh thoại sử dụng lời nhắc thoại và bắt đầu một hoạt động, hãy lấy văn bản được chép lời bằng mã sau (chẳng hạn như trong onResume()):

    ArrayList<String> voiceResults = getIntent().getExtras()
            .getStringArrayList(RecognizerIntent.EXTRA_RESULTS);
    

    Nếu lệnh thoại bắt đầu một dịch vụ, thì ý định bổ sung sẽ có trong lệnh gọi lại onStartCommand():

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        ArrayList<String> voiceResults = intent.getExtras()
                .getStringArrayList(RecognizerIntent.EXTRA_RESULTS);
        // ...
    }
    

Thiết lập điều kiện ràng buộc

Nếu bạn cần một hoặc tất cả các tính năng sau để khởi động Glassware, hãy chỉ định chúng trong tài nguyên res/xml/<my_voice_trigger>.xml. Nếu các tính năng không hoạt động, Glass sẽ tắt lệnh thoại:

  • camera
  • network
  • microphone

    <trigger command="POST_AN_UPDATE">
        <constraints
            camera="true"
            network="true" />
    </trigger>
    

Lệnh thoại theo ngữ cảnh

Lệnh thoại theo ngữ cảnh cho phép người dùng thực hiện hành động từ các hoạt động. Bạn tạo lệnh thoại theo ngữ cảnh bằng API trình đơn Android tiêu chuẩn nhưng người dùng có thể gọi các mục trong trình đơn bằng lệnh thoại thay vì chạm.

Để bật lệnh thoại theo ngữ cảnh cho một hoạt động cụ thể:

  1. Gọi getWindow().requestFeature(WindowUtils.FEATURE_VOICE_COMMANDS) trong hoạt động mong muốn để bật lệnh thoại theo ngữ cảnh. Khi tính năng này được bật, trình đơn "ok Glass" xuất hiện ở khu vực chân trang trên màn hình bất cứ khi nào hoạt động này nhận được tiêu điểm.

  2. Ghi đè onCreatePanelMenu() và xử lý trường hợp bật WindowUtils.FEATURE_VOICE_COMMANDS. Nếu được bật, đây sẽ là nơi bạn thực hiện thiết lập trình đơn một lần, chẳng hạn như tăng cường tài nguyên trình đơn hoặc gọi phương thức Menu.add() để tạo hệ thống trình đơn thoại.

  3. Ghi đè onMenuItemSelected() để xử lý các lệnh thoại khi người dùng nói. Khi người dùng chọn xong một mục trong trình đơn, lệnh thoại "ok, Glass" sẽ tự động xuất hiện lại ở phần chân trang trên màn hình, sẵn sàng chấp nhận lệnh thoại mới, miễn là hoạt động đó vẫn là tiêu điểm.

    Mã sau đây bật lệnh thoại theo ngữ cảnh, tăng cường tài nguyên trình đơn khi thích hợp và xử lý lệnh thoại khi được đọc:

    public class ContextualMenuActivity extends Activity {
    
        @Override
        protected void onCreate(Bundle bundle) {
            super.onCreate(bundle);
    
            // Requests a voice menu on this activity. As for any other
            // window feature, be sure to request this before
            // setContentView() is called
            getWindow().requestFeature(WindowUtils.FEATURE_VOICE_COMMANDS);
            setContentView(R.layout.activity_main);
        }
    
        @Override
        public boolean onCreatePanelMenu(int featureId, Menu menu) {
            if (featureId == WindowUtils.FEATURE_VOICE_COMMANDS) {
                getMenuInflater().inflate(R.menu.main, menu);
                return true;
            }
            // Pass through to super to setup touch menu.
            return super.onCreatePanelMenu(featureId, menu);
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            getMenuInflater().inflate(R.menu.main, menu);
            return true;
        }
    
        @Override
        public boolean onMenuItemSelected(int featureId, MenuItem item) {
            if (featureId == WindowUtils.FEATURE_VOICE_COMMANDS) {
                switch (item.getItemId()) {
                    case R.id.dogs_menu_item:
                        // handle top-level dogs menu item
                        break;
                    case R.id.cats_menu_item:
                        // handle top-level cats menu item
                        break;
                    case R.id.lab_menu_item:
                        // handle second-level labrador menu item
                        break;
                    case R.id.golden_menu_item:
                        // handle second-level golden menu item
                        break;
                    case R.id.calico_menu_item:
                        // handle second-level calico menu item
                        break;
                    case R.id.cheshire_menu_item:
                        // handle second-level cheshire menu item
                        break;
                    default:
                        return true;
                }
                return true;
            }
            // Good practice to pass through to super if not handled
            return super.onMenuItemSelected(featureId, item);
        }
    }
    

    Dưới đây là ví dụ về tài nguyên trình đơn mà hoạt động trước đó sử dụng. Hãy lưu ý cách tạo các mục trong trình đơn lồng nhau cho một hệ thống trình đơn thoại phân cấp. Trong ví dụ sau, mục đầu tiên trong trình đơn có thể truy cập được là: ok Glass, Show medog, Labrador.

    <menu xmlns:android="http://schemas.android.com/apk/res/android">
        <!-- Use the constants defined in the ContextualMenus.Command enum-->
        <item
            android:id="@+id/dogs_menu_item"
            android:title="@string/show_me_dogs">
            <menu>
                <item
                    android:id="@+id/lab_menu_item"
                    android:title="@string/labrador" />
                <item
                    android:id="@+id/golden_menu_item"
                    android:title="@string/golden" />
            </menu>
        </item>
        <item
            android:id="@+id/cats_menu_item"
            android:title="@string/show_me_cats">
            <menu>
                <item
                    android:id="@+id/cheshire_menu_item"
                    android:title="@string/cheshire" />
                <item
                    android:id="@+id/calico_menu_item"
                    android:title="@string/calico" />
            </menu>
        </item>
    </menu>
    
    <menu xmlns:android="http://schemas.android.com/apk/res/android">
        <!-- Use the constants defined in the ContextualMenus.Command enum-->
        <item
            android:id="@+id/play_menu_item"
            android:title="PLAY_MUSIC" />
        <item
            android:id="@+id/pause_menu_item"
            android:title="PAUSE_MUSIC" />
    </menu>
    
  4. (Không bắt buộc) Ghi đè onPreparePanel(), kiểm tra xem WindowUtils.FEATURE_VOICE_COMMANDS đã được bật hay chưa. Nếu được bật, đây là nơi bạn có thể thực hiện logic khác để thiết lập hệ thống trình đơn, chẳng hạn như thêm và xoá một số mục trong trình đơn dựa trên một số tiêu chí. Bạn cũng có thể bật (tắt) true theo trình đơn ngữ cảnh và tắt (trả về false) dựa trên một số tiêu chí. Ví dụ:

        private boolean mVoiceMenuEnabled;
        ...
        @Override
        public boolean onPreparePanel(int featureId, View view, Menu menu) {
            if (featureId == WindowUtils.FEATURE_VOICE_COMMANDS) {
            // toggle this boolean on and off based on some criteria
                return mVoiceMenuEnabled;
            }
            // Good practice to call through to super for other cases
            return super.onPreparePanel(featureId, view, menu);
        }
    

Hỗ trợ đồng thời trình đơn thoại và cảm ứng

Vì các lệnh thoại theo ngữ cảnh sử dụng API trình đơn Android hiện có, nên bạn có thể sử dụng lại nhiều mã và tài nguyên mà bạn đã có cho các trình đơn cảm ứng đồng thời hỗ trợ cả hai loại trình đơn.

Bạn chỉ cần kiểm tra tính năng Window.FEATURE_OPTIONS_PANEL ngoài tính năng WindowUtils.FEATURE_VOICE_COMMANDS mà bạn đã kiểm tra bằng một số phương thức, sau đó thêm logic để mở trình đơn cảm ứng trên một số thao tác của người dùng, chẳng hạn như một lần nhấn.

Ví dụ: bạn có thể thay đổi ví dụ về hoạt động trước đó để thêm sự hỗ trợ cho các trình đơn cảm ứng như sau (các thay đổi được nhận xét):

// 1. Check for Window.FEATURE_OPTIONS_PANEL
// to inflate the same menu resource for touch menus.
@Override
public boolean onCreatePanelMenu(int featureId, Menu menu) {
    if (featureId == WindowUtils.FEATURE_VOICE_COMMANDS ||
            featureId == Window.FEATURE_OPTIONS_PANEL) {
    ...
}

// 2. Check for Window.FEATURE_OPTIONS_PANEL
// to handle touch menu item selections.
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
    if (featureId == WindowUtils.FEATURE_VOICE_COMMANDS ||
            featureId == Window.FEATURE_OPTIONS_PANEL) {
    ...
}

Với những thay đổi này, bạn có thể nhấn hoặc nói OK kính để hiển thị trình đơn của mình.

Sử dụng lệnh thoại không công khai để phát triển

Khi muốn phân phối Glassware, bạn phải sử dụng các lệnh thoại chính đã phê duyệt trong VoiceTriggers.Command và các lệnh thoại theo ngữ cảnh được phê duyệt trong ContextualMenus.Command.

Nếu muốn sử dụng các lệnh thoại không có trong GDK, bạn có thể yêu cầu quyền trên Android trong tệp AndroidManifest.xml:

<uses-permission
     android:name="com.google.android.glass.permission.DEVELOPMENT" />

Sử dụng lệnh thoại chính không công khai

  1. Khai báo một giá trị chuỗi trong res/values/strings.xml để xác định tên của trình kích hoạt giọng nói. Tùy ý khai báo lời nhắc bằng giọng nói để hiển thị Glassware nhận dạng lời nói trước khi khởi động Glassware của bạn.

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <string name="glass_voice_trigger">read me a story</string>
        <string name="glass_voice_prompt">what story?</string>
    </resources>
    
  2. Tạo một tài nguyên XML cho trình kích hoạt giọng nói trong res/xml/<my_voice_trigger>.xml. Đối với các lệnh thoại không công khai, bạn nên sử dụng thuộc tính keyword thay vì thuộc tính command dùng cho các lệnh thoại đã được phê duyệt. Thuộc tính keyword phải tham chiếu đến tài nguyên chuỗi xác định lệnh thoại. Đối với trình kích hoạt thoại đơn giản bắt đầu một hoạt động hoặc dịch vụ ngay lập tức, bạn chỉ cần chỉ định phần tử trigger:

    <?xml version="1.0" encoding="utf-8"?>
    <trigger keyword="@string/glass_voice_trigger" />
    

    Để tạo trình kích hoạt thoại nhắc người dùng nói thêm một cụm từ trước khi bắt đầu hoạt động hoặc dịch vụ, hãy thêm cả một phần tử đầu vào:

    <?xml version="1.0" encoding="utf-8"?>
    <trigger keyword="@string/glass_voice_trigger">
        <input prompt="@string/glass_voice_prompt" />
    </trigger>
    

Sử dụng lệnh thoại theo ngữ cảnh không công khai

Khi tạo các mục trong trình đơn, hãy sử dụng văn bản bất kỳ cho tiêu đề của mục trong trình đơn. Ví dụ:

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Use the constants defined in the ContextualMenus.Command enum-->
    <item
        android:id="@+id/pizza_menu_item"
        android:title="@string/find_pizza" />
</menu>

Bắt đầu nhận dạng giọng nói


Tính năng nhận dạng lời nói Glassware chờ người dùng nói và trả về văn bản được chép lời sau khi họ hoàn tất. Để bắt đầu hoạt động:

  1. Gọi startActivityForResult() bằng ý định ACTION_RECOGNIZE_SPEECH. Các thành phần bổ sung ý định sau đây được hỗ trợ khi bắt đầu hoạt động:
  2. Ghi đè lệnh gọi lại onActivityResult() để nhận văn bản được chép lời từ ý định EXTRA_RESULTS bổ sung. Lệnh gọi lại này được gọi khi người dùng nói xong.

    private static final int SPEECH_REQUEST = 0;
    
    private void displaySpeechRecognizer() {
        Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
        startActivityForResult(intent, SPEECH_REQUEST);
    }
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode,
            Intent data) {
        if (requestCode == SPEECH_REQUEST && resultCode == RESULT_OK) {
            List<String> results = data.getStringArrayListExtra(
                    RecognizerIntent.EXTRA_RESULTS);
            String spokenText = results.get(0);
            // Do something with spokenText.
        }
        super.onActivityResult(requestCode, resultCode, data);
    }