| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * 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.android.pmc; |
| |
| import android.app.AlarmManager; |
| import android.app.PendingIntent; |
| import android.bluetooth.BluetoothAdapter; |
| import android.bluetooth.le.BluetoothLeScanner; |
| import android.bluetooth.le.ScanCallback; |
| import android.bluetooth.le.ScanFilter; |
| import android.bluetooth.le.ScanResult; |
| import android.bluetooth.le.ScanSettings; |
| import android.content.BroadcastReceiver; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.IntentFilter; |
| import android.os.Bundle; |
| import android.os.SystemClock; |
| import android.util.Log; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| /** |
| * Bluetooth LE Receiver functions for power testing. |
| */ |
| public class BleScanReceiver extends BroadcastReceiver { |
| public static final String TAG = "BLEPOWER"; |
| public static final String BLE_SCAN_INTENT = "com.android.pmc.BLESCAN"; |
| public static final int START_SCAN = 1; |
| public static final int STOP_SCAN = 2; |
| public static final int INIT_ALARM_NO = 1; |
| private final Context mContext; |
| private final AlarmManager mAlarmManager; |
| private final BleScanListener mAlarmScanListener; |
| private BluetoothLeScanner mBleScanner; |
| private ScanSettings mScanSettings; |
| private List<ScanFilter> mScanFilterList; |
| // Use PMCStatusLogger to send status and start & end times back to Python client |
| private PMCStatusLogger mPMCStatusLogger; |
| // Test start time is set when receiving the broadcast message from Python client |
| private long mStartTestTime; |
| |
| private ScanCallback mScanCallback = new ScanCallback() { |
| @Override |
| public void onScanResult(int callbackType, ScanResult result) { |
| Log.e(TAG, "Bluetooth scan result: " + result.toString()); |
| } |
| |
| @Override |
| public void onScanFailed(int errorCode) { |
| Log.e(TAG, "Scan Failed: " + errorCode); |
| } |
| }; |
| |
| /** |
| * Class to provide callback for AlarmManager to start BLE scan alarms |
| */ |
| public class BleScanListener extends BroadcastReceiver { |
| |
| public static final String BLESCAN = |
| "com.android.pmc.BLESCAN.ALARM"; |
| |
| private int mScanTime; |
| private int mNoScanTime; |
| private int mNumAlarms; |
| private int mFirstScanTime; |
| private long mScanStartTime; |
| private long mScanEndTime; |
| |
| /** |
| * Constructor |
| * |
| */ |
| public BleScanListener() { |
| Log.d(TAG, "Start BleScanListener()"); |
| BluetoothAdapter bleAdaptor = BluetoothAdapter.getDefaultAdapter(); |
| |
| if (bleAdaptor == null) { |
| Log.e(TAG, "BluetoothAdapter is Null"); |
| return; |
| } else { |
| if (!bleAdaptor.isEnabled()) { |
| Log.d(TAG, "BluetoothAdapter is NOT enabled, enable now"); |
| bleAdaptor.enable(); |
| if (!bleAdaptor.isEnabled()) { |
| Log.e(TAG, "Can't enable Bluetooth"); |
| return; |
| } |
| } |
| } |
| |
| mBleScanner = bleAdaptor.getBluetoothLeScanner(); |
| mScanFilterList = new ArrayList<ScanFilter>(); |
| Log.d(TAG, "End BleScanListener()"); |
| } |
| |
| /** |
| * Function to be called by BleScanReceiver to start |
| * Initial Bluetooth scan alarm |
| * |
| * @param scanMode - scan mode |
| * @param startTime - time when the first scan needs to be started |
| * @param scanTime - time for the scan is lasted |
| * @param noScanTime - time when the scan is stopped |
| * @param numAlarms - number of alarms to start and to stop scan |
| * |
| */ |
| public void firstAlarm(int scanMode, int startTime, int scanTime, |
| int noScanTime, int numAlarms) { |
| Log.d(TAG, "First Alarm for scan mode: " + scanMode); |
| mScanTime = scanTime; |
| mNoScanTime = noScanTime; |
| mNumAlarms = numAlarms; |
| mFirstScanTime = startTime; |
| |
| mScanSettings = new ScanSettings.Builder().setScanMode( |
| scanMode).build(); |
| |
| Intent alarmIntent = new Intent(BleScanListener.BLESCAN); |
| alarmIntent.putExtra("com.android.pmc.BLESCAN.Action", START_SCAN); |
| alarmIntent.putExtra("com.android.pmc.BLESCAN.CurrentAlarm", INIT_ALARM_NO); |
| long triggerTime = SystemClock.elapsedRealtime() + startTime * 1000; |
| mAlarmManager.setExactAndAllowWhileIdle( |
| AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerTime, |
| PendingIntent.getBroadcast(mContext, 0, |
| alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT)); |
| } |
| |
| /** |
| * Function to be called by onReceive() to start subsequent alarm |
| * |
| * @param intent - intent to get extra data |
| * @param timeInterval - time for alarm to trigger next alarm |
| * @param nextAction - next action for the alarm |
| * |
| */ |
| public void repeatAlarm(Intent intent, int timeInterval, |
| int nextAction) { |
| |
| int currentAlarm = intent.getIntExtra("com.android.pmc.BLESCAN.CurrentAlarm", 0); |
| Log.d(TAG, "repeatAlarm() currentAlarm: " + currentAlarm); |
| if (currentAlarm == 0) { |
| Log.d(TAG, "Received Alarm with no currentAlarm"); |
| return; |
| } |
| if (currentAlarm >= mNumAlarms) { |
| mPMCStatusLogger.flash(); // To flash out timestamps into log file |
| Log.d(TAG, "All alarms are done"); |
| return; |
| } |
| Log.d(TAG, "Next Action: " + nextAction); |
| Intent alarmIntent = new Intent(BleScanListener.BLESCAN); |
| alarmIntent.putExtra("com.android.pmc.BLESCAN.Action", nextAction); |
| alarmIntent.putExtra("com.android.pmc.BLESCAN.CurrentAlarm", ++currentAlarm); |
| long triggerTime = SystemClock.elapsedRealtime() |
| + timeInterval * 1000; |
| mAlarmManager.setExactAndAllowWhileIdle( |
| AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerTime, |
| PendingIntent.getBroadcast(mContext, 0, |
| alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT)); |
| } |
| |
| /** |
| * Callback will be called for AlarmManager to start Bluetooth LE scan |
| * |
| * @param context - system will provide a context to this function |
| * @param intent - system will provide an intent to this function |
| */ |
| @Override |
| public void onReceive(Context context, Intent intent) { |
| if (!intent.getAction().equals(BLESCAN)) { |
| return; |
| } |
| int action = intent.getIntExtra("com.android.pmc.BLESCAN.Action", 0); |
| Log.d(TAG, "onReceive() Action: " + action); |
| if (action == -1) { |
| Log.e(TAG, "Received Alarm with no Action"); |
| return; |
| } |
| if (action == START_SCAN) { |
| Log.v(TAG, "Before Start Scan"); |
| mScanStartTime = System.currentTimeMillis(); |
| mBleScanner.startScan(mScanFilterList, mScanSettings, |
| mScanCallback); |
| repeatAlarm(intent, mScanTime, STOP_SCAN); |
| } else if (action == STOP_SCAN) { |
| Log.v(TAG, "Before Stop scan"); |
| mScanEndTime = System.currentTimeMillis(); |
| mPMCStatusLogger.logAlarmTimes(mScanStartTime / 1000.0, mScanEndTime / 1000.0); |
| mBleScanner.stopScan(mScanCallback); |
| if ((mScanEndTime - mStartTestTime) |
| < ((mScanTime + mNoScanTime) * mNumAlarms / 2 + mFirstScanTime) * 1000) { |
| repeatAlarm(intent, mNoScanTime, START_SCAN); |
| } else { |
| mPMCStatusLogger.flash(); // To flash out timestamps into log file |
| Log.d(TAG, "Time is up to end"); |
| } |
| } else { |
| Log.e(TAG, "Unknown Action"); |
| } |
| } |
| } |
| |
| /** |
| * Constructor to be called by PMC |
| * |
| * @param context - PMC will provide a context |
| * @param alarmManager - PMC will provide alarmManager |
| */ |
| public BleScanReceiver(Context context, AlarmManager alarmManager) { |
| // prepare for setting alarm service |
| mContext = context; |
| mAlarmManager = alarmManager; |
| mAlarmScanListener = new BleScanListener(); |
| |
| // RegisterAlarmReceiver for BleScanListener |
| mContext.registerReceiver(mAlarmScanListener, |
| new IntentFilter(BleScanListener.BLESCAN)); |
| |
| } |
| |
| /** |
| * Method to receive the broadcast from python client |
| * |
| * @param context - system will provide a context to this function |
| * @param intent - system will provide an intent to this function |
| */ |
| @Override |
| public void onReceive(Context context, Intent intent) { |
| if (intent.getAction().equals(BLE_SCAN_INTENT)) { |
| Bundle extras = intent.getExtras(); |
| int scanMode = -1, startTime = 0, scanTime = 0, noScanTime = 0; |
| int repetitions = 1; |
| String str; |
| |
| mStartTestTime = System.currentTimeMillis(); |
| mPMCStatusLogger = new PMCStatusLogger(TAG + ".log", TAG); |
| |
| if (extras == null) { |
| Log.e(TAG, "No parameters specified"); |
| return; |
| } |
| |
| if (!extras.containsKey("ScanMode")) { |
| Log.e(TAG, "No scan mode specified"); |
| return; |
| } |
| str = extras.getString("ScanMode"); |
| Log.d(TAG, "Scan Mode = " + str); |
| scanMode = Integer.valueOf(str); |
| |
| if (!extras.containsKey("StartTime")) { |
| Log.e(TAG, "No Start Time specified"); |
| return; |
| } |
| str = extras.getString("StartTime"); |
| Log.d(TAG, "Start Time = " + str); |
| startTime = Integer.valueOf(str); |
| |
| if (!extras.containsKey("ScanTime")) { |
| Log.e(TAG, "No Scan Time specified"); |
| return; |
| } |
| str = extras.getString("ScanTime"); |
| Log.d(TAG, "Scan Time = " + str); |
| scanTime = Integer.valueOf(str); |
| |
| if (extras.containsKey("Repetitions")) { |
| |
| str = extras.getString("Repetitions"); |
| Log.d(TAG, "Repetitions = " + str); |
| repetitions = Integer.valueOf(str); |
| |
| if (!extras.containsKey("NoScanTime")) { |
| Log.e(TAG, "No NoScan Time specified"); |
| return; |
| } |
| str = extras.getString("NoScanTime"); |
| Log.d(TAG, "NoScan Time = " + str); |
| noScanTime = Integer.valueOf(str); |
| } |
| if (scanTime == 0 || startTime == 0 || scanMode == -1) { |
| Log.d(TAG, "Invalid paramters"); |
| return; |
| } |
| mAlarmScanListener.firstAlarm(scanMode, startTime, |
| scanTime, noScanTime, repetitions * 2); |
| if (mBleScanner != null && mScanFilterList != null && mScanSettings != null |
| && mScanCallback != null) { |
| mPMCStatusLogger.logStatus("READY"); |
| } else { |
| Log.e(TAG, "BLE scanner is not ready to start test"); |
| } |
| } |
| } |
| } |