Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4a361067 authored by Babak Bostan's avatar Babak Bostan Committed by Android (Google) Code Review
Browse files

Merge "Add toast message when bluetooth connects to voice recognition." into rvc-dev

parents 4431668e a8600124
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -84,5 +84,6 @@
        <item>com.android.systemui.theme.ThemeOverlayController</item>
        <item>com.android.systemui.navigationbar.car.CarNavigationBar</item>
        <item>com.android.systemui.toast.ToastUI</item>
        <item>com.android.systemui.voicerecognition.car.ConnectedDeviceVoiceRecognitionNotifier</item>
    </string-array>
</resources>
+2 −0
Original line number Diff line number Diff line
@@ -20,4 +20,6 @@
    <string name="hvac_min_text">Min</string>
    <!-- String to represent largest setting of an HVAC system [CHAR LIMIT=5]-->
    <string name="hvac_max_text">Max</string>
    <!-- Text for voice recognition toast. [CHAR LIMIT=60] -->
    <string name="voice_recognition_toast">Voice recognition now handled by connected Bluetooth device</string>
</resources>
+8 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import com.android.systemui.statusbar.tv.TvStatusBar;
import com.android.systemui.theme.ThemeOverlayController;
import com.android.systemui.toast.ToastUI;
import com.android.systemui.util.leak.GarbageMonitor;
import com.android.systemui.voicerecognition.car.ConnectedDeviceVoiceRecognitionNotifier;
import com.android.systemui.volume.VolumeUI;

import dagger.Binds;
@@ -174,4 +175,11 @@ public abstract class CarSystemUIBinder {
    @IntoMap
    @ClassKey(ToastUI.class)
    public abstract SystemUI bindToastUI(ToastUI service);

    /** Inject into ConnectedDeviceVoiceRecognitionNotifier. */
    @Binds
    @IntoMap
    @ClassKey(ConnectedDeviceVoiceRecognitionNotifier.class)
    public abstract SystemUI bindConnectedDeviceVoiceRecognitionNotifier(
            ConnectedDeviceVoiceRecognitionNotifier sysui);
}
+95 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.voicerecognition.car;

import android.bluetooth.BluetoothHeadsetClient;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.os.UserHandle;
import android.util.Log;
import android.widget.Toast;

import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
import com.android.systemui.SysUIToast;
import com.android.systemui.SystemUI;
import com.android.systemui.dagger.qualifiers.Main;

import javax.inject.Inject;

/**
 * Controller responsible for showing toast message when voice recognition over bluetooth device
 * getting activated.
 */
public class ConnectedDeviceVoiceRecognitionNotifier extends SystemUI {

    private static final String TAG = "CarVoiceRecognition";
    @VisibleForTesting
    static final int INVALID_VALUE = -1;
    @VisibleForTesting
    static final int VOICE_RECOGNITION_STARTED = 1;

    private Handler mHandler;

    private final BroadcastReceiver mVoiceRecognitionReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (Log.isLoggable(TAG, Log.DEBUG)) {
                Log.d(TAG, "Voice recognition received an intent!");
            }
            if (intent == null
                    || intent.getAction() == null
                    || !BluetoothHeadsetClient.ACTION_AG_EVENT.equals(intent.getAction())
                    || !intent.hasExtra(BluetoothHeadsetClient.EXTRA_VOICE_RECOGNITION)) {
                return;
            }

            int voiceRecognitionState = intent.getIntExtra(
                    BluetoothHeadsetClient.EXTRA_VOICE_RECOGNITION, INVALID_VALUE);

            if (voiceRecognitionState == VOICE_RECOGNITION_STARTED) {
                showToastMessage();
            }
        }
    };

    private void showToastMessage() {
        mHandler.post(() -> SysUIToast.makeText(mContext, R.string.voice_recognition_toast,
                Toast.LENGTH_LONG).show());
    }

    @Inject
    public ConnectedDeviceVoiceRecognitionNotifier(Context context, @Main Handler handler) {
        super(context);
        mHandler = handler;
    }

    @Override
    public void start() {
    }

    @Override
    protected void onBootCompleted() {
        IntentFilter filter = new IntentFilter();
        filter.addAction(BluetoothHeadsetClient.ACTION_AG_EVENT);
        mContext.registerReceiverAsUser(mVoiceRecognitionReceiver, UserHandle.ALL, filter,
                /* broadcastPermission= */ null, /* scheduler= */ null);
    }
}
+97 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.voicerecognition.car;

import static com.android.systemui.voicerecognition.car.ConnectedDeviceVoiceRecognitionNotifier.INVALID_VALUE;
import static com.android.systemui.voicerecognition.car.ConnectedDeviceVoiceRecognitionNotifier.VOICE_RECOGNITION_STARTED;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;

import android.bluetooth.BluetoothHeadsetClient;
import android.content.Intent;
import android.os.Handler;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;

import androidx.test.filters.SmallTest;

import com.android.systemui.SysuiTestCase;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
public class ConnectedDeviceVoiceRecognitionNotifierTest extends SysuiTestCase {

    private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;

    private ConnectedDeviceVoiceRecognitionNotifier mVoiceRecognitionNotifier;
    private Handler mTestHandler;

    @Before
    public void setUp() throws Exception {
        TestableLooper testableLooper = TestableLooper.get(this);
        mTestHandler = spy(new Handler(testableLooper.getLooper()));
        mVoiceRecognitionNotifier = new ConnectedDeviceVoiceRecognitionNotifier(
                mContext, mTestHandler);
        mVoiceRecognitionNotifier.onBootCompleted();
    }

    @Test
    public void testReceiveIntent_started_showToast() {
        Intent intent = new Intent(BluetoothHeadsetClient.ACTION_AG_EVENT);
        intent.putExtra(BluetoothHeadsetClient.EXTRA_VOICE_RECOGNITION, VOICE_RECOGNITION_STARTED);
        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
        waitForIdleSync();

        verify(mTestHandler).post(any());
    }

    @Test
    public void testReceiveIntent_invalidExtra_noToast() {
        Intent intent = new Intent(BluetoothHeadsetClient.ACTION_AG_EVENT);
        intent.putExtra(BluetoothHeadsetClient.EXTRA_VOICE_RECOGNITION, INVALID_VALUE);
        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
        waitForIdleSync();

        verify(mTestHandler, never()).post(any());
    }

    @Test
    public void testReceiveIntent_noExtra_noToast() {
        Intent intent = new Intent(BluetoothHeadsetClient.ACTION_AG_EVENT);
        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
        waitForIdleSync();

        verify(mTestHandler, never()).post(any());
    }

    @Test
    public void testReceiveIntent_invalidIntent_noToast() {
        Intent intent = new Intent(BluetoothHeadsetClient.ACTION_AUDIO_STATE_CHANGED);
        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
        waitForIdleSync();

        verify(mTestHandler, never()).post(any());
    }
}