1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.car.voicerecognition;
18 
19 import android.content.BroadcastReceiver;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.IntentFilter;
23 import android.os.UserHandle;
24 import android.util.Log;
25 import android.widget.Toast;
26 
27 import com.android.internal.annotations.VisibleForTesting;
28 import com.android.systemui.CoreStartable;
29 import com.android.systemui.R;
30 import com.android.systemui.SysUIToast;
31 import com.android.systemui.dagger.qualifiers.Main;
32 import com.android.systemui.util.concurrency.DelayableExecutor;
33 
34 import javax.inject.Inject;
35 
36 /**
37  * Controller responsible for showing toast message when voice recognition over bluetooth device
38  * getting activated.
39  */
40 public class ConnectedDeviceVoiceRecognitionNotifier implements CoreStartable {
41 
42     private static final String TAG = "CarVoiceRecognition";
43     @VisibleForTesting
44     static final int INVALID_VALUE = -1;
45     @VisibleForTesting
46     static final int VOICE_RECOGNITION_STARTED = 1;
47 
48     // TODO(b/218911666): {@link BluetoothHeadsetClient.ACTION_AG_EVENT} is a hidden API.
49     private static final String HEADSET_CLIENT_ACTION_AG_EVENT =
50             "android.bluetooth.headsetclient.profile.action.AG_EVENT";
51     // TODO(b/218911666): {@link BluetoothHeadsetClient.EXTRA_VOICE_RECOGNITION} is a hidden API.
52     private static final String HEADSET_CLIENT_EXTRA_VOICE_RECOGNITION =
53             "android.bluetooth.headsetclient.extra.VOICE_RECOGNITION";
54 
55     private final Context mContext;
56     private final DelayableExecutor mExecutor;
57 
58     private final BroadcastReceiver mVoiceRecognitionReceiver = new BroadcastReceiver() {
59         @Override
60         public void onReceive(Context context, Intent intent) {
61             if (Log.isLoggable(TAG, Log.DEBUG)) {
62                 Log.d(TAG, "Voice recognition received an intent!");
63             }
64             if (intent == null
65                     || intent.getAction() == null
66                     || !HEADSET_CLIENT_ACTION_AG_EVENT.equals(intent.getAction())
67                     || !intent.hasExtra(HEADSET_CLIENT_EXTRA_VOICE_RECOGNITION)) {
68                 return;
69             }
70 
71             int voiceRecognitionState = intent.getIntExtra(
72                     HEADSET_CLIENT_EXTRA_VOICE_RECOGNITION, INVALID_VALUE);
73 
74             if (voiceRecognitionState == VOICE_RECOGNITION_STARTED) {
75                 showToastMessage();
76             }
77         }
78     };
79 
showToastMessage()80     private void showToastMessage() {
81         mExecutor.execute(() -> SysUIToast.makeText(mContext, R.string.voice_recognition_toast,
82                 Toast.LENGTH_LONG).show());
83     }
84 
85     @Inject
ConnectedDeviceVoiceRecognitionNotifier( Context context, @Main DelayableExecutor mainExecutor )86     public ConnectedDeviceVoiceRecognitionNotifier(
87             Context context,
88             @Main DelayableExecutor mainExecutor
89     ) {
90         mContext = context;
91         mExecutor = mainExecutor;
92     }
93 
94     @Override
start()95     public void start() {
96     }
97 
98     @Override
onBootCompleted()99     public void onBootCompleted() {
100         IntentFilter filter = new IntentFilter();
101         filter.addAction(HEADSET_CLIENT_ACTION_AG_EVENT);
102         mContext.registerReceiverAsUser(mVoiceRecognitionReceiver, UserHandle.ALL, filter,
103                 /* broadcastPermission= */ null, /* scheduler= */ null);
104     }
105 }
106