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

Commit 00ce0254 authored by hughchen's avatar hughchen
Browse files

Add a subtext to remind user that profile connected fail

This CL add a subtext to remind user that Bluetooth device
is failed to connect profile.

If user meet the one of following condition, Bluetooth device
will show the warning subtext:
1. The result of profile state is STATE_DISCONNECTED after
   Bluetooth device tries to connect profile.
2. There is no response when Bluetooth device tries to connect
   profile for more than 60 second.

Bug: 110920548
Test: make -j42 RunSettingsLibRoboTests
Change-Id: I7342f761a6fb6c7c24869971ba0c613beff9ecc4
parent 07ae3bec
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -1180,4 +1180,7 @@

    <!-- Name of the this device. [CHAR LIMIT=30] -->
    <string name="media_transfer_this_device_name">This device</string>

    <!-- Warning message to tell user is have problem during profile connect, it need to turn off device and back on. [CHAR_LIMIT=NONE] -->
    <string name="profile_connect_timeout_subtext">Problem connecting. Turn device off &amp; back on</string>
</resources>
+86 −0
Original line number Diff line number Diff line
@@ -24,6 +24,9 @@ import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelUuid;
import android.os.SystemClock;
import android.text.TextUtils;
@@ -55,6 +58,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
    // Some Hearing Aids (especially the 2nd device) needs more time to do service discovery
    private static final long MAX_HEARING_AIDS_DELAY_FOR_AUTO_CONNECT = 15000;
    private static final long MAX_HOGP_DELAY_FOR_AUTO_CONNECT = 30000;
    private static final long MAX_MEDIA_PROFILE_CONNECT_DELAY = 60000;

    private final Context mContext;
    private final BluetoothAdapter mLocalAdapter;
@@ -90,9 +94,35 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
    private boolean mIsActiveDeviceA2dp = false;
    private boolean mIsActiveDeviceHeadset = false;
    private boolean mIsActiveDeviceHearingAid = false;
    // Media profile connect state
    private boolean mIsA2dpProfileConnectedFail = false;
    private boolean mIsHeadsetProfileConnectedFail = false;
    private boolean mIsHearingAidProfileConnectedFail = false;
    // Group second device for Hearing Aid
    private CachedBluetoothDevice mSubDevice;

    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case BluetoothProfile.A2DP:
                    mIsA2dpProfileConnectedFail = true;
                    break;
                case BluetoothProfile.HEADSET:
                    mIsHeadsetProfileConnectedFail = true;
                    break;
                case BluetoothProfile.HEARING_AID:
                    mIsHearingAidProfileConnectedFail = true;
                    break;
                default:
                    Log.w(TAG, "handleMessage(): unknown message : " + msg.what);
                    break;
            }
            Log.w(TAG, "Connect to profile : " + msg.what + " timeout, show error message !");
            refresh();
        }
    };

    CachedBluetoothDevice(Context context, LocalBluetoothProfileManager profileManager,
            BluetoothDevice device) {
        mContext = context;
@@ -133,6 +163,35 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
        }

        synchronized (mProfileLock) {
            if (profile instanceof A2dpProfile || profile instanceof HeadsetProfile
                    || profile instanceof HearingAidProfile) {
                setProfileConnectedStatus(profile.getProfileId(), false);
                switch (newProfileState) {
                    case BluetoothProfile.STATE_CONNECTED:
                        mHandler.removeMessages(profile.getProfileId());
                        break;
                    case BluetoothProfile.STATE_CONNECTING:
                        mHandler.sendEmptyMessageDelayed(profile.getProfileId(),
                                MAX_MEDIA_PROFILE_CONNECT_DELAY);
                        break;
                    case BluetoothProfile.STATE_DISCONNECTING:
                        if (mHandler.hasMessages(profile.getProfileId())) {
                            mHandler.removeMessages(profile.getProfileId());
                        }
                        break;
                    case BluetoothProfile.STATE_DISCONNECTED:
                        if (mHandler.hasMessages(profile.getProfileId())) {
                            mHandler.removeMessages(profile.getProfileId());
                            setProfileConnectedStatus(profile.getProfileId(), true);
                        }
                        break;
                    default:
                        Log.w(TAG, "onProfileStateChanged(): unknown profile state : "
                                + newProfileState);
                        break;
                }
            }

            if (newProfileState == BluetoothProfile.STATE_CONNECTED) {
                if (profile instanceof MapProfile) {
                    profile.setPreferred(mDevice, true);
@@ -162,6 +221,24 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
        fetchActiveDevices();
    }

    @VisibleForTesting
    void setProfileConnectedStatus(int profileId, boolean isFailed) {
        switch (profileId) {
            case BluetoothProfile.A2DP:
                mIsA2dpProfileConnectedFail = isFailed;
                break;
            case BluetoothProfile.HEADSET:
                mIsHeadsetProfileConnectedFail = isFailed;
                break;
            case BluetoothProfile.HEARING_AID:
                mIsHearingAidProfileConnectedFail = isFailed;
                break;
            default:
                Log.w(TAG, "setProfileConnectedStatus(): unknown profile id : " + profileId);
                break;
        }
    }

    public void disconnect() {
        synchronized (mProfileLock) {
            for (LocalBluetoothProfile profile : mProfiles) {
@@ -844,6 +921,10 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
        int leftBattery = -1;
        int rightBattery = -1;

        if (isProfileConnectedFail() && isConnected()) {
            return mContext.getString(R.string.profile_connect_timeout_subtext);
        }

        synchronized (mProfileLock) {
            for (LocalBluetoothProfile profile : getProfiles()) {
                int connectionStatus = getProfileConnectionState(profile);
@@ -943,6 +1024,11 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
        return leftBattery >= 0 && rightBattery >= 0;
    }

    private boolean isProfileConnectedFail() {
        return mIsA2dpProfileConnectedFail || mIsHearingAidProfileConnectedFail
                || mIsHeadsetProfileConnectedFail;
    }

    /**
     * @return resource for android auto string that describes the connection state of this device.
     */
+15 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -31,6 +32,8 @@ import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.media.AudioManager;

import com.android.settingslib.R;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -922,4 +925,16 @@ public class CachedBluetoothDeviceTest {
        assertThat(subCachedDevice.mJustDiscovered).isEqualTo(JUSTDISCOVERED_1);
        assertThat(subCachedDevice.mDevice).isEqualTo(mDevice);
    }

    @Test
    public void getConnectionSummary_profileConnectedFail_showErrorMessage() {
        final A2dpProfile profle = mock(A2dpProfile.class);
        mCachedDevice.onProfileStateChanged(profle, BluetoothProfile.STATE_CONNECTED);
        mCachedDevice.setProfileConnectedStatus(BluetoothProfile.A2DP, true);

        when(profle.getConnectionStatus(mDevice)).thenReturn(BluetoothProfile.STATE_CONNECTED);

        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
                mContext.getString(R.string.profile_connect_timeout_subtext));
    }
}