• 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             Log.d(TAG, "End BleScanListener()");
110         }
111 
112         /**
113          * Function to be called by BleScanReceiver to start
114          * Initial Bluetooth scan alarm
115          *
116          * @param scanMode - scan mode
117          * @param startTime - time when the first scan needs to be started
118          * @param scanTime - time for the scan is lasted
119          * @param noScanTime - time when the scan is stopped
120          * @param numAlarms - number of alarms to start and to stop scan
121          *
122          */
firstAlarm(int scanMode, int startTime, int scanTime, int noScanTime, int numAlarms)123         public void firstAlarm(int scanMode, int startTime, int scanTime,
124                                int noScanTime, int numAlarms) {
125             Log.d(TAG, "First Alarm for scan mode: " + scanMode);
126             mScanTime = scanTime;
127             mNoScanTime = noScanTime;
128             mNumAlarms = numAlarms;
129             mFirstScanTime = startTime;
130 
131             mScanSettings = new ScanSettings.Builder().setScanMode(
132                                             scanMode).build();
133 
134             Intent alarmIntent = new Intent(BleScanListener.BLESCAN);
135             alarmIntent.putExtra("com.android.pmc.BLESCAN.Action", START_SCAN);
136             alarmIntent.putExtra("com.android.pmc.BLESCAN.CurrentAlarm", INIT_ALARM_NO);
137             long triggerTime = SystemClock.elapsedRealtime() + startTime * 1000;
138             mAlarmManager.setExactAndAllowWhileIdle(
139                           AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerTime,
140                           PendingIntent.getBroadcast(mContext, 0,
141                                         alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT));
142         }
143 
144         /**
145          * Function to be called by onReceive() to start subsequent alarm
146          *
147          * @param intent - intent to get extra data
148          * @param timeInterval - time for alarm to trigger next alarm
149          * @param nextAction - next action for the alarm
150          *
151          */
repeatAlarm(Intent intent, int timeInterval, int nextAction)152         public void repeatAlarm(Intent intent, int timeInterval,
153                                   int nextAction) {
154 
155             int currentAlarm = intent.getIntExtra("com.android.pmc.BLESCAN.CurrentAlarm", 0);
156             Log.d(TAG, "repeatAlarm() currentAlarm: " + currentAlarm);
157             if (currentAlarm == 0) {
158                 Log.d(TAG, "Received Alarm with no currentAlarm");
159                 return;
160             }
161             if (currentAlarm >= mNumAlarms) {
162                 mPMCStatusLogger.flash();  // To flash out timestamps into log file
163                 Log.d(TAG, "All alarms are done");
164                 return;
165             }
166             Log.d(TAG, "Next Action: " + nextAction);
167             Intent alarmIntent = new Intent(BleScanListener.BLESCAN);
168             alarmIntent.putExtra("com.android.pmc.BLESCAN.Action", nextAction);
169             alarmIntent.putExtra("com.android.pmc.BLESCAN.CurrentAlarm", ++currentAlarm);
170             long triggerTime = SystemClock.elapsedRealtime()
171                                           + timeInterval * 1000;
172             mAlarmManager.setExactAndAllowWhileIdle(
173                           AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerTime,
174                           PendingIntent.getBroadcast(mContext, 0,
175                           alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT));
176         }
177 
178         /**
179          * Callback will be called for AlarmManager to start Bluetooth LE scan
180          *
181          * @param context - system will provide a context to this function
182          * @param intent - system will provide an intent to this function
183          */
184         @Override
onReceive(Context context, Intent intent)185         public void onReceive(Context context, Intent intent) {
186             if (!intent.getAction().equals(BLESCAN)) {
187                 return;
188             }
189             int action = intent.getIntExtra("com.android.pmc.BLESCAN.Action", 0);
190             Log.d(TAG, "onReceive() Action: " + action);
191             if (action == -1) {
192                 Log.e(TAG, "Received Alarm with no Action");
193                 return;
194             }
195             if (action == START_SCAN) {
196                 Log.v(TAG, "Before Start Scan");
197                 mScanStartTime = System.currentTimeMillis();
198                 mBleScanner.startScan(mScanFilterList, mScanSettings,
199                                  mScanCallback);
200                 repeatAlarm(intent, mScanTime, STOP_SCAN);
201             } else if (action == STOP_SCAN) {
202                 Log.v(TAG, "Before Stop scan");
203                 mScanEndTime = System.currentTimeMillis();
204                 mPMCStatusLogger.logAlarmTimes(mScanStartTime / 1000.0, mScanEndTime / 1000.0);
205                 mBleScanner.stopScan(mScanCallback);
206                 if ((mScanEndTime - mStartTestTime)
207                         < ((mScanTime + mNoScanTime) * mNumAlarms / 2 + mFirstScanTime) * 1000) {
208                     repeatAlarm(intent, mNoScanTime, START_SCAN);
209                 } else {
210                     mPMCStatusLogger.flash();  // To flash out timestamps into log file
211                     Log.d(TAG, "Time is up to end");
212                 }
213             } else {
214                 Log.e(TAG, "Unknown Action");
215             }
216         }
217     }
218 
219     /**
220      * Constructor to be called by PMC
221      *
222      * @param context - PMC will provide a context
223      * @param alarmManager - PMC will provide alarmManager
224      */
BleScanReceiver(Context context, AlarmManager alarmManager)225     public BleScanReceiver(Context context, AlarmManager alarmManager) {
226         // prepare for setting alarm service
227         mContext = context;
228         mAlarmManager = alarmManager;
229         mAlarmScanListener = new BleScanListener();
230 
231         // RegisterAlarmReceiver for BleScanListener
232         mContext.registerReceiver(mAlarmScanListener,
233                 new IntentFilter(BleScanListener.BLESCAN));
234 
235     }
236 
237     /**
238      * Method to receive the broadcast from python client
239      *
240      * @param context - system will provide a context to this function
241      * @param intent - system will provide an intent to this function
242      */
243     @Override
onReceive(Context context, Intent intent)244     public void onReceive(Context context, Intent intent) {
245         if (intent.getAction().equals(BLE_SCAN_INTENT)) {
246             Bundle extras = intent.getExtras();
247             int scanMode = -1, startTime = 0, scanTime = 0, noScanTime = 0;
248             int repetitions = 1;
249             String str;
250 
251             mStartTestTime = System.currentTimeMillis();
252             mPMCStatusLogger = new PMCStatusLogger(TAG + ".log", TAG);
253 
254             if (extras == null) {
255                 Log.e(TAG, "No parameters specified");
256                 return;
257             }
258 
259             if (!extras.containsKey("ScanMode")) {
260                 Log.e(TAG, "No scan mode specified");
261                 return;
262             }
263             str = extras.getString("ScanMode");
264             Log.d(TAG, "Scan Mode = " + str);
265             scanMode = Integer.valueOf(str);
266 
267             if (!extras.containsKey("StartTime")) {
268                 Log.e(TAG, "No Start Time specified");
269                 return;
270             }
271             str = extras.getString("StartTime");
272             Log.d(TAG, "Start Time = " + str);
273             startTime = Integer.valueOf(str);
274 
275             if (!extras.containsKey("ScanTime")) {
276                 Log.e(TAG, "No Scan Time specified");
277                 return;
278             }
279             str = extras.getString("ScanTime");
280             Log.d(TAG, "Scan Time = " + str);
281             scanTime = Integer.valueOf(str);
282 
283             if (extras.containsKey("Repetitions")) {
284 
285                 str = extras.getString("Repetitions");
286                 Log.d(TAG, "Repetitions = " + str);
287                 repetitions = Integer.valueOf(str);
288 
289                 if (!extras.containsKey("NoScanTime")) {
290                     Log.e(TAG, "No NoScan Time specified");
291                     return;
292                 }
293                 str = extras.getString("NoScanTime");
294                 Log.d(TAG, "NoScan Time = " + str);
295                 noScanTime = Integer.valueOf(str);
296             }
297             if (scanTime == 0 || startTime == 0 || scanMode == -1) {
298                 Log.d(TAG, "Invalid paramters");
299                 return;
300             }
301             mAlarmScanListener.firstAlarm(scanMode, startTime,
302                                        scanTime, noScanTime, repetitions * 2);
303             if (mBleScanner != null && mScanFilterList != null && mScanSettings != null
304                                  && mScanCallback != null) {
305                 mPMCStatusLogger.logStatus("READY");
306             } else {
307                 Log.e(TAG, "BLE scanner is not ready to start test");
308             }
309         }
310     }
311 }
312