19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.server;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.bluetooth.BluetoothA2dp;
20bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellyimport android.bluetooth.BluetoothAdapter;
2132d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganeshimport android.bluetooth.BluetoothClass;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.bluetooth.BluetoothDevice;
23b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganeshimport android.bluetooth.BluetoothHealth;
24545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganeshimport android.bluetooth.BluetoothInputDevice;
256fdd0c6274c81b337ad35b70480f881daf7354c3Danica Changimport android.bluetooth.BluetoothPan;
2696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganeshimport android.bluetooth.BluetoothProfile;
27d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganeshimport android.bluetooth.BluetoothUuid;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message;
32577dd1f3e274b84876471c22efac578db94811fcJaikumar Ganeshimport android.os.ParcelUuid;
335a1e4cf83f5be1b5d79e2643fa791aa269b6a4bcJaikumar Ganeshimport android.os.PowerManager;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap;
375a1e4cf83f5be1b5d79e2643fa791aa269b6a4bcJaikumar Ganeshimport java.util.List;
38abf9943704f4f71c619d27e0de5f68afdaab5e3bBheemsen Kulkarni
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectclass BluetoothEventLoop {
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "BluetoothEventLoop";
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final boolean DBG = false;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mNativeData;
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Thread mThread;
49b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project    private boolean mStarted;
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mInterrupted;
51bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly
52105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private final HashMap<String, Integer> mPasskeyAgentRequestData;
53a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    private final HashMap<String, Integer> mAuthorizationAgentRequestData;
54bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private final BluetoothService mBluetoothService;
55bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private final BluetoothAdapter mAdapter;
567f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    private final BluetoothAdapterStateMachine mBluetoothState;
5796a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh    private BluetoothA2dp mA2dp;
58105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private final Context mContext;
59abf9943704f4f71c619d27e0de5f68afdaab5e3bBheemsen Kulkarni    // The WakeLock is used for bringing up the LCD during a pairing request
60abf9943704f4f71c619d27e0de5f68afdaab5e3bBheemsen Kulkarni    // from remote device when Android is in Suspend state.
61abf9943704f4f71c619d27e0de5f68afdaab5e3bBheemsen Kulkarni    private PowerManager.WakeLock mWakeLock;
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
63694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie    private static final int EVENT_PAIRING_CONSENT_DELAYED_ACCEPT = 1;
64694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie    private static final int EVENT_AGENT_CANCEL = 2;
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private static final int CREATE_DEVICE_ALREADY_EXISTS = 1;
6716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private static final int CREATE_DEVICE_SUCCESS = 0;
6816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private static final int CREATE_DEVICE_FAILED = -1;
6916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Handler mHandler = new Handler() {
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void handleMessage(Message msg) {
7632d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh            String address = null;
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (msg.what) {
7832d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh            case EVENT_PAIRING_CONSENT_DELAYED_ACCEPT:
7932d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh                address = (String)msg.obj;
8032d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh                if (address != null) {
8132d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh                    mBluetoothService.setPairingConfirmation(address, true);
8232d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh                }
8332d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh                break;
84e5d93b7ed983f98855555d560faf060836f1a52fJaikumar Ganesh            case EVENT_AGENT_CANCEL:
85e5d93b7ed983f98855555d560faf060836f1a52fJaikumar Ganesh                // Set the Bond State to BOND_NONE.
86e5d93b7ed983f98855555d560faf060836f1a52fJaikumar Ganesh                // We always have only 1 device in BONDING state.
87a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                String[] devices = mBluetoothService.listInState(BluetoothDevice.BOND_BONDING);
88e5d93b7ed983f98855555d560faf060836f1a52fJaikumar Ganesh                if (devices.length == 0) {
89e5d93b7ed983f98855555d560faf060836f1a52fJaikumar Ganesh                    break;
90e5d93b7ed983f98855555d560faf060836f1a52fJaikumar Ganesh                } else if (devices.length > 1) {
91e5d93b7ed983f98855555d560faf060836f1a52fJaikumar Ganesh                    Log.e(TAG, " There is more than one device in the Bonding State");
92e5d93b7ed983f98855555d560faf060836f1a52fJaikumar Ganesh                    break;
93e5d93b7ed983f98855555d560faf060836f1a52fJaikumar Ganesh                }
94e5d93b7ed983f98855555d560faf060836f1a52fJaikumar Ganesh                address = devices[0];
95a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                mBluetoothService.setBondState(address,
96e5d93b7ed983f98855555d560faf060836f1a52fJaikumar Ganesh                        BluetoothDevice.BOND_NONE,
97e5d93b7ed983f98855555d560faf060836f1a52fJaikumar Ganesh                        BluetoothDevice.UNBOND_REASON_REMOTE_AUTH_CANCELED);
98e5d93b7ed983f98855555d560faf060836f1a52fJaikumar Ganesh                break;
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static { classInitNative(); }
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static native void classInitNative();
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
106a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    /* package */ BluetoothEventLoop(Context context, BluetoothAdapter adapter,
1077f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                                     BluetoothService bluetoothService,
1087f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                                     BluetoothAdapterStateMachine bluetoothState) {
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBluetoothService = bluetoothService;
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
1117f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        mBluetoothState = bluetoothState;
1129a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        mPasskeyAgentRequestData = new HashMap<String, Integer>();
113a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        mAuthorizationAgentRequestData = new HashMap<String, Integer>();
114bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapter = adapter;
115abf9943704f4f71c619d27e0de5f68afdaab5e3bBheemsen Kulkarni        //WakeLock instantiation in BluetoothEventLoop class
116abf9943704f4f71c619d27e0de5f68afdaab5e3bBheemsen Kulkarni        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
117abf9943704f4f71c619d27e0de5f68afdaab5e3bBheemsen Kulkarni        mWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP
118abf9943704f4f71c619d27e0de5f68afdaab5e3bBheemsen Kulkarni                | PowerManager.ON_AFTER_RELEASE, TAG);
119abf9943704f4f71c619d27e0de5f68afdaab5e3bBheemsen Kulkarni        mWakeLock.setReferenceCounted(false);
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        initializeNativeDataNative();
1217d0548d0944e48421857de4aec2822ced325bea0Jaikumar Ganesh    }
12296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh
1237d0548d0944e48421857de4aec2822ced325bea0Jaikumar Ganesh    /*package*/ void getProfileProxy() {
12496a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        mAdapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.A2DP);
1254ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh        mAdapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.INPUT_DEVICE);
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12896a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh    private BluetoothProfile.ServiceListener mProfileServiceListener =
12996a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        new BluetoothProfile.ServiceListener() {
13096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        public void onServiceConnected(int profile, BluetoothProfile proxy) {
1314ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            if (profile == BluetoothProfile.A2DP) {
1324ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                mA2dp = (BluetoothA2dp) proxy;
1334ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            }
13496a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        }
13596a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        public void onServiceDisconnected(int profile) {
1364ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            if (profile == BluetoothProfile.A2DP) {
1374ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                mA2dp = null;
1384ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            }
13996a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        }
14096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh    };
14196a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh
14296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void finalize() throws Throwable {
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            cleanupNativeDataNative();
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super.finalize();
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
151d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ HashMap<String, Integer> getPasskeyAgentRequestData() {
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mPasskeyAgentRequestData;
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
155a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    /* package */ HashMap<String, Integer> getAuthorizationAgentRequestData() {
156a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        return mAuthorizationAgentRequestData;
157a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    }
158a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie
15928d139fa953c0b3bf2c66d92587e5287ec4dd5abRobert Greenwalt    /* package */ void start() {
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16128d139fa953c0b3bf2c66d92587e5287ec4dd5abRobert Greenwalt        if (!isEventLoopRunningNative()) {
16228d139fa953c0b3bf2c66d92587e5287ec4dd5abRobert Greenwalt            if (DBG) log("Starting Event Loop thread");
16328d139fa953c0b3bf2c66d92587e5287ec4dd5abRobert Greenwalt            startEventLoopNative();
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16628d139fa953c0b3bf2c66d92587e5287ec4dd5abRobert Greenwalt
16728d139fa953c0b3bf2c66d92587e5287ec4dd5abRobert Greenwalt    public void stop() {
16828d139fa953c0b3bf2c66d92587e5287ec4dd5abRobert Greenwalt        if (isEventLoopRunningNative()) {
16928d139fa953c0b3bf2c66d92587e5287ec4dd5abRobert Greenwalt            if (DBG) log("Stopping Event Loop thread");
17028d139fa953c0b3bf2c66d92587e5287ec4dd5abRobert Greenwalt            stopEventLoopNative();
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17428d139fa953c0b3bf2c66d92587e5287ec4dd5abRobert Greenwalt    public boolean isEventLoopRunning() {
17528d139fa953c0b3bf2c66d92587e5287ec4dd5abRobert Greenwalt        return isEventLoopRunningNative();
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1789488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    private void addDevice(String address, String[] properties) {
1799a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        BluetoothDeviceProperties deviceProperties =
1809a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                mBluetoothService.getDeviceProperties();
1819a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        deviceProperties.addProperties(address, properties);
1829a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String rssi = deviceProperties.getProperty(address, "RSSI");
1839a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String classValue = deviceProperties.getProperty(address, "Class");
1849a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String name = deviceProperties.getProperty(address, "Name");
1859488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        short rssiValue;
1869488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        // For incoming connections, we don't get the RSSI value. Use a default of MIN_VALUE.
1879488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        // If we accept the pairing, we will automatically show it at the top of the list.
1889488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        if (rssi != null) {
1899488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh            rssiValue = (short)Integer.valueOf(rssi).intValue();
1909488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        } else {
1919488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh            rssiValue = Short.MIN_VALUE;
1929488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        }
1939488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        if (classValue != null) {
194005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            Intent intent = new Intent(BluetoothDevice.ACTION_FOUND);
195005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
196005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_CLASS,
197005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                    new BluetoothClass(Integer.valueOf(classValue)));
198005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_RSSI, rssiValue);
199005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_NAME, name);
200d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mContext.sendBroadcast(intent, BLUETOOTH_PERM);
202d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        } else {
2039488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh            log ("ClassValue: " + classValue + " for remote device: " + address + " is null");
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2079a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /**
2089a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * Called by native code on a DeviceFound signal from org.bluez.Adapter.
2099a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     *
2109a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param address the MAC address of the new device
2119a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param properties an array of property keys and value strings
2129a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     *
2139a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @see BluetoothDeviceProperties#addProperties(String, String[])
2149a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     */
2159488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    private void onDeviceFound(String address, String[] properties) {
2169488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        if (properties == null) {
2179488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh            Log.e(TAG, "ERROR: Remote device properties are null");
2189488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh            return;
2199488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        }
2209488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        addDevice(address, properties);
2219488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    }
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2239a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /**
2249a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * Called by native code on a DeviceDisappeared signal from
2259a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * org.bluez.Adapter.
2269a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     *
2279a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param address the MAC address of the disappeared device
2289a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     */
2299488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    private void onDeviceDisappeared(String address) {
230005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        Intent intent = new Intent(BluetoothDevice.ACTION_DISAPPEARED);
231005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2359a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /**
2369a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * Called by native code on a DisconnectRequested signal from
2379a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * org.bluez.Device.
2389a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     *
2399a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param deviceObjectPath the object path for the disconnecting device
2409a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     */
2415e59ca8ae4e29efb77acbd5513dcc109ea5dd2b4Jaikumar Ganesh    private void onDeviceDisconnectRequested(String deviceObjectPath) {
2425e59ca8ae4e29efb77acbd5513dcc109ea5dd2b4Jaikumar Ganesh        String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
2435e59ca8ae4e29efb77acbd5513dcc109ea5dd2b4Jaikumar Ganesh        if (address == null) {
2445e59ca8ae4e29efb77acbd5513dcc109ea5dd2b4Jaikumar Ganesh            Log.e(TAG, "onDeviceDisconnectRequested: Address of the remote device in null");
2455e59ca8ae4e29efb77acbd5513dcc109ea5dd2b4Jaikumar Ganesh            return;
2465e59ca8ae4e29efb77acbd5513dcc109ea5dd2b4Jaikumar Ganesh        }
2475e59ca8ae4e29efb77acbd5513dcc109ea5dd2b4Jaikumar Ganesh        Intent intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED);
2485e59ca8ae4e29efb77acbd5513dcc109ea5dd2b4Jaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
2495e59ca8ae4e29efb77acbd5513dcc109ea5dd2b4Jaikumar Ganesh        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
2505e59ca8ae4e29efb77acbd5513dcc109ea5dd2b4Jaikumar Ganesh    }
2515e59ca8ae4e29efb77acbd5513dcc109ea5dd2b4Jaikumar Ganesh
2529a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /**
2539a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * Called by native code for the async response to a CreatePairedDevice
2549a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * method call to org.bluez.Adapter.
2559a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     *
2569a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param address the MAC address of the device to pair
2579a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param result success or error result for the pairing operation
2589a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     */
259d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private void onCreatePairedDeviceResult(String address, int result) {
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
261a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        mBluetoothService.onCreatePairedDeviceResult(address, result);
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2649a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /**
2659a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * Called by native code on a DeviceCreated signal from org.bluez.Adapter.
2669a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     *
2679a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param deviceObjectPath the object path for the created device
2689a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     */
269d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private void onDeviceCreated(String deviceObjectPath) {
2709488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
27102c4b353f7b2427d8a335e41fc336aea7cede8a3Matthew Xie        if (address == null) {
27202c4b353f7b2427d8a335e41fc336aea7cede8a3Matthew Xie            Log.e(TAG, "onDeviceCreated: device address null!" + " deviceObjectPath: " +
27302c4b353f7b2427d8a335e41fc336aea7cede8a3Matthew Xie                  deviceObjectPath);
27402c4b353f7b2427d8a335e41fc336aea7cede8a3Matthew Xie            return;
27502c4b353f7b2427d8a335e41fc336aea7cede8a3Matthew Xie        }
2769488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        if (!mBluetoothService.isRemoteDeviceInCache(address)) {
2779488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh            // Incoming connection, we haven't seen this device, add to cache.
2789488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh            String[] properties = mBluetoothService.getRemoteDeviceProperties(address);
2799488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh            if (properties != null) {
2809488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh                addDevice(address, properties);
2819488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh            }
2829488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        }
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2859a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /**
2869a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * Called by native code on a DeviceRemoved signal from org.bluez.Adapter.
2879a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     *
2889a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param deviceObjectPath the object path for the removed device
2899a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     */
290d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private void onDeviceRemoved(String deviceObjectPath) {
291d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
292081a9b69a79ad16093122002b27320b23ac656e1Jaikumar Ganesh        if (address != null) {
293a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            mBluetoothService.setBondState(address.toUpperCase(), BluetoothDevice.BOND_NONE,
294a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                BluetoothDevice.UNBOND_REASON_REMOVED);
295081a9b69a79ad16093122002b27320b23ac656e1Jaikumar Ganesh            mBluetoothService.setRemoteDeviceProperty(address, "UUIDs", null);
296081a9b69a79ad16093122002b27320b23ac656e1Jaikumar Ganesh        }
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2999a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /**
3009a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * Called by native code on a PropertyChanged signal from
3017f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie     * org.bluez.Adapter. This method is also called from
3027f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie     * {@link BluetoothAdapterStateMachine} to set the "Pairable"
3039a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * property when Bluetooth is enabled.
3049a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     *
3059a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param propValues a string array containing the key and one or more
3069a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     *  values.
3079a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     */
308d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ void onPropertyChanged(String[] propValues) {
3099a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        BluetoothAdapterProperties adapterProperties =
3109a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                mBluetoothService.getAdapterProperties();
3119a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
3129a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        if (adapterProperties.isEmpty()) {
3139519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh            // We have got a property change before
3149519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh            // we filled up our cache.
3159a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            adapterProperties.getAllProperties();
3169519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh        }
317b1ef24473297410872654a6c4ad51c8341b2c40bJaikumar Ganesh        log("Property Changed: " + propValues[0] + " : " + propValues[1]);
318d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String name = propValues[0];
319d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (name.equals("Name")) {
3209a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            adapterProperties.setProperty(name, propValues[1]);
3216a9d93cc1abd0f96c68d6b0a6860acd002e9df3dJaikumar Ganesh            Intent intent = new Intent(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
3226a9d93cc1abd0f96c68d6b0a6860acd002e9df3dJaikumar Ganesh            intent.putExtra(BluetoothAdapter.EXTRA_LOCAL_NAME, propValues[1]);
3236a3c47391066f2eb0f2edb12208a1af37f953b19Jaikumar Ganesh            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
324d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            mContext.sendBroadcast(intent, BLUETOOTH_PERM);
325d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        } else if (name.equals("Pairable") || name.equals("Discoverable")) {
32614e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie            adapterProperties.setProperty(name, propValues[1]);
32714e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie
32814e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie            if (name.equals("Discoverable")) {
32914e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                mBluetoothState.sendMessage(BluetoothAdapterStateMachine.SCAN_MODE_CHANGED);
33014e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie            }
33114e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie
332d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            String pairable = name.equals("Pairable") ? propValues[1] :
3339a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                adapterProperties.getProperty("Pairable");
334d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            String discoverable = name.equals("Discoverable") ? propValues[1] :
3359a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                adapterProperties.getProperty("Discoverable");
336d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
337d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            // This shouldn't happen, unless Adapter Properties are null.
338d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            if (pairable == null || discoverable == null)
339d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                return;
340d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
341bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            int mode = BluetoothService.bluezStringToScanMode(
342d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    pairable.equals("true"),
343d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    discoverable.equals("true"));
344d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            if (mode >= 0) {
345de893f550301a60274e87aa8168225e7a7a42184Nick Pelly                Intent intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
346de893f550301a60274e87aa8168225e7a7a42184Nick Pelly                intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, mode);
347d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
348d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                mContext.sendBroadcast(intent, BLUETOOTH_PERM);
349d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            }
350d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        } else if (name.equals("Discovering")) {
351d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Intent intent;
3529a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            adapterProperties.setProperty(name, propValues[1]);
353d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            if (propValues[1].equals("true")) {
354005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
355d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            } else {
35639657b808f087a41a4161de2f8962023bdb04741Jake Hamby                // Stop the discovery.
35739657b808f087a41a4161de2f8962023bdb04741Jake Hamby                mBluetoothService.cancelDiscovery();
358005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
359d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            }
360d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            mContext.sendBroadcast(intent, BLUETOOTH_PERM);
36184690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh        } else if (name.equals("Devices") || name.equals("UUIDs")) {
3628bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            String value = null;
3638bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            int len = Integer.valueOf(propValues[1]);
3648bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            if (len > 0) {
365efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                StringBuilder str = new StringBuilder();
3668bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                for (int i = 2; i < propValues.length; i++) {
367efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(propValues[i]);
368efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(",");
3698bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                }
370efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                value = str.toString();
371d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            }
3729a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            adapterProperties.setProperty(name, value);
37350b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh            if (name.equals("UUIDs")) {
37450b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh                mBluetoothService.updateBluetoothState(value);
37550b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh            }
376d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        } else if (name.equals("Powered")) {
37714e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie            mBluetoothState.sendMessage(BluetoothAdapterStateMachine.POWER_STATE_CHANGED,
37814e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                propValues[1].equals("true") ? new Boolean(true) : new Boolean(false));
379ff7db40be166844000749de17382e424617e11b2Jaikumar Ganesh        } else if (name.equals("DiscoverableTimeout")) {
3809a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            adapterProperties.setProperty(name, propValues[1]);
381d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
382d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
383d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
3849a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /**
3859a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * Called by native code on a PropertyChanged signal from
3869a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * org.bluez.Device.
3879a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     *
3889a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param deviceObjectPath the object path for the changed device
3899a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param propValues a string array containing the key and one or more
3909a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     *  values.
3919a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     */
392d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private void onDevicePropertyChanged(String deviceObjectPath, String[] propValues) {
393d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String name = propValues[0];
394d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
395d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (address == null) {
396d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "onDevicePropertyChanged: Address of the remote device in null");
397d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return;
398d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
399b1ef24473297410872654a6c4ad51c8341b2c40bJaikumar Ganesh        log("Device property changed: " + address + " property: "
400b1ef24473297410872654a6c4ad51c8341b2c40bJaikumar Ganesh            + name + " value: " + propValues[1]);
401b1ef24473297410872654a6c4ad51c8341b2c40bJaikumar Ganesh
402bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        BluetoothDevice device = mAdapter.getRemoteDevice(address);
403d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (name.equals("Name")) {
4042dfe1011497b743d4d1fa7786610bc9271ae6d0eJaikumar Ganesh            mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
405005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            Intent intent = new Intent(BluetoothDevice.ACTION_NAME_CHANGED);
406005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
407005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_NAME, propValues[1]);
408ee4837b3a08aebd284a2122169e61b8b3f80005eJaikumar Ganesh            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
409d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            mContext.sendBroadcast(intent, BLUETOOTH_PERM);
410269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie        } else if (name.equals("Alias")) {
411269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie            mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
4125bbd4b4f5fc19302fa017ad6afee6eb2d489d91aJeff Brown            Intent intent = new Intent(BluetoothDevice.ACTION_ALIAS_CHANGED);
4135bbd4b4f5fc19302fa017ad6afee6eb2d489d91aJeff Brown            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
4145bbd4b4f5fc19302fa017ad6afee6eb2d489d91aJeff Brown            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
4155bbd4b4f5fc19302fa017ad6afee6eb2d489d91aJeff Brown            mContext.sendBroadcast(intent, BLUETOOTH_PERM);
416d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        } else if (name.equals("Class")) {
4172dfe1011497b743d4d1fa7786610bc9271ae6d0eJaikumar Ganesh            mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
418005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            Intent intent = new Intent(BluetoothDevice.ACTION_CLASS_CHANGED);
419005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
420005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_CLASS,
421005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                    new BluetoothClass(Integer.valueOf(propValues[1])));
422ee4837b3a08aebd284a2122169e61b8b3f80005eJaikumar Ganesh            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
423d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            mContext.sendBroadcast(intent, BLUETOOTH_PERM);
424d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        } else if (name.equals("Connected")) {
4252dfe1011497b743d4d1fa7786610bc9271ae6d0eJaikumar Ganesh            mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
426d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Intent intent = null;
427d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            if (propValues[1].equals("true")) {
428005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                intent = new Intent(BluetoothDevice.ACTION_ACL_CONNECTED);
429b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh                // Set the link timeout to 8000 slots (5 sec timeout)
430b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh                // for bluetooth docks.
431b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh                if (mBluetoothService.isBluetoothDock(address)) {
432b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh                    mBluetoothService.setLinkTimeout(address, 8000);
433b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh                }
434d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            } else {
435005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECTED);
436d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            }
437005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
438ee4837b3a08aebd284a2122169e61b8b3f80005eJaikumar Ganesh            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
439d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            mContext.sendBroadcast(intent, BLUETOOTH_PERM);
440d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        } else if (name.equals("UUIDs")) {
4418bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            String uuid = null;
4428bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            int len = Integer.valueOf(propValues[1]);
4438bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            if (len > 0) {
444efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                StringBuilder str = new StringBuilder();
4458bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                for (int i = 2; i < propValues.length; i++) {
446efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(propValues[i]);
447efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(",");
4488bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                }
449efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                uuid = str.toString();
450d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            }
4518bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            mBluetoothService.setRemoteDeviceProperty(address, name, uuid);
45210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
45310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            // UUIDs have changed, query remote service channel and update cache.
45410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            mBluetoothService.updateDeviceServiceChannelCache(address);
45510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
4561caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            mBluetoothService.sendUuidIntent(address);
4579488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        } else if (name.equals("Paired")) {
4589488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh            if (propValues[1].equals("true")) {
4594226415bd9f376c41d85f4cd2e11da59a866d241Henrik Backlund                // If locally initiated pairing, we will
4604226415bd9f376c41d85f4cd2e11da59a866d241Henrik Backlund                // not go to BOND_BONDED state until we have received a
4614226415bd9f376c41d85f4cd2e11da59a866d241Henrik Backlund                // successful return value in onCreatePairedDeviceResult
462a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                if (null == mBluetoothService.getPendingOutgoingBonding()) {
463a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                    mBluetoothService.setBondState(address, BluetoothDevice.BOND_BONDED);
4644226415bd9f376c41d85f4cd2e11da59a866d241Henrik Backlund                }
4659488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh            } else {
466a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                mBluetoothService.setBondState(address, BluetoothDevice.BOND_NONE);
467efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue                mBluetoothService.setRemoteDeviceProperty(address, "Trusted", "false");
4689488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh            }
469efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        } else if (name.equals("Trusted")) {
470efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            if (DBG)
4719a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                log("set trust state succeeded, value is: " + propValues[1]);
472efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
473d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4769a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /**
4779a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * Called by native code on a PropertyChanged signal from
4789a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * org.bluez.Input.
4799a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     *
4809a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param path the object path for the changed input device
4819a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param propValues a string array containing the key and one or more
4829a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     *  values.
4839a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     */
484545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    private void onInputDevicePropertyChanged(String path, String[] propValues) {
485545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        String address = mBluetoothService.getAddressFromObjectPath(path);
486545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        if (address == null) {
4879a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            Log.e(TAG, "onInputDevicePropertyChanged: Address of the remote device is null");
488545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            return;
489545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        }
4909a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        log("Input Device : Name of Property is: " + propValues[0]);
491545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        boolean state = false;
492545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        if (propValues[1].equals("true")) {
493545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            state = true;
494545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        }
495545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        mBluetoothService.handleInputDevicePropertyChange(address, state);
496545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    }
497545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
4989a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /**
4999a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * Called by native code on a PropertyChanged signal from
5009a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * org.bluez.Network.
5019a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     *
5029a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param deviceObjectPath the object path for the changed PAN device
5039a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param propValues a string array containing the key and one or more
5049a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     *  values.
5059a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     */
5066fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    private void onPanDevicePropertyChanged(String deviceObjectPath, String[] propValues) {
5076fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        String name = propValues[0];
5086fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
5096fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        if (address == null) {
5106fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            Log.e(TAG, "onPanDevicePropertyChanged: Address of the remote device in null");
5116fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            return;
5126fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        }
5136fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        if (DBG) {
5146fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            log("Pan Device property changed: " + address + "  property: "
5156fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang                    + name + " value: "+ propValues[1]);
5166fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        }
5176fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        BluetoothDevice device = mAdapter.getRemoteDevice(address);
5186fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        if (name.equals("Connected")) {
519707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh            if (propValues[1].equals("false")) {
520707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                mBluetoothService.handlePanDeviceStateChange(device,
5215200c8ab721b56025340306bdecca651e6bf2f12Jaikumar Ganesh                                          BluetoothPan.STATE_DISCONNECTED,
5225200c8ab721b56025340306bdecca651e6bf2f12Jaikumar Ganesh                                          BluetoothPan.LOCAL_PANU_ROLE);
523707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh            }
524707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        } else if (name.equals("Interface")) {
525707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh            String iface = propValues[1];
526057898a9b5d50e0d8eed52bdaa74a5f17bf85c1aJaikumar Ganesh            if (!iface.equals("")) {
527057898a9b5d50e0d8eed52bdaa74a5f17bf85c1aJaikumar Ganesh                mBluetoothService.handlePanDeviceStateChange(device, iface,
528057898a9b5d50e0d8eed52bdaa74a5f17bf85c1aJaikumar Ganesh                                              BluetoothPan.STATE_CONNECTED,
529057898a9b5d50e0d8eed52bdaa74a5f17bf85c1aJaikumar Ganesh                                              BluetoothPan.LOCAL_PANU_ROLE);
530057898a9b5d50e0d8eed52bdaa74a5f17bf85c1aJaikumar Ganesh            }
5316fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        }
5326fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    }
5336fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
534b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private String checkPairingRequestAndGetAddress(String objectPath, int nativeData) {
535d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String address = mBluetoothService.getAddressFromObjectPath(objectPath);
536d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (address == null) {
537b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.e(TAG, "Unable to get device address in checkPairingRequestAndGetAddress, " +
538b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  "returning null");
539b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return null;
540d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mPasskeyAgentRequestData.put(address, new Integer(nativeData));
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
544de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        if (mBluetoothService.getBluetoothState() == BluetoothAdapter.STATE_TURNING_OFF) {
545105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            // shutdown path
546b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            mBluetoothService.cancelPairingUserInput(address);
547b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return null;
548105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
54937686069ae1d7db2604c8aef96a79904f6ddd2f3Jaikumar Ganesh        // Set state to BONDING. For incoming connections it will be set here.
55037686069ae1d7db2604c8aef96a79904f6ddd2f3Jaikumar Ganesh        // For outgoing connections, it gets set when we call createBond.
55137686069ae1d7db2604c8aef96a79904f6ddd2f3Jaikumar Ganesh        // Also set it only when the state is not already Bonded, we can sometimes
55237686069ae1d7db2604c8aef96a79904f6ddd2f3Jaikumar Ganesh        // get an authorization request from the remote end if it doesn't have the link key
55337686069ae1d7db2604c8aef96a79904f6ddd2f3Jaikumar Ganesh        // while we still have it.
554a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        if (mBluetoothService.getBondState(address) != BluetoothDevice.BOND_BONDED)
555a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            mBluetoothService.setBondState(address, BluetoothDevice.BOND_BONDING);
556b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return address;
557b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    }
558b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh
5599a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /**
5609a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * Called by native code on a RequestPairingConsent method call to
5619a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * org.bluez.Agent.
5629a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     *
5639a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param objectPath the path of the device to request pairing consent for
5649a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param nativeData a native pointer to the original D-Bus message
5659a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     */
56632d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh    private void onRequestPairingConsent(String objectPath, int nativeData) {
56732d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh        String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
56832d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh        if (address == null) return;
56932d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh
57032d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh        /* The link key will not be stored if the incoming request has MITM
57132d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh         * protection switched on. Unfortunately, some devices have MITM
57232d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh         * switched on even though their capabilities are NoInputNoOutput,
57332d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh         * so we may get this request many times. Also if we respond immediately,
57432d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh         * the other end is unable to handle it. Delay sending the message.
57532d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh         */
576a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        if (mBluetoothService.getBondState(address) == BluetoothDevice.BOND_BONDED) {
57732d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh            Message message = mHandler.obtainMessage(EVENT_PAIRING_CONSENT_DELAYED_ACCEPT);
57832d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh            message.obj = address;
57932d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh            mHandler.sendMessageDelayed(message, 1500);
58032d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh            return;
58132d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh        }
582abf9943704f4f71c619d27e0de5f68afdaab5e3bBheemsen Kulkarni        // Acquire wakelock during PIN code request to bring up LCD display
583abf9943704f4f71c619d27e0de5f68afdaab5e3bBheemsen Kulkarni        mWakeLock.acquire();
58432d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh        Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
58532d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
58632d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
58732d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh                        BluetoothDevice.PAIRING_VARIANT_CONSENT);
58832d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
5899a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        // Release wakelock to allow the LCD to go off after the PIN popup notification.
590abf9943704f4f71c619d27e0de5f68afdaab5e3bBheemsen Kulkarni        mWakeLock.release();
59132d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh        return;
59232d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh    }
59332d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh
5949a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /**
5959a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * Called by native code on a RequestConfirmation method call to
5969a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * org.bluez.Agent.
5979a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     *
5989a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param objectPath the path of the device to confirm the passkey for
5999a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param passkey an integer containing the 6-digit passkey to confirm
6009a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param nativeData a native pointer to the original D-Bus message
6019a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     */
60232d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh    private void onRequestPasskeyConfirmation(String objectPath, int passkey, int nativeData) {
603b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
604b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        if (address == null) return;
605abf9943704f4f71c619d27e0de5f68afdaab5e3bBheemsen Kulkarni        // Acquire wakelock during PIN code request to bring up LCD display
606abf9943704f4f71c619d27e0de5f68afdaab5e3bBheemsen Kulkarni        mWakeLock.acquire();
607005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
608005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
609c88b0c62c52ab76f1277f3c999d795d8ba527028Jaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, passkey);
610005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
61132d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh                BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION);
612b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
6139a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        // Release wakelock to allow the LCD to go off after the PIN popup notification.
614abf9943704f4f71c619d27e0de5f68afdaab5e3bBheemsen Kulkarni        mWakeLock.release();
615b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return;
616b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    }
617b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh
6189a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /**
6199a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * Called by native code on a RequestPasskey method call to
6209a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * org.bluez.Agent.
6219a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     *
6229a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param objectPath the path of the device requesting a passkey
6239a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param nativeData a native pointer to the original D-Bus message
6249a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     */
625b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private void onRequestPasskey(String objectPath, int nativeData) {
626b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
627b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        if (address == null) return;
628abf9943704f4f71c619d27e0de5f68afdaab5e3bBheemsen Kulkarni        // Acquire wakelock during PIN code request to bring up LCD display
629abf9943704f4f71c619d27e0de5f68afdaab5e3bBheemsen Kulkarni        mWakeLock.acquire();
630005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
631005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
632005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
633005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                BluetoothDevice.PAIRING_VARIANT_PASSKEY);
634b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
6359a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        // Release wakelock to allow the LCD to go off after the PIN popup notification.
636abf9943704f4f71c619d27e0de5f68afdaab5e3bBheemsen Kulkarni        mWakeLock.release();
637b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return;
638b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    }
639b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh
6409a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /**
6419a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * Called by native code on a RequestPinCode method call to
6429a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * org.bluez.Agent.
6439a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     *
6449a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param objectPath the path of the device requesting a PIN code
6459a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param nativeData a native pointer to the original D-Bus message
6469a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     */
647b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private void onRequestPinCode(String objectPath, int nativeData) {
648b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
649b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        if (address == null) return;
650105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
6512092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        String pendingOutgoingAddress =
652a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                mBluetoothService.getPendingOutgoingBonding();
653c88b0c62c52ab76f1277f3c999d795d8ba527028Jaikumar Ganesh        BluetoothClass btClass = new BluetoothClass(mBluetoothService.getRemoteClass(address));
654c88b0c62c52ab76f1277f3c999d795d8ba527028Jaikumar Ganesh        int btDeviceClass = btClass.getDeviceClass();
655c88b0c62c52ab76f1277f3c999d795d8ba527028Jaikumar Ganesh
6562092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        if (address.equals(pendingOutgoingAddress)) {
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // we initiated the bonding
6583fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
6593fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            // Check if its a dock
6603fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (mBluetoothService.isBluetoothDock(address)) {
6613fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                String pin = mBluetoothService.getDockPin();
6623fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                mBluetoothService.setPin(address, BluetoothDevice.convertPinToBytes(pin));
6633fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                return;
6643fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
6653fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // try 0000 once if the device looks dumb
667c88b0c62c52ab76f1277f3c999d795d8ba527028Jaikumar Ganesh            switch (btDeviceClass) {
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES:
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case BluetoothClass.Device.AUDIO_VIDEO_PORTABLE_AUDIO:
6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case BluetoothClass.Device.AUDIO_VIDEO_HIFI_AUDIO:
673a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                if (mBluetoothService.attemptAutoPair(address)) return;
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project           }
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
676c88b0c62c52ab76f1277f3c999d795d8ba527028Jaikumar Ganesh
677ac6f13dc68dadb59fcad1df4af478bf0955e6e87Jaikumar Ganesh        if (btDeviceClass == BluetoothClass.Device.PERIPHERAL_KEYBOARD ||
678ac6f13dc68dadb59fcad1df4af478bf0955e6e87Jaikumar Ganesh            btDeviceClass == BluetoothClass.Device.PERIPHERAL_KEYBOARD_POINTING) {
679ac6f13dc68dadb59fcad1df4af478bf0955e6e87Jaikumar Ganesh            // Its a keyboard. Follow the HID spec recommendation of creating the
680f487d72215421a02e5a1b2fbff4618bc5ee185cbJaikumar Ganesh            // passkey and displaying it to the user. If the keyboard doesn't follow
681f487d72215421a02e5a1b2fbff4618bc5ee185cbJaikumar Ganesh            // the spec recommendation, check if the keyboard has a fixed PIN zero
682f487d72215421a02e5a1b2fbff4618bc5ee185cbJaikumar Ganesh            // and pair.
683f487d72215421a02e5a1b2fbff4618bc5ee185cbJaikumar Ganesh            if (mBluetoothService.isFixedPinZerosAutoPairKeyboard(address)) {
684f487d72215421a02e5a1b2fbff4618bc5ee185cbJaikumar Ganesh                mBluetoothService.setPin(address, BluetoothDevice.convertPinToBytes("0000"));
685f487d72215421a02e5a1b2fbff4618bc5ee185cbJaikumar Ganesh                return;
686f487d72215421a02e5a1b2fbff4618bc5ee185cbJaikumar Ganesh            }
687f487d72215421a02e5a1b2fbff4618bc5ee185cbJaikumar Ganesh
688ac6f13dc68dadb59fcad1df4af478bf0955e6e87Jaikumar Ganesh            // Generate a variable PIN. This is not truly random but good enough.
689ac6f13dc68dadb59fcad1df4af478bf0955e6e87Jaikumar Ganesh            int pin = (int) Math.floor(Math.random() * 10000);
690ac6f13dc68dadb59fcad1df4af478bf0955e6e87Jaikumar Ganesh            sendDisplayPinIntent(address, pin);
691ac6f13dc68dadb59fcad1df4af478bf0955e6e87Jaikumar Ganesh            return;
692c88b0c62c52ab76f1277f3c999d795d8ba527028Jaikumar Ganesh        }
693abf9943704f4f71c619d27e0de5f68afdaab5e3bBheemsen Kulkarni        // Acquire wakelock during PIN code request to bring up LCD display
694abf9943704f4f71c619d27e0de5f68afdaab5e3bBheemsen Kulkarni        mWakeLock.acquire();
695005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
696005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
697005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.PAIRING_VARIANT_PIN);
6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
6999a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        // Release wakelock to allow the LCD to go off after the PIN popup notification.
700abf9943704f4f71c619d27e0de5f68afdaab5e3bBheemsen Kulkarni        mWakeLock.release();
701d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return;
7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7049a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /**
7059a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * Called by native code on a DisplayPasskey method call to
7069a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * org.bluez.Agent.
7079a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     *
7089a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param objectPath the path of the device to display the passkey for
7099a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param passkey an integer containing the 6-digit passkey
7109a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param nativeData a native pointer to the original D-Bus message
7119a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     */
71232d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh    private void onDisplayPasskey(String objectPath, int passkey, int nativeData) {
71332d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh        String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
71432d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh        if (address == null) return;
71532d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh
716abf9943704f4f71c619d27e0de5f68afdaab5e3bBheemsen Kulkarni        // Acquire wakelock during PIN code request to bring up LCD display
717abf9943704f4f71c619d27e0de5f68afdaab5e3bBheemsen Kulkarni        mWakeLock.acquire();
71832d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh        Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
71932d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
720c88b0c62c52ab76f1277f3c999d795d8ba527028Jaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, passkey);
72132d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
72232d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh                        BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY);
72332d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
7249a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        //Release wakelock to allow the LCD to go off after the PIN popup notification.
725abf9943704f4f71c619d27e0de5f68afdaab5e3bBheemsen Kulkarni        mWakeLock.release();
72632d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh    }
72732d8571f509c392dca732c243e9b2138c15daecfJaikumar Ganesh
728c88b0c62c52ab76f1277f3c999d795d8ba527028Jaikumar Ganesh    private void sendDisplayPinIntent(String address, int pin) {
729c88b0c62c52ab76f1277f3c999d795d8ba527028Jaikumar Ganesh        // Acquire wakelock during PIN code request to bring up LCD display
730c88b0c62c52ab76f1277f3c999d795d8ba527028Jaikumar Ganesh        mWakeLock.acquire();
731c88b0c62c52ab76f1277f3c999d795d8ba527028Jaikumar Ganesh        Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
732c88b0c62c52ab76f1277f3c999d795d8ba527028Jaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
733c88b0c62c52ab76f1277f3c999d795d8ba527028Jaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, pin);
734c88b0c62c52ab76f1277f3c999d795d8ba527028Jaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
735c88b0c62c52ab76f1277f3c999d795d8ba527028Jaikumar Ganesh                        BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN);
736c88b0c62c52ab76f1277f3c999d795d8ba527028Jaikumar Ganesh        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
737c88b0c62c52ab76f1277f3c999d795d8ba527028Jaikumar Ganesh        //Release wakelock to allow the LCD to go off after the PIN popup notifcation.
738c88b0c62c52ab76f1277f3c999d795d8ba527028Jaikumar Ganesh        mWakeLock.release();
739c88b0c62c52ab76f1277f3c999d795d8ba527028Jaikumar Ganesh    }
740c88b0c62c52ab76f1277f3c999d795d8ba527028Jaikumar Ganesh
7419a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /**
7429a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * Called by native code on a RequestOobData method call to
7439a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * org.bluez.Agent.
7449a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     *
7459a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param objectPath the path of the device requesting OOB data
7469a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param nativeData a native pointer to the original D-Bus message
7479a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     */
7489a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private void onRequestOobData(String objectPath, int nativeData) {
749cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
750cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (address == null) return;
751cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
752cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
753cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
754cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
755cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT);
756cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
757cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    }
758cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
7599a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /**
7609a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * Called by native code on an Authorize method call to org.bluez.Agent.
7619a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     *
7629a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param objectPath the path of the device requesting to be authorized
7639a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param deviceUuid the UUID of the requesting device
764a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie     * @param nativeData reference for native data
7659a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     */
766a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    private void  onAgentAuthorize(String objectPath, String deviceUuid, int nativeData) {
767a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        if (!mBluetoothService.isEnabled()) return;
768545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
769d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String address = mBluetoothService.getAddressFromObjectPath(objectPath);
770d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (address == null) {
771d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "Unable to get device address in onAuthAgentAuthorize");
772a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            return;
773d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean authorized = false;
776dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        ParcelUuid uuid = ParcelUuid.fromString(deviceUuid);
777a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie
778545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        BluetoothDevice device = mAdapter.getRemoteDevice(address);
779a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        mAuthorizationAgentRequestData.put(address, new Integer(nativeData));
780b16c4f7dd92dabf0cc27438a5d3d9ebd203a38b3Jaikumar Ganesh
781b23d4458a91c8e77828fc38ffd81914c2e37d43aNick Pelly        // Bluez sends the UUID of the local service being accessed, _not_ the
782b23d4458a91c8e77828fc38ffd81914c2e37d43aNick Pelly        // remote service
78396a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        if (mA2dp != null &&
78496a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh            (BluetoothUuid.isAudioSource(uuid) || BluetoothUuid.isAvrcpTarget(uuid)
785545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh              || BluetoothUuid.isAdvAudioDist(uuid)) &&
78696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh              !isOtherSinkInNonDisconnectedState(address)) {
78796a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh            authorized = mA2dp.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
788a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            if (authorized && !BluetoothUuid.isAvrcpTarget(uuid)) {
789a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                Log.i(TAG, "First check pass for incoming A2DP / AVRCP connection from " + address);
79070a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh                // Some headsets try to connect AVCTP before AVDTP - against the recommendation
79170a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh                // If AVCTP connection fails, we get stuck in IncomingA2DP state in the state
79270a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh                // machine.  We don't handle AVCTP signals currently. We only send
79370a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh                // intents for AVDTP state changes. We need to handle both of them in
79470a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh                // some cases. For now, just don't move to incoming state in this case.
7950901e601b53b79e5ff37d9aed7acd4291a6ce9dcMatthew Xie                mBluetoothService.notifyIncomingA2dpConnection(address, false);
7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
797a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                Log.i(TAG, "" + authorized +
798a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                      "Incoming A2DP / AVRCP connection from " + address);
799a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                mA2dp.allowIncomingConnect(device, authorized);
8000901e601b53b79e5ff37d9aed7acd4291a6ce9dcMatthew Xie                mBluetoothService.notifyIncomingA2dpConnection(address, true);
8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
802bbd86750570ff75e428b3810dc2e65db558c14b2Jaikumar Ganesh        } else if (BluetoothUuid.isInputDevice(uuid)) {
8034ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            // We can have more than 1 input device connected.
804bbd86750570ff75e428b3810dc2e65db558c14b2Jaikumar Ganesh            authorized = mBluetoothService.getInputDevicePriority(device) >
805bbd86750570ff75e428b3810dc2e65db558c14b2Jaikumar Ganesh                    BluetoothInputDevice.PRIORITY_OFF;
806bbd86750570ff75e428b3810dc2e65db558c14b2Jaikumar Ganesh            if (authorized) {
807bbd86750570ff75e428b3810dc2e65db558c14b2Jaikumar Ganesh                Log.i(TAG, "First check pass for incoming HID connection from " + address);
808bbd86750570ff75e428b3810dc2e65db558c14b2Jaikumar Ganesh                // notify profile state change
809bbd86750570ff75e428b3810dc2e65db558c14b2Jaikumar Ganesh                mBluetoothService.notifyIncomingHidConnection(address);
810bbd86750570ff75e428b3810dc2e65db558c14b2Jaikumar Ganesh            } else {
811bbd86750570ff75e428b3810dc2e65db558c14b2Jaikumar Ganesh                Log.i(TAG, "Rejecting incoming HID connection from " + address);
812bbd86750570ff75e428b3810dc2e65db558c14b2Jaikumar Ganesh                mBluetoothService.allowIncomingProfileConnect(device, authorized);
813bbd86750570ff75e428b3810dc2e65db558c14b2Jaikumar Ganesh            }
814bbd86750570ff75e428b3810dc2e65db558c14b2Jaikumar Ganesh        } else if (BluetoothUuid.isBnep(uuid)) {
815bbd86750570ff75e428b3810dc2e65db558c14b2Jaikumar Ganesh            // PAN doesn't go to the state machine, accept or reject from here
816bbd86750570ff75e428b3810dc2e65db558c14b2Jaikumar Ganesh            authorized = mBluetoothService.allowIncomingTethering();
817bbd86750570ff75e428b3810dc2e65db558c14b2Jaikumar Ganesh            mBluetoothService.allowIncomingProfileConnect(device, authorized);
8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
819d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.i(TAG, "Rejecting incoming " + deviceUuid + " connection from " + address);
820bbd86750570ff75e428b3810dc2e65db558c14b2Jaikumar Ganesh            mBluetoothService.allowIncomingProfileConnect(device, authorized);
8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
822b23d4458a91c8e77828fc38ffd81914c2e37d43aNick Pelly        log("onAgentAuthorize(" + objectPath + ", " + deviceUuid + ") = " + authorized);
8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
825cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    private boolean onAgentOutOfBandDataAvailable(String objectPath) {
826cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!mBluetoothService.isEnabled()) return false;
827cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
828cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        String address = mBluetoothService.getAddressFromObjectPath(objectPath);
829cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (address == null) return false;
830cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
831cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (mBluetoothService.getDeviceOutOfBandData(
832cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            mAdapter.getRemoteDevice(address)) != null) {
833cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            return true;
834cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        }
8351510770165b7bc675e5171560e907c0269dbe0faJaikumar Ganesh        return false;
836cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    }
837cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
83896a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh    private boolean isOtherSinkInNonDisconnectedState(String address) {
8395a1e4cf83f5be1b5d79e2643fa791aa269b6a4bcJaikumar Ganesh        List<BluetoothDevice> devices =
84096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh            mA2dp.getDevicesMatchingConnectionStates(new int[] {BluetoothA2dp.STATE_CONNECTED,
84196a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                                                     BluetoothA2dp.STATE_CONNECTING,
84296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                                                     BluetoothA2dp.STATE_DISCONNECTING});
84396a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh
844577dd1f3e274b84876471c22efac578db94811fcJaikumar Ganesh        if (devices.size() == 0) return false;
8455a1e4cf83f5be1b5d79e2643fa791aa269b6a4bcJaikumar Ganesh        for (BluetoothDevice dev: devices) {
846577dd1f3e274b84876471c22efac578db94811fcJaikumar Ganesh            if (!dev.getAddress().equals(address)) return true;
847577dd1f3e274b84876471c22efac578db94811fcJaikumar Ganesh        }
848577dd1f3e274b84876471c22efac578db94811fcJaikumar Ganesh        return false;
849577dd1f3e274b84876471c22efac578db94811fcJaikumar Ganesh    }
850577dd1f3e274b84876471c22efac578db94811fcJaikumar Ganesh
8519a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /**
8529a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * Called by native code on a Cancel method call to org.bluez.Agent.
8539a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     */
854d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private void onAgentCancel() {
855005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_CANCEL);
856b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
857e5d93b7ed983f98855555d560faf060836f1a52fJaikumar Ganesh
858e5d93b7ed983f98855555d560faf060836f1a52fJaikumar Ganesh        mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_AGENT_CANCEL),
859e5d93b7ed983f98855555d560faf060836f1a52fJaikumar Ganesh                   1500);
860e5d93b7ed983f98855555d560faf060836f1a52fJaikumar Ganesh
861b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return;
8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8649a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /**
8659a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * Called by native code for the async response to a DiscoverServices
8669a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * method call to org.bluez.Adapter.
8679a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     *
8689a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param deviceObjectPath the path for the specified device
8699a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param result true for success; false on error
8709a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     */
8711caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private void onDiscoverServicesResult(String deviceObjectPath, boolean result) {
8721caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
87381f8e3c85ff8d134fc21bd103145202ea7f78e49Staffan Lindvall        if (address == null) return;
87481f8e3c85ff8d134fc21bd103145202ea7f78e49Staffan Lindvall
8751caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        // We don't parse the xml here, instead just query Bluez for the properties.
8761caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        if (result) {
87710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            mBluetoothService.updateRemoteDevicePropertiesCache(address);
8781caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
8791caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mBluetoothService.sendUuidIntent(address);
88016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        mBluetoothService.makeServiceChannelCallbacks(address);
8811caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
8821caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
8839a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /**
8849a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * Called by native code for the async response to a CreateDevice
8859a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * method call to org.bluez.Adapter.
8869a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     *
8879a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param address the MAC address of the device to create
8889a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param result {@link #CREATE_DEVICE_SUCCESS},
8899a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     *  {@link #CREATE_DEVICE_ALREADY_EXISTS} or {@link #CREATE_DEVICE_FAILED}}
8909a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     */
89116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private void onCreateDeviceResult(String address, int result) {
89216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (DBG) log("Result of onCreateDeviceResult:" + result);
89316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
89416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        switch (result) {
89516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        case CREATE_DEVICE_ALREADY_EXISTS:
89616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            String path = mBluetoothService.getObjectPathFromAddress(address);
89716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (path != null) {
89816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                mBluetoothService.discoverServicesNative(path, "");
89916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                break;
90016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
9019a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            Log.w(TAG, "Device exists, but we don't have the bluez path, failing");
90216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // fall-through
90316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        case CREATE_DEVICE_FAILED:
9041caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            mBluetoothService.sendUuidIntent(address);
90516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mBluetoothService.makeServiceChannelCallbacks(address);
90616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            break;
90716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        case CREATE_DEVICE_SUCCESS:
90816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // nothing to do, UUID intent's will be sent via property changed
9091caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
9101caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
9111caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
9129a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /**
9139a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * Called by native code for the async response to a Connect
9149a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * method call to org.bluez.Input.
9159a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     *
9169a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param path the path of the specified input device
9179a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param result Result code of the operation.
9189a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     */
919fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh    private void onInputDeviceConnectionResult(String path, int result) {
920de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        // Success case gets handled by Property Change signal
921fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh        if (result != BluetoothInputDevice.INPUT_OPERATION_SUCCESS) {
922de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            String address = mBluetoothService.getAddressFromObjectPath(path);
923de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            if (address == null) return;
924de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh
925de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            boolean connected = false;
926de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            BluetoothDevice device = mAdapter.getRemoteDevice(address);
9274ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            int state = mBluetoothService.getInputDeviceConnectionState(device);
928de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            if (state == BluetoothInputDevice.STATE_CONNECTING) {
929fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh                if (result == BluetoothInputDevice.INPUT_CONNECT_FAILED_ALREADY_CONNECTED) {
930fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh                    connected = true;
931fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh                } else {
932fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh                    connected = false;
933fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh                }
934de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            } else if (state == BluetoothInputDevice.STATE_DISCONNECTING) {
935fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh                if (result == BluetoothInputDevice.INPUT_DISCONNECT_FAILED_NOT_CONNECTED) {
936fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh                    connected = false;
937fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh                } else {
938fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh                    // There is no better way to handle this, this shouldn't happen
939fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh                    connected = true;
940fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh                }
941de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            } else {
942de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh                Log.e(TAG, "Error onInputDeviceConnectionResult. State is:" + state);
943de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            }
944de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            mBluetoothService.handleInputDevicePropertyChange(address, connected);
945de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        }
946de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh    }
947de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh
9489a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /**
9499a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * Called by native code for the async response to a Connect
9509a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * method call to org.bluez.Network.
9519a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     *
9529a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param path the path of the specified PAN device
9539a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param result Result code of the operation.
9549a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     */
955fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh    private void onPanDeviceConnectionResult(String path, int result) {
9566fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        log ("onPanDeviceConnectionResult " + path + " " + result);
9576fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        // Success case gets handled by Property Change signal
958fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh        if (result != BluetoothPan.PAN_OPERATION_SUCCESS) {
9596fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            String address = mBluetoothService.getAddressFromObjectPath(path);
9606fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            if (address == null) return;
9616fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
9626fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            boolean connected = false;
9636fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            BluetoothDevice device = mAdapter.getRemoteDevice(address);
96474ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            int state = mBluetoothService.getPanDeviceConnectionState(device);
9656fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            if (state == BluetoothPan.STATE_CONNECTING) {
966fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh                if (result == BluetoothPan.PAN_CONNECT_FAILED_ALREADY_CONNECTED) {
967fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh                    connected = true;
968fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh                } else {
969fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh                    connected = false;
970fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh                }
9716fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            } else if (state == BluetoothPan.STATE_DISCONNECTING) {
972fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh                if (result == BluetoothPan.PAN_DISCONNECT_FAILED_NOT_CONNECTED) {
973fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh                    connected = false;
974fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh                } else {
975fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh                    // There is no better way to handle this, this shouldn't happen
976fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh                    connected = true;
977fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh                }
9786fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            } else {
9796fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang                Log.e(TAG, "Error onPanDeviceConnectionResult. State is: "
9806fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang                        + state + " result: "+ result);
9816fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            }
9826fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            int newState = connected? BluetoothPan.STATE_CONNECTED :
9836fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang                BluetoothPan.STATE_DISCONNECTED;
9845200c8ab721b56025340306bdecca651e6bf2f12Jaikumar Ganesh            mBluetoothService.handlePanDeviceStateChange(device, newState,
9855200c8ab721b56025340306bdecca651e6bf2f12Jaikumar Ganesh                                                  BluetoothPan.LOCAL_PANU_ROLE);
9866fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        }
9876fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    }
9886fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
9899a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /**
990b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh     * Called by native code for the async response to a Connect
991b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh     * method call to org.bluez.Health
992b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh     *
993b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh     * @param chanCode The internal id of the channel
994b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh     * @param result Result code of the operation.
995b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh     */
996b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh    private void onHealthDeviceConnectionResult(int chanCode, int result) {
997b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh        log ("onHealthDeviceConnectionResult " + chanCode + " " + result);
998b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh        // Success case gets handled by Property Change signal
999b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh        if (result != BluetoothHealth.HEALTH_OPERATION_SUCCESS) {
1000b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh            mBluetoothService.onHealthDeviceChannelConnectionError(chanCode,
1001b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh                                                 BluetoothHealth.STATE_CHANNEL_DISCONNECTED);
1002b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh        }
1003b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh    }
1004b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh
1005b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh    /**
10069a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * Called by native code on a DeviceDisconnected signal from
10079a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * org.bluez.NetworkServer.
10089a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     *
10099a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param address the MAC address of the disconnected device
10109a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     */
1011c1520ecb41600cd364f03c4c100f927a98924e6aJaikumar Ganesh    private void onNetworkDeviceDisconnected(String address) {
1012c1520ecb41600cd364f03c4c100f927a98924e6aJaikumar Ganesh        BluetoothDevice device = mAdapter.getRemoteDevice(address);
10135200c8ab721b56025340306bdecca651e6bf2f12Jaikumar Ganesh        mBluetoothService.handlePanDeviceStateChange(device, BluetoothPan.STATE_DISCONNECTED,
10145200c8ab721b56025340306bdecca651e6bf2f12Jaikumar Ganesh                                                      BluetoothPan.LOCAL_NAP_ROLE);
1015c1520ecb41600cd364f03c4c100f927a98924e6aJaikumar Ganesh    }
1016c1520ecb41600cd364f03c4c100f927a98924e6aJaikumar Ganesh
10179a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /**
10189a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * Called by native code on a DeviceConnected signal from
10199a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * org.bluez.NetworkServer.
10209a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     *
10219a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param address the MAC address of the connected device
10229a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param iface interface of remote network
10239a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @param destUuid unused UUID parameter
10249a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     */
1025707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh    private void onNetworkDeviceConnected(String address, String iface, int destUuid) {
1026c1520ecb41600cd364f03c4c100f927a98924e6aJaikumar Ganesh        BluetoothDevice device = mAdapter.getRemoteDevice(address);
10275200c8ab721b56025340306bdecca651e6bf2f12Jaikumar Ganesh        mBluetoothService.handlePanDeviceStateChange(device, iface, BluetoothPan.STATE_CONNECTED,
10285200c8ab721b56025340306bdecca651e6bf2f12Jaikumar Ganesh                                                      BluetoothPan.LOCAL_NAP_ROLE);
1029c1520ecb41600cd364f03c4c100f927a98924e6aJaikumar Ganesh    }
1030c1520ecb41600cd364f03c4c100f927a98924e6aJaikumar Ganesh
10312ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
10322ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Called by native code on a PropertyChanged signal from
10332ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * org.bluez.HealthDevice.
10342ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
10352ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param devicePath the object path of the remote device
10362ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param propValues Properties (Name-Value) of the Health Device.
10372ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
10382ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    private void onHealthDevicePropertyChanged(String devicePath, String[] propValues) {
10392ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        log("Health Device : Name of Property is: " + propValues[0] + " Value:" + propValues[1]);
10402ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        mBluetoothService.onHealthDevicePropertyChanged(devicePath, propValues[1]);
10412ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
10422ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
10432ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
10442ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Called by native code on a ChannelCreated/Deleted signal from
10452ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * org.bluez.HealthDevice.
10462ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
10472ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param devicePath the object path of the remote device
10482ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param channelPath the path of the health channel.
10492ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param exists Boolean to indicate if the channel was created or deleted.
10502ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
10512ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    private void onHealthDeviceChannelChanged(String devicePath, String channelPath,
10522ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            boolean exists) {
10532ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        log("Health Device : devicePath: " + devicePath + ":channelPath:" + channelPath +
10542ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                ":exists" + exists);
10552ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        mBluetoothService.onHealthDeviceChannelChanged(devicePath, channelPath, exists);
10562ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
10572ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static void log(String msg) {
10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Log.d(TAG, msg);
10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1061d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1062d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native void initializeNativeDataNative();
1063d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native void startEventLoopNative();
1064d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native void stopEventLoopNative();
1065d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean isEventLoopRunningNative();
1066d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native void cleanupNativeDataNative();
10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1068