aboutsummaryrefslogtreecommitdiff
path: root/service/src/com/android/car/FastPairProvider.java
blob: ff5973236f75c2d7988d29853c2f61f6dd022b8d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.car;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager;

import android.bluetooth.le.AdvertiseCallback;
import android.bluetooth.le.AdvertiseData;
import android.bluetooth.le.AdvertiseSettings;
import android.bluetooth.le.BluetoothLeAdvertiser;
import android.content.Context;
import android.content.res.Resources;
import android.os.ParcelUuid;
import android.util.Log;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;

/**
 * An advertiser for the Bluetooth LE based Fast Pair service.
 * FastPairProvider enables easy Bluetooth pairing between a peripheral and a phone participating in
 * the Fast Pair Seeker role.  When the seeker finds a compatible peripheral a notification prompts
 * the user to begin pairing if desired.  A peripheral should call startAdvertising when it is
 * appropriate to pair, and stopAdvertising when pairing is complete or it is no longer appropriate
 * to pair.
 */
class FastPairProvider {

    private static final String TAG = "FastPairProvider";
    private static final boolean DBG = Utils.DBG;

    // Service ID assigned for FastPair.
    private static final ParcelUuid FastPairServiceUuid = ParcelUuid
            .fromString("0000FE2C-0000-1000-8000-00805f9b34fb");

    private AdvertiseSettings mSettings;
    private AdvertiseData mData;
    private BluetoothLeAdvertiser mBluetoothLeAdvertiser;
    private AdvertiseCallback mAdvertiseCallback;


    FastPairProvider(Context context) {
        Resources res = context.getResources();
        int modelId = res.getInteger(R.integer.fastPairModelId);
        if (modelId == 0) {
            Log.w(TAG, "Model ID undefined, disabling");
            return;
        }

        BluetoothManager bluetoothManager = (BluetoothManager) context.getSystemService(
                Context.BLUETOOTH_SERVICE);
        if (bluetoothManager != null) {
            BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
            if (bluetoothAdapter != null) {
                mBluetoothLeAdvertiser = bluetoothAdapter.getBluetoothLeAdvertiser();
            }
        }

        AdvertiseSettings.Builder settingsBuilder = new AdvertiseSettings.Builder();
        settingsBuilder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY);
        settingsBuilder.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH);
        settingsBuilder.setConnectable(true);
        settingsBuilder.setTimeout(0);
        mSettings = settingsBuilder.build();

        AdvertiseData.Builder dataBuilder = new AdvertiseData.Builder();
        ByteBuffer modelIdBytes = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(
                modelId);
        byte[] fastPairServiceData = Arrays.copyOfRange(modelIdBytes.array(), 0, 3);
        dataBuilder.addServiceData(FastPairServiceUuid, fastPairServiceData);
        dataBuilder.setIncludeTxPowerLevel(true).build();
        mData = dataBuilder.build();

        mAdvertiseCallback = new FastPairAdvertiseCallback();
    }

    /* register the BLE advertisement using the model id provided during construction */
    boolean startAdvertising() {
        if (mBluetoothLeAdvertiser != null) {
            mBluetoothLeAdvertiser.startAdvertising(mSettings, mData, mAdvertiseCallback);
            return true;
        }
        return false;
    }

    /* unregister the BLE advertisement. */
    boolean stopAdvertising() {
        if (mBluetoothLeAdvertiser != null) {
            mBluetoothLeAdvertiser.stopAdvertising(mAdvertiseCallback);
            return true;
        }
        return false;
    }

    /* Callback to handle status when advertising starts. */
    private class FastPairAdvertiseCallback extends AdvertiseCallback {
        @Override
        public void onStartFailure(int errorCode) {
            super.onStartFailure(errorCode);
            if (DBG) Log.d(TAG, "Advertising failed");
        }

        @Override
        public void onStartSuccess(AdvertiseSettings settingsInEffect) {
            super.onStartSuccess(settingsInEffect);
            if (DBG) Log.d(TAG, "Advertising successfully started");
        }
    }
}