• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 
17 package com.android.pmc;
18 
19 import android.app.AlarmManager;
20 import android.app.PendingIntent;
21 import android.bluetooth.BluetoothAdapter;
22 import android.bluetooth.le.BluetoothLeScanner;
23 import android.bluetooth.le.ScanCallback;
24 import android.bluetooth.le.ScanFilter;
25 import android.bluetooth.le.ScanResult;
26 import android.bluetooth.le.ScanSettings;
27 import android.content.BroadcastReceiver;
28 import android.content.Context;
29 import android.content.Intent;
30 import android.content.IntentFilter;
31 import android.os.Bundle;
32 import android.os.SystemClock;
33 import android.util.Log;
34 
35 import java.util.ArrayList;
36 import java.util.List;
37 
38 /**
39  * Bluetooth LE Receiver functions for power testing.
40  */
41 public class BleScanReceiver extends BroadcastReceiver {
42     public static final String TAG = "BLEPOWER";
43     public static final String BLE_SCAN_INTENT = "com.android.pmc.BLESCAN";
44     public static final int START_SCAN = 1;
45     public static final int STOP_SCAN = 2;
46     public static final int INIT_ALARM_NO = 1;
47     private final Context mContext;
48     private final AlarmManager mAlarmManager;
49     private final BleScanListener mAlarmScanListener;
50     private BluetoothLeScanner mBleScanner;
51     private ScanSettings mScanSettings;
52     private List<ScanFilter> mScanFilterList;
53     // Use PMCStatusLogger to send status and start & end times back to Python client
54     private PMCStatusLogger mPMCStatusLogger;
55     // Test start time is set when receiving the broadcast message from Python client
56     private long mStartTestTime;
57 
58     private ScanCallback mScanCallback = new ScanCallback() {
59         @Override
60         public void onScanResult(int callbackType, ScanResult result) {
61             Log.e(TAG, "Bluetooth scan result: " + result.toString());
62         }
63 
64         @Override
65         public void onScanFailed(int errorCode) {
66             Log.e(TAG, "Scan Failed: " + errorCode);
67         }
68     };
69 
70     /**
71      * Class to provide callback for AlarmManager to start BLE scan alarms
72      */
73     public class BleScanListener extends BroadcastReceiver {
74 
75         public static final String BLESCAN =
76                        "com.android.pmc.BLESCAN.ALARM";
77 
78         private int mScanTime;
79         private int mNoScanTime;
80         private int mNumAlarms;
81         private int mFirstScanTime;
82         private long mScanStartTime;
83         private long mScanEndTime;
84 
85         /**
86          * Constructor
87          *
88          */
BleScanListener()89         public BleScanListener() {
90             Log.d(TAG, "Start BleScanListener()");
91             BluetoothAdapter bleAdaptor = BluetoothAdapter.getDefaultAdapter();
92 
93             if (bleAdaptor == null) {
94                 Log.e(TAG, "BluetoothAdapter is Null");
95                 return;
96             } else {
97                 if (!bleAdaptor.isEnabled()) {
98                     Log.d(TAG, "BluetoothAdapter is NOT enabled, enable now");
99                     bleAdaptor.enable();
100                     if (!bleAdaptor.isEnabled()) {
101                         Log.e(TAG, "Can't enable Bluetooth");
102                         return;
103                     }
104                 }
105             }
106 
107             mBleScanner = bleAdaptor.getBluetoothLeScanner();
108             mScanFilterList = new ArrayList<ScanFilter>();
109 
110             // Create ScanFilter object, to force scan even with screen OFF
111             // using deviceName string of "dummy" for example
112             ScanFilter scanFilterDeviceName = new ScanFilter.Builder().setDeviceName(
113                        "dummy").build();
114             // Add the object to FilterList
115             mScanFilterList.add(scanFilterDeviceName);
116 
117             Log.d(TAG, "End BleScanListener()");
118         }
119 
120         /**
121          * Function to be called by BleScanReceiver to start
122          * Initial Bluetooth scan alarm
123          *
124          * @param scanMode - scan mode
125          * @param startTime - time when the first scan needs to be started
126          * @param scanTime - time for the scan is lasted
127          * @param noScanTime - time when the scan is stopped
128          * @param numAlarms - number of alarms to start and to stop scan
129          *
130          */
firstAlarm(int scanMode, int startTime, int scanTime, int noScanTime, int numAlarms)131         public void firstAlarm(int scanMode, int startTime, int scanTime,
132                                int noScanTime, int numAlarms) {
133             Log.d(TAG, "First Alarm for scan mode: " + scanMode);
134             mScanTime = scanTime;
135             mNoScanTime = noScanTime;
136             mNumAlarms = numAlarms;
137             mFirstScanTime = startTime;
138 
139             mScanSettings = new ScanSettings.Builder().setScanMode(
140                                             scanMode).build();
141 
142             Intent alarmIntent = new Intent(BleScanListener.BLESCAN);
143             alarmIntent.putExtra("com.android.pmc.BLESCAN.Action", START_SCAN);
144             alarmIntent.putExtra("com.android.pmc.BLESCAN.CurrentAlarm", INIT_ALARM_NO);
145             long triggerTime = SystemClock.elapsedRealtime() + startTime * 1000;
146             mAlarmManager.setExactAndAllowWhileIdle(
147                           AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerTime,
148                           PendingIntent.getBroadcast(mContext, 0,
149                                         alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT));
150         }
151 
152         /**
153          * Function to be called by onReceive() to start subsequent alarm
154          *
155          * @param intent - intent to get extra data
156          * @param timeInterval - time for alarm to trigger next alarm
157          * @param nextAction - next action for the alarm
158          *
159          */
repeatAlarm(Intent intent, int timeInterval, int nextAction)160         public void repeatAlarm(Intent intent, int timeInterval,
161                                   int nextAction) {
162 
163             int currentAlarm = intent.getIntExtra("com.android.pmc.BLESCAN.CurrentAlarm", 0);
164             Log.d(TAG, "repeatAlarm() currentAlarm: " + currentAlarm);
165             if (currentAlarm == 0) {
166                 Log.d(TAG, "Received Alarm with no currentAlarm");
167                 return;
168             }
169             if (currentAlarm >= mNumAlarms) {
170                 mPMCStatusLogger.flash();  // To flash out timestamps into log file
171                 Log.d(TAG, "All alarms are done");
172                 return;
173             }
174             Log.d(TAG, "Next Action: " + nextAction);
175             Intent alarmIntent = new Intent(BleScanListener.BLESCAN);
176             alarmIntent.putExtra("com.android.pmc.BLESCAN.Action", nextAction);
177             alarmIntent.putExtra("com.android.pmc.BLESCAN.CurrentAlarm", ++currentAlarm);
178             long triggerTime = SystemClock.elapsedRealtime()
179                                           + timeInterval * 1000;
180             mAlarmManager.setExactAndAllowWhileIdle(
181                           AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerTime,
182                           PendingIntent.getBroadcast(mContext, 0,
183                           alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT));
184         }
185 
186         /**
187          * Callback will be called for AlarmManager to start Bluetooth LE scan
188          *
189          * @param context - system will provide a context to this function
190          * @param intent - system will provide an intent to this function
191          */
192         @Override
onReceive(Context context, Intent intent)193         public void onReceive(Context context, Intent intent) {
194             if (!intent.getAction().equals(BLESCAN)) {
195                 return;
196             }
197             int action = intent.getIntExtra("com.android.pmc.BLESCAN.Action", 0);
198             Log.d(TAG, "onReceive() Action: " + action);
199             if (action == -1) {
200                 Log.e(TAG, "Received Alarm with no Action");
201                 return;
202             }
203             if (action == START_SCAN) {
204                 Log.v(TAG, "Before Start Scan");
205                 mScanStartTime = System.currentTimeMillis();
206                 mBleScanner.startScan(mScanFilterList, mScanSettings,
207                                  mScanCallback);
208                 repeatAlarm(intent, mScanTime, STOP_SCAN);
209             } else if (action == STOP_SCAN) {
210                 Log.v(TAG, "Before Stop scan");
211                 mScanEndTime = System.currentTimeMillis();
212                 mPMCStatusLogger.logAlarmTimes(mScanStartTime / 1000.0, mScanEndTime / 1000.0);
213                 mBleScanner.stopScan(mScanCallback);
214                 if ((mScanEndTime - mStartTestTime)
215                         < ((mScanTime + mNoScanTime) * mNumAlarms / 2 + mFirstScanTime) * 1000) {
216                     repeatAlarm(intent, mNoScanTime, START_SCAN);
217                 } else {
218                     mPMCStatusLogger.flash();  // To flash out timestamps into log file
219                     Log.d(TAG, "Time is up to end");
220                 }
221             } else {
222                 Log.e(TAG, "Unknown Action");
223             }
224         }
225     }
226 
227     /**
228      * Constructor to be called by PMC
229      *
230      * @param context - PMC will provide a context
231      * @param alarmManager - PMC will provide alarmManager
232      */
BleScanReceiver(Context context, AlarmManager alarmManager)233     public BleScanReceiver(Context context, AlarmManager alarmManager) {
234         // prepare for setting alarm service
235         mContext = context;
236         mAlarmManager = alarmManager;
237         mAlarmScanListener = new BleScanListener();
238 
239         // RegisterAlarmReceiver for BleScanListener
240         mContext.registerReceiver(mAlarmScanListener,
241                 new IntentFilter(BleScanListener.BLESCAN));
242 
243     }
244 
245     /**
246      * Method to receive the broadcast from python client
247      *
248      * @param context - system will provide a context to this function
249      * @param intent - system will provide an intent to this function
250      */
251     @Override
onReceive(Context context, Intent intent)252     public void onReceive(Context context, Intent intent) {
253         if (intent.getAction().equals(BLE_SCAN_INTENT)) {
254             Bundle extras = intent.getExtras();
255             int scanMode = -1, startTime = 0, scanTime = 0, noScanTime = 0;
256             int repetitions = 1;
257             String str;
258 
259             mStartTestTime = System.currentTimeMillis();
260             mPMCStatusLogger = new PMCStatusLogger(TAG + ".log", TAG);
261 
262             if (extras == null) {
263                 Log.e(TAG, "No parameters specified");
264                 return;
265             }
266 
267             if (!extras.containsKey("ScanMode")) {
268                 Log.e(TAG, "No scan mode specified");
269                 return;
270             }
271             str = extras.getString("ScanMode");
272             Log.d(TAG, "Scan Mode = " + str);
273             scanMode = Integer.valueOf(str);
274 
275             if (!extras.containsKey("StartTime")) {
276                 Log.e(TAG, "No Start Time specified");
277                 return;
278             }
279             str = extras.getString("StartTime");
280             Log.d(TAG, "Start Time = " + str);
281             startTime = Integer.valueOf(str);
282 
283             if (!extras.containsKey("ScanTime")) {
284                 Log.e(TAG, "No Scan Time specified");
285                 return;
286             }
287             str = extras.getString("ScanTime");
288             Log.d(TAG, "Scan Time = " + str);
289             scanTime = Integer.valueOf(str);
290 
291             if (extras.containsKey("Repetitions")) {
292 
293                 str = extras.getString("Repetitions");
294                 Log.d(TAG, "Repetitions = " + str);
295                 repetitions = Integer.valueOf(str);
296 
297                 if (!extras.containsKey("NoScanTime")) {
298                     Log.e(TAG, "No NoScan Time specified");
299                     return;
300                 }
301                 str = extras.getString("NoScanTime");
302                 Log.d(TAG, "NoScan Time = " + str);
303                 noScanTime = Integer.valueOf(str);
304             }
305             if (scanTime == 0 || startTime == 0 || scanMode == -1) {
306                 Log.d(TAG, "Invalid paramters");
307                 return;
308             }
309             mAlarmScanListener.firstAlarm(scanMode, startTime,
310                                        scanTime, noScanTime, repetitions * 2);
311             if (mBleScanner != null && mScanFilterList != null && mScanSettings != null
312                                  && mScanCallback != null) {
313                 mPMCStatusLogger.logStatus("READY");
314             } else {
315                 Log.e(TAG, "BLE scanner is not ready to start test");
316             }
317         }
318     }
319 }
320