1/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.car;
18
19import android.bluetooth.BluetoothAdapter;
20import android.bluetooth.BluetoothManager;
21
22import android.bluetooth.le.AdvertiseCallback;
23import android.bluetooth.le.AdvertiseData;
24import android.bluetooth.le.AdvertiseSettings;
25import android.bluetooth.le.BluetoothLeAdvertiser;
26import android.content.Context;
27import android.content.res.Resources;
28import android.os.ParcelUuid;
29import android.util.Log;
30
31import java.nio.ByteBuffer;
32import java.nio.ByteOrder;
33import java.util.Arrays;
34
35/**
36 * An advertiser for the Bluetooth LE based Fast Pair service.
37 * FastPairProvider enables easy Bluetooth pairing between a peripheral and a phone participating in
38 * the Fast Pair Seeker role.  When the seeker finds a compatible peripheral a notification prompts
39 * the user to begin pairing if desired.  A peripheral should call startAdvertising when it is
40 * appropriate to pair, and stopAdvertising when pairing is complete or it is no longer appropriate
41 * to pair.
42 */
43class FastPairProvider {
44
45    private static final String TAG = "FastPairProvider";
46    private static final boolean DBG = Utils.DBG;
47
48    // Service ID assigned for FastPair.
49    private static final ParcelUuid FastPairServiceUuid = ParcelUuid
50            .fromString("0000FE2C-0000-1000-8000-00805f9b34fb");
51
52    private AdvertiseSettings mSettings;
53    private AdvertiseData mData;
54    private BluetoothLeAdvertiser mBluetoothLeAdvertiser;
55    private AdvertiseCallback mAdvertiseCallback;
56
57
58    FastPairProvider(Context context) {
59        Resources res = context.getResources();
60        int modelId = res.getInteger(R.integer.fastPairModelId);
61        if (modelId == 0) {
62            Log.w(TAG, "Model ID undefined, disabling");
63            return;
64        }
65
66        BluetoothManager bluetoothManager = (BluetoothManager) context.getSystemService(
67                Context.BLUETOOTH_SERVICE);
68        if (bluetoothManager != null) {
69            BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
70            if (bluetoothAdapter != null) {
71                mBluetoothLeAdvertiser = bluetoothAdapter.getBluetoothLeAdvertiser();
72            }
73        }
74
75        AdvertiseSettings.Builder settingsBuilder = new AdvertiseSettings.Builder();
76        settingsBuilder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY);
77        settingsBuilder.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH);
78        settingsBuilder.setConnectable(true);
79        settingsBuilder.setTimeout(0);
80        mSettings = settingsBuilder.build();
81
82        AdvertiseData.Builder dataBuilder = new AdvertiseData.Builder();
83        ByteBuffer modelIdBytes = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(
84                modelId);
85        byte[] fastPairServiceData = Arrays.copyOfRange(modelIdBytes.array(), 0, 3);
86        dataBuilder.addServiceData(FastPairServiceUuid, fastPairServiceData);
87        dataBuilder.setIncludeTxPowerLevel(true).build();
88        mData = dataBuilder.build();
89
90        mAdvertiseCallback = new FastPairAdvertiseCallback();
91    }
92
93    /* register the BLE advertisement using the model id provided during construction */
94    boolean startAdvertising() {
95        if (mBluetoothLeAdvertiser != null) {
96            mBluetoothLeAdvertiser.startAdvertising(mSettings, mData, mAdvertiseCallback);
97            return true;
98        }
99        return false;
100    }
101
102    /* unregister the BLE advertisement. */
103    boolean stopAdvertising() {
104        if (mBluetoothLeAdvertiser != null) {
105            mBluetoothLeAdvertiser.stopAdvertising(mAdvertiseCallback);
106            return true;
107        }
108        return false;
109    }
110
111    /* Callback to handle status when advertising starts. */
112    private class FastPairAdvertiseCallback extends AdvertiseCallback {
113        @Override
114        public void onStartFailure(int errorCode) {
115            super.onStartFailure(errorCode);
116            if (DBG) Log.d(TAG, "Advertising failed");
117        }
118
119        @Override
120        public void onStartSuccess(AdvertiseSettings settingsInEffect) {
121            super.onStartSuccess(settingsInEffect);
122            if (DBG) Log.d(TAG, "Advertising successfully started");
123        }
124    }
125}
126