aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/com/google/android/mobly/snippet/bundled/BluetoothLeScannerSnippet.java
blob: 7e133d1c8b5209d73f0e0cd4eed5084a7466bb96 (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
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
 * Copyright (C) 2017 Google Inc.
 *
 * 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.google.android.mobly.snippet.bundled;

import android.annotation.TargetApi;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.os.Build;
import android.os.Bundle;
import com.google.android.mobly.snippet.Snippet;
import com.google.android.mobly.snippet.bundled.utils.JsonSerializer;
import com.google.android.mobly.snippet.bundled.utils.MbsEnums;
import com.google.android.mobly.snippet.event.EventCache;
import com.google.android.mobly.snippet.event.SnippetEvent;
import com.google.android.mobly.snippet.rpc.AsyncRpc;
import com.google.android.mobly.snippet.rpc.Rpc;
import com.google.android.mobly.snippet.rpc.RpcMinSdk;
import com.google.android.mobly.snippet.util.Log;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/** Snippet class exposing Android APIs in WifiManager. */
@TargetApi(Build.VERSION_CODES.LOLLIPOP_MR1)
public class BluetoothLeScannerSnippet implements Snippet {
    private static class BluetoothLeScanSnippetException extends Exception {
        private static final long serialVersionUID = 1;

        public BluetoothLeScanSnippetException(String msg) {
            super(msg);
        }
    }

    private final BluetoothLeScanner mScanner;
    private final EventCache mEventCache = EventCache.getInstance();
    private final HashMap<String, ScanCallback> mScanCallbacks = new HashMap<>();
    private final JsonSerializer mJsonSerializer = new JsonSerializer();

    public BluetoothLeScannerSnippet() {
        mScanner = BluetoothAdapter.getDefaultAdapter().getBluetoothLeScanner();
    }

    /**
     * Start a BLE scan.
     *
     * @param callbackId
     * @throws BluetoothLeScanSnippetException
     */
    @RpcMinSdk(Build.VERSION_CODES.LOLLIPOP_MR1)
    @AsyncRpc(description = "Start BLE scan.")
    public void bleStartScan(String callbackId) throws BluetoothLeScanSnippetException {
        if (!BluetoothAdapter.getDefaultAdapter().isEnabled()) {
            throw new BluetoothLeScanSnippetException(
                    "Bluetooth is disabled, cannot start BLE scan.");
        }
        DefaultScanCallback callback = new DefaultScanCallback(callbackId);
        mScanner.startScan(callback);
        mScanCallbacks.put(callbackId, callback);
    }

    /**
     * Stop a BLE scan.
     *
     * @param callbackId The callbackId corresponding to the {@link
     *     BluetoothLeScannerSnippet#bleStartScan} call that started the scan.
     * @throws BluetoothLeScanSnippetException
     */
    @RpcMinSdk(Build.VERSION_CODES.LOLLIPOP_MR1)
    @Rpc(description = "Stop a BLE scan.")
    public void bleStopScan(String callbackId) throws BluetoothLeScanSnippetException {
        ScanCallback callback = mScanCallbacks.remove(callbackId);
        if (callback == null) {
            throw new BluetoothLeScanSnippetException("No ongoing scan with ID: " + callbackId);
        }
        mScanner.stopScan(callback);
    }

    @Override
    public void shutdown() {
        for (ScanCallback callback : mScanCallbacks.values()) {
            mScanner.stopScan(callback);
        }
        mScanCallbacks.clear();
    }

    private class DefaultScanCallback extends ScanCallback {
        private final String mCallbackId;

        public DefaultScanCallback(String callbackId) {
            mCallbackId = callbackId;
        }

        public void onScanResult(int callbackType, ScanResult result) {
            Log.i("Got Bluetooth LE scan result.");
            SnippetEvent event = new SnippetEvent(mCallbackId, "onScanResult");
            String callbackTypeString =
                    MbsEnums.BLE_SCAN_RESULT_CALLBACK_TYPE.getString(callbackType);
            event.getData().putString("CallbackType", callbackTypeString);
            event.getData().putBundle("result", mJsonSerializer.serializeBleScanResult(result));
            mEventCache.postEvent(event);
        }

        public void onBatchScanResults(List<ScanResult> results) {
            Log.i("Got Bluetooth LE batch scan results.");
            SnippetEvent event = new SnippetEvent(mCallbackId, "onBatchScanResult");
            ArrayList<Bundle> resultList = new ArrayList<>(results.size());
            for (ScanResult result : results) {
                resultList.add(mJsonSerializer.serializeBleScanResult(result));
            }
            event.getData().putParcelableArrayList("results", resultList);
            mEventCache.postEvent(event);
        }

        public void onScanFailed(int errorCode) {
            Log.e("Bluetooth LE scan failed with error code: " + errorCode);
            SnippetEvent event = new SnippetEvent(mCallbackId, "onScanFailed");
            String errorCodeString = MbsEnums.BLE_SCAN_FAILED_ERROR_CODE.getString(errorCode);
            event.getData().putString("ErrorCode", errorCodeString);
            mEventCache.postEvent(event);
        }
    }
}