1 /*
2  * Copyright (C) 2021 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 package android.permissionui.cts.usepermission
17 
18 import android.bluetooth.BluetoothManager
19 import android.bluetooth.le.BluetoothLeScanner
20 import android.bluetooth.le.ScanCallback
21 import android.bluetooth.le.ScanResult
22 import android.content.ContentProvider
23 import android.content.ContentValues
24 import android.content.Intent
25 import android.database.Cursor
26 import android.net.Uri
27 import android.os.Bundle
28 import android.os.SystemClock
29 import android.util.Base64
30 import android.util.Log
31 import java.util.concurrent.ConcurrentHashMap
32 import java.util.concurrent.atomic.AtomicInteger
33 
34 private const val LOG_TAG = "AccessBluetoothOnCommand"
35 
36 class AccessBluetoothOnCommand : ContentProvider() {
37 
38     private enum class Result {
39         UNKNOWN,
40         ERROR,
41         EXCEPTION,
42         EMPTY,
43         FILTERED,
44         FULL
45     }
46 
callnull47     override fun call(authority: String, method: String, arg: String?, extras: Bundle?): Bundle? {
48         Log.v(LOG_TAG, "call() - start")
49         val res = Bundle()
50 
51         var scanner: BluetoothLeScanner? = null
52         var scanCallback: ScanCallback? = null
53 
54         try {
55 
56             scanner =
57                 context!!
58                     .getSystemService(BluetoothManager::class.java)
59                     ?.adapter!!
60                     .bluetoothLeScanner
61 
62             val observedScans: MutableSet<String> = ConcurrentHashMap.newKeySet()
63             val observedErrorCode = AtomicInteger(0)
64 
65             scanCallback =
66                 object : ScanCallback() {
67                     override fun onScanResult(callbackType: Int, result: ScanResult) {
68                         Log.v(LOG_TAG, "onScanResult() - result = $result")
69                         observedScans.add(Base64.encodeToString(result.scanRecord!!.bytes, 0))
70                     }
71 
72                     override fun onBatchScanResults(results: List<ScanResult>) {
73                         Log.v(LOG_TAG, "onBatchScanResults() - results.size = ${results.size}")
74                         for (result in results) {
75                             onScanResult(0, result)
76                         }
77                     }
78 
79                     override fun onScanFailed(errorCode: Int) {
80                         Log.e(LOG_TAG, "onScanFailed() - errorCode = $errorCode")
81                         observedErrorCode.set(errorCode)
82                     }
83                 }
84 
85             Log.v(LOG_TAG, "call() - startScan...")
86             scanner.startScan(scanCallback)
87 
88             // Wait a few seconds to figure out what we actually observed
89             Log.v(LOG_TAG, "call() - sleep...")
90             SystemClock.sleep(3000)
91 
92             if (observedErrorCode.get() > 0) {
93                 Log.v(LOG_TAG, "call() observed error: ${observedErrorCode.get()}")
94                 res.putInt(Intent.EXTRA_INDEX, Result.ERROR.ordinal)
95                 return res
96             }
97             Log.v(LOG_TAG, "call() - (scanCount=${observedScans.size})")
98 
99             when (observedScans.size) {
100                 0 -> res.putInt(Intent.EXTRA_INDEX, Result.EMPTY.ordinal)
101                 1 -> res.putInt(Intent.EXTRA_INDEX, Result.FILTERED.ordinal)
102                 5 -> res.putInt(Intent.EXTRA_INDEX, Result.FULL.ordinal)
103                 else -> res.putInt(Intent.EXTRA_INDEX, Result.UNKNOWN.ordinal)
104             }
105         } catch (t: Throwable) {
106             Log.e(LOG_TAG, "call() - EXCEPTION", t)
107             res.putInt(Intent.EXTRA_INDEX, Result.EXCEPTION.ordinal)
108         } finally {
109             try {
110                 Log.v(LOG_TAG, "call() - finally - stopScan...")
111                 scanner!!.stopScan(scanCallback)
112             } catch (e: Exception) {
113                 Log.e(LOG_TAG, "call() - finally - EXCEPTION", e)
114             }
115         }
116         Log.v(LOG_TAG, "call() - end")
117         return res
118     }
119 
onCreatenull120     override fun onCreate(): Boolean {
121         return true
122     }
123 
querynull124     override fun query(
125         uri: Uri,
126         projection: Array<String>?,
127         selection: String?,
128         selectionArgs: Array<String>?,
129         sortOrder: String?
130     ): Cursor? {
131         throw UnsupportedOperationException()
132     }
133 
getTypenull134     override fun getType(uri: Uri): String? {
135         throw UnsupportedOperationException()
136     }
137 
insertnull138     override fun insert(uri: Uri, values: ContentValues?): Uri? {
139         throw UnsupportedOperationException()
140     }
141 
deletenull142     override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int {
143         throw UnsupportedOperationException()
144     }
145 
updatenull146     override fun update(
147         uri: Uri,
148         values: ContentValues?,
149         selection: String?,
150         selectionArgs: Array<String>?
151     ): Int {
152         throw UnsupportedOperationException()
153     }
154 }
155