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

Commit 1b0b6c90 authored by Jason Hsu's avatar Jason Hsu Committed by Automerger Merge Worker
Browse files

Merge "Pop up pairing another ear dialog when detecting hearing aid is a set"...

Merge "Pop up pairing another ear dialog when detecting hearing aid is a set" into tm-dev am: 13438e60

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Settings/+/17291804



Change-Id: I828626ed6844804f8314e90fba766c01f161f699
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents cf507b60 13438e60
Loading
Loading
Loading
Loading
+15 −1
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import com.android.settings.R;
import com.android.settings.bluetooth.BluetoothDeviceDetailsFragment;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.SubSettingLauncher;
import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.HearingAidProfile;
@@ -54,7 +55,7 @@ import java.util.concurrent.FutureTask;
 * Controller that shows and updates the bluetooth device name
 */
public class AccessibilityHearingAidPreferenceController extends BasePreferenceController
        implements LifecycleObserver, OnStart, OnStop {
        implements LifecycleObserver, OnStart, OnStop, BluetoothCallback {
    private static final String TAG = "AccessibilityHearingAidPreferenceController";
    private Preference mHearingAidPreference;

@@ -109,11 +110,13 @@ public class AccessibilityHearingAidPreferenceController extends BasePreferenceC
        filter.addAction(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
        mContext.registerReceiver(mHearingAidChangedReceiver, filter);
        mLocalBluetoothManager.getEventManager().registerCallback(this);
    }

    @Override
    public void onStop() {
        mContext.unregisterReceiver(mHearingAidChangedReceiver);
        mLocalBluetoothManager.getEventManager().unregisterCallback(this);
    }

    @Override
@@ -159,6 +162,17 @@ public class AccessibilityHearingAidPreferenceController extends BasePreferenceC
                        R.string.accessibility_hearingaid_right_side_device_summary, name);
    }

    @Override
    public void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile) {
        if (activeDevice == null) {
            return;
        }

        if (bluetoothProfile == BluetoothProfile.HEARING_AID) {
            HearingAidUtils.launchHearingAidPairingDialog(mFragmentManager, activeDevice);
        }
    }

    public void setFragmentManager(FragmentManager fragmentManager) {
        mFragmentManager = fragmentManager;
    }
+59 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.settings.accessibility;

import android.util.Log;

import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentManager;

import com.android.settings.bluetooth.HearingAidPairingDialogFragment;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.HearingAidProfile;

/** Provides utility methods related hearing aids. */
public final class HearingAidUtils {
    private static final String TAG = "HearingAidUtils";

    private HearingAidUtils(){}

    /**
     * Launches pairing dialog when hearing aid device needs other side of hearing aid device to
     * work.
     *
     * @param fragmentManager The {@link FragmentManager} used to show dialog fragment
     * @param device The {@link CachedBluetoothDevice} need to be hearing aid device
     */
    public static void launchHearingAidPairingDialog(FragmentManager fragmentManager,
            @NonNull CachedBluetoothDevice device) {
        if (device.isConnectedHearingAidDevice()
                && device.getDeviceMode() == HearingAidProfile.DeviceMode.MODE_BINAURAL
                && device.getSubDevice() == null) {
            launchHearingAidPairingDialogInternal(fragmentManager, device);
        }
    }

    private static void launchHearingAidPairingDialogInternal(FragmentManager fragmentManager,
            @NonNull CachedBluetoothDevice device) {
        if (device.getDeviceSide() == HearingAidProfile.DeviceSide.SIDE_INVALID) {
            Log.w(TAG, "Can not launch hearing aid pairing dialog for invalid side");
            return;
        }
        HearingAidPairingDialogFragment.newInstance(device).show(fragmentManager,
                HearingAidPairingDialogFragment.TAG);
    }
}
+88 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.settings.bluetooth;

import android.app.Dialog;
import android.app.settings.SettingsEnums;
import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;

import com.android.settings.R;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.HearingAidProfile;

/**
 * Provides a dialog to pair another side of hearing aid device.
 */
public class HearingAidPairingDialogFragment extends InstrumentedDialogFragment {
    public static final String TAG = "HearingAidPairingDialogFragment";
    private static final String KEY_CACHED_DEVICE_SIDE = "cached_device_side";

    /**
     * Creates a new {@link HearingAidPairingDialogFragment} and shows pair another side of hearing
     * aid device according to {@code CachedBluetoothDevice} side.
     *
     * @param device The remote Bluetooth device, that needs to be hearing aid device.
     * @return a DialogFragment
     */
    public static HearingAidPairingDialogFragment newInstance(CachedBluetoothDevice device) {
        Bundle args = new Bundle(1);
        args.putInt(KEY_CACHED_DEVICE_SIDE, device.getDeviceSide());
        final HearingAidPairingDialogFragment fragment = new HearingAidPairingDialogFragment();
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public int getMetricsCategory() {
        // TODO(b/225117454): Need to update SettingsEnums later
        return SettingsEnums.ACCESSIBILITY;
    }

    @NonNull
    @Override
    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
        final int deviceSide = getArguments().getInt(KEY_CACHED_DEVICE_SIDE);
        final int titleId = R.string.bluetooth_pair_other_ear_dialog_title;
        final int messageId = (deviceSide == HearingAidProfile.DeviceSide.SIDE_LEFT)
                        ? R.string.bluetooth_pair_other_ear_dialog_left_ear_message
                        : R.string.bluetooth_pair_other_ear_dialog_right_ear_message;
        final int pairBtnId = (deviceSide == HearingAidProfile.DeviceSide.SIDE_LEFT)
                        ? R.string.bluetooth_pair_other_ear_dialog_right_ear_positive_button
                        : R.string.bluetooth_pair_other_ear_dialog_left_ear_positive_button;

        return new AlertDialog.Builder(getActivity())
                .setTitle(titleId)
                .setMessage(messageId)
                .setNegativeButton(
                        android.R.string.cancel, /* listener= */ null)
                .setPositiveButton(pairBtnId, (dialog, which) -> positiveButtonListener())
                .create();
    }

    private void positiveButtonListener() {
        new SubSettingLauncher(getActivity())
                .setDestination(BluetoothPairingDetail.class.getName())
                .setSourceMetricsCategory(SettingsEnums.ACCESSIBILITY)
                .launch();
    }
}
+18 −0
Original line number Diff line number Diff line
@@ -17,22 +17,26 @@ package com.android.settings.connecteddevice;

import static com.android.settingslib.Utils.isAudioModeOngoingCall;

import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.pm.PackageManager;
import android.util.Log;

import androidx.annotation.VisibleForTesting;
import androidx.fragment.app.FragmentManager;
import androidx.preference.Preference;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceScreen;

import com.android.settings.R;
import com.android.settings.accessibility.HearingAidUtils;
import com.android.settings.bluetooth.AvailableMediaBluetoothDeviceUpdater;
import com.android.settings.bluetooth.BluetoothDeviceUpdater;
import com.android.settings.bluetooth.Utils;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnStart;
@@ -54,6 +58,7 @@ public class AvailableMediaDeviceGroupController extends BasePreferenceControlle
    @VisibleForTesting
    LocalBluetoothManager mLocalBluetoothManager;
    private BluetoothDeviceUpdater mBluetoothDeviceUpdater;
    private FragmentManager mFragmentManager;

    public AvailableMediaDeviceGroupController(Context context) {
        super(context, KEY);
@@ -124,6 +129,7 @@ public class AvailableMediaDeviceGroupController extends BasePreferenceControlle
    }

    public void init(DashboardFragment fragment) {
        mFragmentManager = fragment.getParentFragmentManager();
        mBluetoothDeviceUpdater = new AvailableMediaBluetoothDeviceUpdater(fragment.getContext(),
                fragment, AvailableMediaDeviceGroupController.this);
    }
@@ -138,6 +144,18 @@ public class AvailableMediaDeviceGroupController extends BasePreferenceControlle
        updateTitle();
    }

    @Override
    public void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile) {
        // exclude inactive device
        if (activeDevice == null) {
            return;
        }

        if (bluetoothProfile == BluetoothProfile.HEARING_AID) {
            HearingAidUtils.launchHearingAidPairingDialog(mFragmentManager, activeDevice);
        }
    }

    private void updateTitle() {
        if (isAudioModeOngoingCall(mContext)) {
            // in phone call
+27 −1
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.settings.accessibility;
import static com.google.common.truth.Truth.assertThat;

import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -32,12 +33,16 @@ import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
import android.content.Intent;

import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentActivity;
import androidx.preference.Preference;

import com.android.settings.R;
import com.android.settings.bluetooth.Utils;
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
import com.android.settingslib.bluetooth.BluetoothEventManager;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.HearingAidProfile;
@@ -59,6 +64,7 @@ import org.robolectric.shadows.ShadowApplication;
import java.util.ArrayList;
import java.util.List;

/** Tests for {@link AccessibilityHearingAidPreferenceController}. */
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowBluetoothAdapter.class, ShadowBluetoothUtils.class})
public class AccessibilityHearingAidPreferenceControllerTest {
@@ -84,6 +90,8 @@ public class AccessibilityHearingAidPreferenceControllerTest {
    @Mock
    private LocalBluetoothManager mLocalBluetoothManager;
    @Mock
    private BluetoothEventManager mEventManager;
    @Mock
    private LocalBluetoothProfileManager mLocalBluetoothProfileManager;
    @Mock
    private HearingAidProfile mHearingAidProfile;
@@ -221,6 +229,24 @@ public class AccessibilityHearingAidPreferenceControllerTest {
        assertThat(mPreferenceController.getConnectedHearingAidDevice()).isNull();
    }

    @Test
    @Config(shadows = ShadowAlertDialogCompat.class)
    public void onActiveDeviceChanged_hearingAidProfile_launchHearingAidPairingDialog() {
        final FragmentActivity mActivity = Robolectric.setupActivity(FragmentActivity.class);
        when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true);
        when(mCachedBluetoothDevice.getDeviceMode()).thenReturn(
                HearingAidProfile.DeviceMode.MODE_BINAURAL);
        when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
                HearingAidProfile.DeviceSide.SIDE_LEFT);
        mPreferenceController.setFragmentManager(mActivity.getSupportFragmentManager());

        mPreferenceController.onActiveDeviceChanged(mCachedBluetoothDevice,
                BluetoothProfile.HEARING_AID);

        final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
        assertThat(dialog.isShowing()).isTrue();
    }

    private void setupBluetoothEnvironment() {
        ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager;
        mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
@@ -229,6 +255,7 @@ public class AccessibilityHearingAidPreferenceControllerTest {
        when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager);
        when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager);
        when(mLocalBluetoothProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile);
        doReturn(mEventManager).when(mLocalBluetoothManager).getEventManager();
    }

    private void setupHearingAidEnvironment() {
@@ -239,7 +266,6 @@ public class AccessibilityHearingAidPreferenceControllerTest {
        mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID);
        when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedBluetoothDevice);
        when(mCachedBluetoothDevice.getName()).thenReturn(TEST_DEVICE_NAME);
        when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true);
    }

    private void sendIntent(Intent intent) {
Loading