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

Commit 875d45aa authored by Michael Wright's avatar Michael Wright
Browse files

Show error message when pairing fails in SUW.

Also, prevent multiple dialogs from coming up, dismiss the dialog
when the device goes back into tablet mode and prevent a SysUI crash
when we attempt to stop a scan after the bluetooth adapter turns off.

Bug: 25662777
Change-Id: Ib99eaecb0b60388e1f1efb89199ac4ffdb281536
parent 52cdc159
Loading
Loading
Loading
Loading
+68 −13
Original line number Diff line number Diff line
@@ -38,7 +38,9 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings.Secure;
import android.text.TextUtils;
import android.util.Pair;
import android.util.Slog;
import android.widget.Toast;

import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
@@ -46,6 +48,7 @@ import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.settingslib.bluetooth.Utils;
import com.android.systemui.R;
import com.android.systemui.SystemUI;

@@ -76,8 +79,9 @@ public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeCha
    private static final int STATE_WAITING_FOR_BLUETOOTH = 4;
    private static final int STATE_PAIRING = 5;
    private static final int STATE_PAIRED = 6;
    private static final int STATE_USER_CANCELLED = 7;
    private static final int STATE_DEVICE_NOT_FOUND = 8;
    private static final int STATE_PAIRING_FAILED = 7;
    private static final int STATE_USER_CANCELLED = 8;
    private static final int STATE_DEVICE_NOT_FOUND = 9;

    private static final int MSG_INIT = 0;
    private static final int MSG_ON_BOOT_COMPLETED = 1;
@@ -90,6 +94,7 @@ public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeCha
    private static final int MSG_SHOW_BLUETOOTH_DIALOG = 8;
    private static final int MSG_DISMISS_BLUETOOTH_DIALOG = 9;
    private static final int MSG_BLE_ABORT_SCAN = 10;
    private static final int MSG_SHOW_ERROR = 11;

    private volatile KeyboardHandler mHandler;
    private volatile KeyboardUIHandler mUIHandler;
@@ -178,6 +183,7 @@ public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeCha
        mLocalBluetoothAdapter = bluetoothManager.getBluetoothAdapter();
        mProfileManager = bluetoothManager.getProfileManager();
        bluetoothManager.getEventManager().registerCallback(new BluetoothCallbackHandler());
        Utils.setErrorListener(new BluetoothErrorListener());

        InputManager im = context.getSystemService(InputManager.class);
        im.registerOnTabletModeChangedListener(this, mHandler);
@@ -204,13 +210,15 @@ public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeCha
        if (mInTabletMode != InputManager.SWITCH_STATE_OFF) {
            if (mState == STATE_WAITING_FOR_DEVICE_DISCOVERY) {
                stopScanning();
            } else if (mState == STATE_WAITING_FOR_BLUETOOTH) {
                mUIHandler.sendEmptyMessage(MSG_DISMISS_BLUETOOTH_DIALOG);
            }
            mState = STATE_WAITING_FOR_TABLET_MODE_EXIT;
            return;
        }

        final int btState = mLocalBluetoothAdapter.getState();
        if (btState == BluetoothAdapter.STATE_TURNING_ON || btState == BluetoothAdapter.STATE_ON
        if ((btState == BluetoothAdapter.STATE_TURNING_ON || btState == BluetoothAdapter.STATE_ON)
                && mState == STATE_WAITING_FOR_BLUETOOTH) {
            // If we're waiting for bluetooth but it has come on in the meantime, or is coming
            // on, just dismiss the dialog. This frequently happens during device startup.
@@ -334,7 +342,10 @@ public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeCha

    private void stopScanning() {
        if (mScanCallback != null) {
            mLocalBluetoothAdapter.getBluetoothLeScanner().stopScan(mScanCallback);
            BluetoothLeScanner scanner = mLocalBluetoothAdapter.getBluetoothLeScanner();
            if (scanner != null) {
                scanner.stopScan(mScanCallback);
            }
            mScanCallback = null;
        }
    }
@@ -370,10 +381,14 @@ public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeCha

    // Should only be called on the handler thread
    private void onDeviceBondStateChangedInternal(CachedBluetoothDevice d, int bondState) {
        if (d.getName().equals(mKeyboardName) && bondState == BluetoothDevice.BOND_BONDED) {
            // We don't need to manually connect to the device here because it will automatically
            // try to connect after it has been paired.
        if (mState == STATE_PAIRING && d.getName().equals(mKeyboardName)) {
            if (bondState == BluetoothDevice.BOND_BONDED) {
                // We don't need to manually connect to the device here because it will
                // automatically try to connect after it has been paired.
                mState = STATE_PAIRED;
            } else if (bondState == BluetoothDevice.BOND_NONE) {
                mState = STATE_PAIRING_FAILED;
            }
        }
    }

@@ -385,6 +400,17 @@ public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeCha
        }
    }

    // Should only be called on the handler thread. We want to be careful not to show errors for
    // pairings not initiated by this UI, so we only pop up the toast when we're at an appropriate
    // point in our pairing flow and it's the expected device.
    private void onShowErrorInternal(Context context, String name, int messageResId) {
        if ((mState == STATE_PAIRING || mState == STATE_PAIRING_FAILED)
                && mKeyboardName.equals(name)) {
            String message = context.getString(messageResId, name);
            Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
        }
    }

    private final class KeyboardUIHandler extends Handler {
        public KeyboardUIHandler() {
            super(Looper.getMainLooper(), null, true /*async*/);
@@ -393,19 +419,27 @@ public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeCha
        public void handleMessage(Message msg) {
            switch(msg.what) {
                case MSG_SHOW_BLUETOOTH_DIALOG: {
                    DialogInterface.OnClickListener listener = new BluetoothDialogClickListener();
                    if (mDialog != null) {
                        // Don't show another dialog if one is already present
                        break;
                    }
                    DialogInterface.OnClickListener clickListener =
                            new BluetoothDialogClickListener();
                    DialogInterface.OnDismissListener dismissListener =
                            new BluetoothDialogDismissListener();
                    mDialog = new BluetoothDialog(mContext);
                    mDialog.setTitle(R.string.enable_bluetooth_title);
                    mDialog.setMessage(R.string.enable_bluetooth_message);
                    mDialog.setPositiveButton(R.string.enable_bluetooth_confirmation_ok, listener);
                    mDialog.setNegativeButton(android.R.string.cancel, listener);
                    mDialog.setPositiveButton(
                            R.string.enable_bluetooth_confirmation_ok, clickListener);
                    mDialog.setNegativeButton(android.R.string.cancel, clickListener);
                    mDialog.setOnDismissListener(dismissListener);
                    mDialog.show();
                    break;
                }
                case MSG_DISMISS_BLUETOOTH_DIALOG: {
                    if (mDialog != null) {
                        mDialog.dismiss();
                        mDialog = null;
                    }
                    break;
                }
@@ -469,6 +503,10 @@ public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeCha
                    onBleScanFailedInternal();
                    break;
                }
                case MSG_SHOW_ERROR: {
                    Pair<Context, String> p = (Pair<Context, String>) msg.obj;
                    onShowErrorInternal(p.first, p.second, msg.arg1);
                }
            }
        }
    }
@@ -482,6 +520,14 @@ public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeCha
        }
    }

    private final class BluetoothDialogDismissListener
            implements DialogInterface.OnDismissListener {
        @Override
        public void onDismiss(DialogInterface dialog) {
            mDialog = null;
        }
    }

    private final class KeyboardScanCallback extends ScanCallback {

        private boolean isDeviceDiscoverable(ScanResult result) {
@@ -564,6 +610,13 @@ public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeCha
        public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { }
    }

    private final class BluetoothErrorListener implements Utils.ErrorListener {
        public void onShowError(Context context, String name, int messageResId) {
            mHandler.obtainMessage(MSG_SHOW_ERROR, messageResId, 0 /*unused*/,
                    new Pair<>(context, name)).sendToTarget();
        }
    }

    private static String stateToString(int state) {
        switch (state) {
            case STATE_NOT_ENABLED:
@@ -580,13 +633,15 @@ public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeCha
                return "STATE_PAIRING";
            case STATE_PAIRED:
                return "STATE_PAIRED";
            case STATE_PAIRING_FAILED:
                return "STATE_PAIRING_FAILED";
            case STATE_USER_CANCELLED:
                return "STATE_USER_CANCELLED";
            case STATE_DEVICE_NOT_FOUND:
                return "STATE_DEVICE_NOT_FOUND";
            case STATE_UNKNOWN:
            default:
                return "STATE_UNKNOWN";
                return "STATE_UNKNOWN (" + state + ")";
        }
    }
}