Merge "Add bt anomaly action in testing app" into oc-mr1-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
4aaacaf7e3
@@ -16,6 +16,11 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.android.settings.anomaly.tester">
|
package="com.android.settings.anomaly.tester">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
|
||||||
|
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
|
||||||
|
<uses-permission android:name="android.permission.BLUETOOTH"/>
|
||||||
|
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
|
||||||
<application
|
<application
|
||||||
android:allowBackup="false"
|
android:allowBackup="false"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
@@ -29,6 +34,10 @@
|
|||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".service.AnomalyService"
|
||||||
|
android:exported="false"/>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
@@ -35,16 +35,21 @@
|
|||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_weight="3"
|
android:layout_weight="3"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="Threshold(ms)"/>
|
android:hint="Threshold(ms)"
|
||||||
|
android:text="3000"
|
||||||
|
android:inputType="number"/>
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/bluetooth_run_time"
|
android:id="@+id/bluetooth_run_time"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_weight="3"
|
android:layout_weight="3"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="Run time(ms)"/>
|
android:hint="Run time(ms)"
|
||||||
|
android:text="6000"
|
||||||
|
android:inputType="number"/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
|
android:id="@+id/bluetooth_button"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_weight="2"
|
android:layout_weight="2"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@@ -15,18 +15,92 @@
|
|||||||
package com.android.settings.anomaly.tester;
|
package com.android.settings.anomaly.tester;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.ResultReceiver;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.android.settings.anomaly.tester.service.AnomalyService;
|
||||||
|
import com.android.settings.anomaly.tester.utils.AnomalyActions;
|
||||||
|
import com.android.settings.anomaly.tester.utils.AnomalyPolicyBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main activity to control and start anomaly
|
||||||
|
*/
|
||||||
public class AnomalyActivity extends Activity {
|
public class AnomalyActivity extends Activity {
|
||||||
|
private static final String TAG = AnomalyActivity.class.getSimpleName();
|
||||||
|
|
||||||
|
public static final String KEY_TARGET_BUTTON = "target_button";
|
||||||
|
|
||||||
|
private AnomalyResultReceiver mResultReceiver;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_main);
|
setContentView(R.layout.activity_main);
|
||||||
|
mResultReceiver = new AnomalyResultReceiver(new Handler());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startBluetoothAnomaly(View view) {
|
public void startBluetoothAnomaly(View view) {
|
||||||
// Add in future cl
|
try {
|
||||||
|
// Enable anomaly detection and change the threshold
|
||||||
|
final String config = new AnomalyPolicyBuilder()
|
||||||
|
.addPolicy(AnomalyPolicyBuilder.KEY_ANOMALY_DETECTION_ENABLED, true)
|
||||||
|
.addPolicy(AnomalyPolicyBuilder.KEY_BLUETOOTH_SCAN_DETECTION_ENABLED, true)
|
||||||
|
.addPolicy(AnomalyPolicyBuilder.KEY_BLUETOOTH_SCAN_THRESHOLD,
|
||||||
|
getValueFromEditText(R.id.bluetooth_threshold))
|
||||||
|
.build();
|
||||||
|
Settings.Global.putString(getContentResolver(),
|
||||||
|
Settings.Global.ANOMALY_DETECTION_CONSTANTS, config);
|
||||||
|
|
||||||
|
// Start the anomaly service
|
||||||
|
Intent intent = new Intent(this, AnomalyService.class);
|
||||||
|
intent.putExtra(AnomalyActions.KEY_ACTION, AnomalyActions.ACTION_BLE_SCAN_UNOPTIMIZED);
|
||||||
|
intent.putExtra(AnomalyActions.KEY_DURATION_MS,
|
||||||
|
getValueFromEditText(R.id.bluetooth_run_time));
|
||||||
|
intent.putExtra(AnomalyActions.KEY_RESULT_RECEIVER, mResultReceiver);
|
||||||
|
intent.putExtra(KEY_TARGET_BUTTON, view.getId());
|
||||||
|
startService(intent);
|
||||||
|
|
||||||
|
view.setEnabled(false);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
Toast.makeText(getApplicationContext(), e.toString(), Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private long getValueFromEditText(final int id) throws NumberFormatException {
|
||||||
|
final EditText editText = findViewById(id);
|
||||||
|
if (editText != null) {
|
||||||
|
final long value = Long.parseLong(editText.getText().toString());
|
||||||
|
if (value > 0) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NumberFormatException("Number should be positive");
|
||||||
|
}
|
||||||
|
|
||||||
|
private class AnomalyResultReceiver extends ResultReceiver {
|
||||||
|
|
||||||
|
public AnomalyResultReceiver(Handler handler) {
|
||||||
|
super(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onReceiveResult(int resultCode, Bundle resultData) {
|
||||||
|
super.onReceiveResult(resultCode, resultData);
|
||||||
|
|
||||||
|
final Button button = findViewById(resultData.getInt(KEY_TARGET_BUTTON));
|
||||||
|
if (button != null) {
|
||||||
|
button.setEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* 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.settings.anomaly.tester.service;
|
||||||
|
|
||||||
|
import android.annotation.Nullable;
|
||||||
|
import android.app.IntentService;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.ResultReceiver;
|
||||||
|
|
||||||
|
import com.android.settings.anomaly.tester.utils.AnomalyActions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service to run the anomaly action
|
||||||
|
*/
|
||||||
|
public class AnomalyService extends IntentService {
|
||||||
|
private static final String TAG = AnomalyService.class.getSimpleName();
|
||||||
|
|
||||||
|
public AnomalyService() {
|
||||||
|
super(AnomalyService.class.getSimpleName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onHandleIntent(@Nullable Intent intent) {
|
||||||
|
final String action = intent.getStringExtra(AnomalyActions.KEY_ACTION);
|
||||||
|
final long durationMs = intent.getLongExtra(AnomalyActions.KEY_DURATION_MS, 0);
|
||||||
|
final ResultReceiver resultReceiver = intent.getParcelableExtra(
|
||||||
|
AnomalyActions.KEY_RESULT_RECEIVER);
|
||||||
|
|
||||||
|
AnomalyActions.doAction(this, action, durationMs);
|
||||||
|
|
||||||
|
if (resultReceiver != null) {
|
||||||
|
resultReceiver.send(0 /* resultCode */, intent.getExtras());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* 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.settings.anomaly.tester.utils;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothAdapter;
|
||||||
|
import android.bluetooth.le.BluetoothLeScanner;
|
||||||
|
import android.bluetooth.le.ScanCallback;
|
||||||
|
import android.bluetooth.le.ScanResult;
|
||||||
|
import android.bluetooth.le.ScanSettings;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actions to generate anomaly.
|
||||||
|
*/
|
||||||
|
public class AnomalyActions {
|
||||||
|
private static final String TAG = AnomalyActions.class.getSimpleName();
|
||||||
|
|
||||||
|
public static final String KEY_ACTION = "action";
|
||||||
|
public static final String KEY_DURATION_MS = "duration_ms";
|
||||||
|
public static final String KEY_RESULT_RECEIVER = "result_receiver";
|
||||||
|
|
||||||
|
public static final String ACTION_BLE_SCAN_UNOPTIMIZED = "action.ble_scan_unoptimized";
|
||||||
|
|
||||||
|
public static void doAction(Context ctx, String actionCode, long durationMs) {
|
||||||
|
if (actionCode == null) {
|
||||||
|
Log.e(TAG, "Intent was missing action.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (actionCode) {
|
||||||
|
case ACTION_BLE_SCAN_UNOPTIMIZED:
|
||||||
|
doUnoptimizedBleScan(ctx, durationMs);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Log.e(TAG, "Intent had invalid action");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void doUnoptimizedBleScan(Context ctx, long durationMs) {
|
||||||
|
ScanSettings scanSettings = new ScanSettings.Builder()
|
||||||
|
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();
|
||||||
|
|
||||||
|
// perform ble scanning
|
||||||
|
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||||
|
if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled() ) {
|
||||||
|
Log.e(TAG, "Device does not support Bluetooth or Bluetooth not enabled");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BluetoothLeScanner bleScanner = bluetoothAdapter.getBluetoothLeScanner();
|
||||||
|
if (bleScanner == null) {
|
||||||
|
Log.e(TAG, "Cannot access BLE scanner");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScanCallback scanCallback = new ScanCallback() {
|
||||||
|
@Override
|
||||||
|
public void onScanResult(int callbackType, ScanResult result) {
|
||||||
|
Log.v(TAG, "called onScanResult");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onScanFailed(int errorCode) {
|
||||||
|
Log.v(TAG, "called onScanFailed");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBatchScanResults(List<ScanResult> results) {
|
||||||
|
Log.v(TAG, "called onBatchScanResults");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bleScanner.startScan(null, scanSettings, scanCallback);
|
||||||
|
try {
|
||||||
|
Thread.sleep(durationMs);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Log.e(TAG, "Thread couldn't sleep for " + durationMs, e);
|
||||||
|
}
|
||||||
|
bleScanner.stopScan(scanCallback);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* 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.settings.anomaly.tester.utils;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder to build the anomaly policy string, used in {@link android.provider.Settings.Global}
|
||||||
|
*
|
||||||
|
* @see android.provider.Settings.Global#ANOMALY_DETECTION_CONSTANTS
|
||||||
|
*/
|
||||||
|
public class AnomalyPolicyBuilder {
|
||||||
|
public static final String KEY_ANOMALY_DETECTION_ENABLED = "anomaly_detection_enabled";
|
||||||
|
public static final String KEY_WAKELOCK_DETECTION_ENABLED = "wakelock_enabled";
|
||||||
|
public static final String KEY_WAKEUP_ALARM_DETECTION_ENABLED = "wakeup_alarm_enabled";
|
||||||
|
public static final String KEY_BLUETOOTH_SCAN_DETECTION_ENABLED = "bluetooth_scan_enabled";
|
||||||
|
public static final String KEY_WAKELOCK_THRESHOLD = "wakelock_threshold";
|
||||||
|
public static final String KEY_WAKEUP_ALARM_THRESHOLD = "wakeup_alarm_threshold";
|
||||||
|
public static final String KEY_BLUETOOTH_SCAN_THRESHOLD = "bluetooth_scan_threshold";
|
||||||
|
|
||||||
|
public static final String DELIM = ",";
|
||||||
|
|
||||||
|
private Map<String, String> mValues;
|
||||||
|
|
||||||
|
public AnomalyPolicyBuilder() {
|
||||||
|
mValues = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnomalyPolicyBuilder addPolicy(String key, String value) {
|
||||||
|
mValues.put(key, value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnomalyPolicyBuilder addPolicy(String key, long value) {
|
||||||
|
mValues.put(key, Long.toString(value));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public AnomalyPolicyBuilder addPolicy(String key, boolean value) {
|
||||||
|
mValues.put(key, value ? "true" : "false");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String build() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (Map.Entry<String, String> entry : mValues.entrySet()) {
|
||||||
|
sb.append(entry.getKey() + "=" + entry.getValue() + DELIM);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sb.length() != 0) {
|
||||||
|
return sb.substring(0, sb.length() - 1);
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user