Merge "Add bt anomaly action in testing app" into oc-mr1-dev
diff --git a/tests/anomaly-tester/AndroidManifest.xml b/tests/anomaly-tester/AndroidManifest.xml
index b5f50c4..c057a66 100644
--- a/tests/anomaly-tester/AndroidManifest.xml
+++ b/tests/anomaly-tester/AndroidManifest.xml
@@ -14,8 +14,13 @@
limitations under the License.
-->
<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
android:allowBackup="false"
android:label="@string/app_name"
@@ -29,6 +34,10 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
+
+ <service
+ android:name=".service.AnomalyService"
+ android:exported="false"/>
</application>
</manifest>
\ No newline at end of file
diff --git a/tests/anomaly-tester/res/layout/bluetooth_anomaly.xml b/tests/anomaly-tester/res/layout/bluetooth_anomaly.xml
index 7de558e..87e61b0 100644
--- a/tests/anomaly-tester/res/layout/bluetooth_anomaly.xml
+++ b/tests/anomaly-tester/res/layout/bluetooth_anomaly.xml
@@ -35,16 +35,21 @@
android:layout_width="0dp"
android:layout_weight="3"
android:layout_height="wrap_content"
- android:hint="Threshold(ms)"/>
+ android:hint="Threshold(ms)"
+ android:text="3000"
+ android:inputType="number"/>
<EditText
android:id="@+id/bluetooth_run_time"
android:layout_width="0dp"
android:layout_weight="3"
android:layout_height="wrap_content"
- android:hint="Run time(ms)"/>
+ android:hint="Run time(ms)"
+ android:text="6000"
+ android:inputType="number"/>
<Button
+ android:id="@+id/bluetooth_button"
android:layout_width="0dp"
android:layout_weight="2"
android:layout_height="wrap_content"
diff --git a/tests/anomaly-tester/src/com/android/settings/anomaly/tester/AnomalyActivity.java b/tests/anomaly-tester/src/com/android/settings/anomaly/tester/AnomalyActivity.java
index 6aa8edd..773dd27 100644
--- a/tests/anomaly-tester/src/com/android/settings/anomaly/tester/AnomalyActivity.java
+++ b/tests/anomaly-tester/src/com/android/settings/anomaly/tester/AnomalyActivity.java
@@ -15,18 +15,92 @@
package com.android.settings.anomaly.tester;
import android.app.Activity;
+import android.content.Intent;
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.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 {
+ private static final String TAG = AnomalyActivity.class.getSimpleName();
+
+ public static final String KEY_TARGET_BUTTON = "target_button";
+
+ private AnomalyResultReceiver mResultReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
+ mResultReceiver = new AnomalyResultReceiver(new Handler());
}
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);
+ }
+
+ }
}
}
diff --git a/tests/anomaly-tester/src/com/android/settings/anomaly/tester/service/AnomalyService.java b/tests/anomaly-tester/src/com/android/settings/anomaly/tester/service/AnomalyService.java
new file mode 100644
index 0000000..b569bce
--- /dev/null
+++ b/tests/anomaly-tester/src/com/android/settings/anomaly/tester/service/AnomalyService.java
@@ -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());
+ }
+ }
+}
diff --git a/tests/anomaly-tester/src/com/android/settings/anomaly/tester/utils/AnomalyActions.java b/tests/anomaly-tester/src/com/android/settings/anomaly/tester/utils/AnomalyActions.java
new file mode 100644
index 0000000..a55efdb
--- /dev/null
+++ b/tests/anomaly-tester/src/com/android/settings/anomaly/tester/utils/AnomalyActions.java
@@ -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);
+ }
+}
diff --git a/tests/anomaly-tester/src/com/android/settings/anomaly/tester/utils/AnomalyPolicyBuilder.java b/tests/anomaly-tester/src/com/android/settings/anomaly/tester/utils/AnomalyPolicyBuilder.java
new file mode 100644
index 0000000..bf8e075
--- /dev/null
+++ b/tests/anomaly-tester/src/com/android/settings/anomaly/tester/utils/AnomalyPolicyBuilder.java
@@ -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 "";
+ }
+ }
+}