fix: 引入Settings的Module
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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.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) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
public void startWakelockAnomaly(View view) {
|
||||
try {
|
||||
// Enable anomaly detection and change the threshold
|
||||
final String config = new AnomalyPolicyBuilder()
|
||||
.addPolicy(AnomalyPolicyBuilder.KEY_ANOMALY_DETECTION_ENABLED, true)
|
||||
.addPolicy(AnomalyPolicyBuilder.KEY_WAKELOCK_DETECTION_ENABLED, true)
|
||||
.addPolicy(AnomalyPolicyBuilder.KEY_WAKELOCK_THRESHOLD,
|
||||
getValueFromEditText(R.id.wakelock_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_WAKE_LOCK);
|
||||
intent.putExtra(AnomalyActions.KEY_DURATION_MS,
|
||||
getValueFromEditText(R.id.wakelock_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,113 @@
|
||||
/*
|
||||
* 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.os.PowerManager;
|
||||
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 final String ACTION_WAKE_LOCK = "action.wake_lock";
|
||||
|
||||
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;
|
||||
case ACTION_WAKE_LOCK:
|
||||
doHoldWakelock(ctx, durationMs);
|
||||
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);
|
||||
}
|
||||
|
||||
private static void doHoldWakelock(Context ctx, long durationMs) {
|
||||
PowerManager powerManager = ctx.getSystemService(PowerManager.class);
|
||||
PowerManager.WakeLock wl = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
|
||||
"AnomalyWakeLock");
|
||||
wl.acquire();
|
||||
try {
|
||||
Thread.sleep(durationMs);
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(TAG, "Thread couldn't sleep for " + durationMs, e);
|
||||
}
|
||||
wl.release();
|
||||
}
|
||||
}
|
||||
@@ -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 "";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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.tests;
|
||||
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.text.format.DateUtils;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
import androidx.test.uiautomator.By;
|
||||
import androidx.test.uiautomator.UiDevice;
|
||||
import androidx.test.uiautomator.Until;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* Functional test for bluetooth unoptimized scanning anomaly detector
|
||||
*
|
||||
* @see com.android.settings.fuelgauge.anomaly.checker.BluetoothScanAnomalyDetector
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class BluetoothAnomalyTest {
|
||||
private static final String BATTERY_INTENT = "android.intent.action.POWER_USAGE_SUMMARY";
|
||||
private static final String RES_BT_EDITTEXT =
|
||||
"com.android.settings.anomaly.tester:id/bluetooth_run_time";
|
||||
private static final String RES_BT_BUTTON =
|
||||
"com.android.settings.anomaly.tester:id/bluetooth_button";
|
||||
private static final long TIME_OUT = 3000;
|
||||
private UiDevice mDevice;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
final Context context = instrumentation.getContext();
|
||||
mDevice = UiDevice.getInstance(instrumentation);
|
||||
|
||||
// setup environment
|
||||
TestUtils.setUp(instrumentation);
|
||||
// start anomaly-tester app
|
||||
TestUtils.startAnomalyApp(context, mDevice);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
TestUtils.tearDown(InstrumentationRegistry.getInstrumentation());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBluetoothAnomaly_longScanningTime_reportAnomaly() throws InterruptedException {
|
||||
// Set running time
|
||||
final long durationMs = DateUtils.SECOND_IN_MILLIS * 15;
|
||||
TestUtils.setEditTextWithValue(mDevice, RES_BT_EDITTEXT, durationMs);
|
||||
|
||||
// Click start button
|
||||
TestUtils.clickButton(mDevice, RES_BT_BUTTON);
|
||||
|
||||
// Wait for its running
|
||||
mDevice.pressHome();
|
||||
TestUtils.wait(mDevice, durationMs);
|
||||
|
||||
// Check it in battery main page
|
||||
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
instrumentation.startActivitySync(new Intent(BATTERY_INTENT));
|
||||
assertWithMessage("Doesn't have bluetooth anomaly").that(
|
||||
mDevice.wait(Until.findObject(By.text("AnomalyTester draining battery")),
|
||||
TIME_OUT)).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBluetoothAnomaly_shortScanningTime_notReport() throws InterruptedException {
|
||||
// Set running time
|
||||
final long durationMs = DateUtils.SECOND_IN_MILLIS;
|
||||
TestUtils.setEditTextWithValue(mDevice, RES_BT_EDITTEXT, durationMs);
|
||||
|
||||
// Click start button
|
||||
TestUtils.clickButton(mDevice, RES_BT_BUTTON);
|
||||
|
||||
// Wait for its running
|
||||
mDevice.pressHome();
|
||||
TestUtils.wait(mDevice, durationMs);
|
||||
|
||||
// Check it in battery main page
|
||||
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
instrumentation.startActivitySync(new Intent(BATTERY_INTENT));
|
||||
assertWithMessage("Shouldn't have bluetooth anomaly").that(
|
||||
mDevice.wait(Until.findObject(By.text("AnomalyTester draining battery")),
|
||||
TIME_OUT)).isNull();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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.tests;
|
||||
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.app.UiAutomation;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.test.uiautomator.By;
|
||||
import androidx.test.uiautomator.UiDevice;
|
||||
import androidx.test.uiautomator.UiObject2;
|
||||
import androidx.test.uiautomator.Until;
|
||||
|
||||
public class TestUtils {
|
||||
private static final String PACKAGE_NAME = "com.android.settings.anomaly.tester";
|
||||
private static final long TIME_OUT = 3000;
|
||||
|
||||
/**
|
||||
* This method set up the environment for anomaly test
|
||||
*
|
||||
* @param instrumentation to execute command
|
||||
*/
|
||||
public static void setUp(Instrumentation instrumentation) {
|
||||
final UiAutomation uiAutomation = instrumentation.getUiAutomation();
|
||||
// pretend unplug and screen off, also reset the battery stats
|
||||
uiAutomation.executeShellCommand("dumpsys battery unplug");
|
||||
uiAutomation.executeShellCommand("dumpsys batterystats enable pretend-screen-off");
|
||||
uiAutomation.executeShellCommand("dumpsys batterystats --reset");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method cleans up all the commands in {@link #setUp(Instrumentation)}
|
||||
*
|
||||
* @param instrumentation to execute command
|
||||
*/
|
||||
public static void tearDown(Instrumentation instrumentation) {
|
||||
final UiAutomation uiAutomation = instrumentation.getUiAutomation();
|
||||
// reset unplug and screen-off
|
||||
uiAutomation.executeShellCommand("dumpsys battery reset");
|
||||
uiAutomation.executeShellCommand("dumpsys batterystats disable pretend-screen-off");
|
||||
}
|
||||
|
||||
public static void startAnomalyApp(Context context, UiDevice uiDevice) {
|
||||
final Intent intent = context.getPackageManager().getLaunchIntentForPackage(PACKAGE_NAME);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
context.startActivity(intent);
|
||||
uiDevice.wait(Until.hasObject(By.pkg(PACKAGE_NAME).depth(0)), TIME_OUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find {@link android.widget.EditText} with {@code res} and set its {@code value}
|
||||
*/
|
||||
public static void setEditTextWithValue(UiDevice uiDevice, String res, long value) {
|
||||
final UiObject2 editText = uiDevice.findObject(By.res(res));
|
||||
assertWithMessage("Cannot find editText with res: " + res).that(editText).isNotNull();
|
||||
editText.setText(String.valueOf(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find {@link android.widget.Button} with {@code res} and click it
|
||||
*/
|
||||
public static void clickButton(UiDevice uiDevice, String res) {
|
||||
final UiObject2 button = uiDevice.findObject(By.res(res));
|
||||
assertWithMessage("Cannot find button with res: " + res).that(button).isNotNull();
|
||||
button.click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Make {@link UiDevice} wait for {@code timeMs}
|
||||
*
|
||||
* @see Thread#sleep(long)
|
||||
*/
|
||||
public static void wait(UiDevice uiDevice, long timeMs) throws InterruptedException {
|
||||
uiDevice.waitForIdle();
|
||||
Thread.sleep(timeMs);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* 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.tests;
|
||||
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.text.format.DateUtils;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
import androidx.test.uiautomator.By;
|
||||
import androidx.test.uiautomator.UiDevice;
|
||||
import androidx.test.uiautomator.Until;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* Functional test for bluetooth unoptimized scanning anomaly detector
|
||||
*
|
||||
* @see com.android.settings.fuelgauge.anomaly.checker.BluetoothScanAnomalyDetector
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class WakelockAnomalyTest {
|
||||
private static final String BATTERY_INTENT = "android.intent.action.POWER_USAGE_SUMMARY";
|
||||
private static final String RES_WAKELOCK_EDITTEXT =
|
||||
"com.android.settings.anomaly.tester:id/wakelock_run_time";
|
||||
private static final String RES_WAKELOCK_BUTTON =
|
||||
"com.android.settings.anomaly.tester:id/wakelock_button";
|
||||
private static final long TIME_OUT = 3000;
|
||||
private UiDevice mDevice;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
final Context context = instrumentation.getContext();
|
||||
mDevice = UiDevice.getInstance(instrumentation);
|
||||
|
||||
// setup environment
|
||||
TestUtils.setUp(instrumentation);
|
||||
// start anomaly-tester app
|
||||
TestUtils.startAnomalyApp(context, mDevice);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
TestUtils.tearDown(InstrumentationRegistry.getInstrumentation());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWakelockAnomaly_longTimeWhileRunning_report() throws InterruptedException {
|
||||
// Set running time
|
||||
final long durationMs = DateUtils.SECOND_IN_MILLIS * 15;
|
||||
TestUtils.setEditTextWithValue(mDevice, RES_WAKELOCK_EDITTEXT, durationMs);
|
||||
|
||||
// Click start button
|
||||
TestUtils.clickButton(mDevice, RES_WAKELOCK_BUTTON);
|
||||
|
||||
// Wait for its running
|
||||
mDevice.pressHome();
|
||||
// Sleeping time less than running time, so the app still holding wakelock when we check
|
||||
TestUtils.wait(mDevice, durationMs - TIME_OUT);
|
||||
|
||||
// Check it in battery main page
|
||||
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
instrumentation.startActivitySync(new Intent(BATTERY_INTENT));
|
||||
assertWithMessage("Doesn't have wakelock anomaly").that(
|
||||
mDevice.wait(Until.findObject(By.text("AnomalyTester draining battery")),
|
||||
TIME_OUT)).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWakelockAnomaly_shortTime_notReport() throws InterruptedException {
|
||||
// Set running time
|
||||
final long durationMs = DateUtils.SECOND_IN_MILLIS;
|
||||
TestUtils.setEditTextWithValue(mDevice, RES_WAKELOCK_EDITTEXT, durationMs);
|
||||
|
||||
// Click start button
|
||||
TestUtils.clickButton(mDevice, RES_WAKELOCK_BUTTON);
|
||||
|
||||
// Wait for its running
|
||||
mDevice.pressHome();
|
||||
TestUtils.wait(mDevice, durationMs);
|
||||
|
||||
// Check it in battery main page
|
||||
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
instrumentation.startActivitySync(new Intent(BATTERY_INTENT));
|
||||
assertWithMessage("Shouldn't have wakelock anomaly").that(
|
||||
mDevice.wait(Until.findObject(By.text("AnomalyTester draining battery")),
|
||||
TIME_OUT)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWakelockAnomaly_longTimeWhileNotRunning_notReport()
|
||||
throws InterruptedException {
|
||||
// Set running time
|
||||
final long durationMs = DateUtils.SECOND_IN_MILLIS * 10;
|
||||
TestUtils.setEditTextWithValue(mDevice, RES_WAKELOCK_EDITTEXT, durationMs);
|
||||
|
||||
// Click start button
|
||||
TestUtils.clickButton(mDevice, RES_WAKELOCK_BUTTON);
|
||||
|
||||
// Wait for its running
|
||||
mDevice.pressHome();
|
||||
// Wait more time for releasing the wakelock
|
||||
TestUtils.wait(mDevice, durationMs + TIME_OUT);
|
||||
|
||||
// Check it in battery main page
|
||||
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
instrumentation.startActivitySync(new Intent(BATTERY_INTENT));
|
||||
assertWithMessage("Shouldn't have wakelock anomaly").that(
|
||||
mDevice.wait(Until.findObject(By.text("AnomalyTester draining battery")),
|
||||
TIME_OUT)).isNull();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user