blob: cb33a68ac47f24e6cc25d21cbe70649d73711c16 [file] [log] [blame]
/*
* 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>();
// Create ScanFilter object, to force scan even with screen OFF
// using deviceName string of "dummy" for example
ScanFilter scanFilterDeviceName = new ScanFilter.Builder().setDeviceName(
"dummy").build();
// Add the object to FilterList
mScanFilterList.add(scanFilterDeviceName);
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");
}
}
}
}