fix: 引入Settings的Module
This commit is contained in:
34
Settings/tests/anomaly-tester/Android.bp
Normal file
34
Settings/tests/anomaly-tester/Android.bp
Normal file
@@ -0,0 +1,34 @@
|
||||
package {
|
||||
default_team: "trendy_team_android_settings_app",
|
||||
// See: http://go/android-license-faq
|
||||
// A large-scale-change added 'default_applicable_licenses' to import
|
||||
// all of the 'license_kinds' from "packages_apps_Settings_license"
|
||||
// to get the below license kinds:
|
||||
// SPDX-license-identifier-Apache-2.0
|
||||
default_applicable_licenses: ["packages_apps_Settings_license"],
|
||||
}
|
||||
|
||||
android_test {
|
||||
name: "AnomalyTester",
|
||||
|
||||
certificate: "platform",
|
||||
|
||||
libs: ["android.test.runner"],
|
||||
|
||||
static_libs: [
|
||||
"androidx.test.rules",
|
||||
"mockito-target",
|
||||
"androidx.test.uiautomator_uiautomator",
|
||||
"truth",
|
||||
],
|
||||
|
||||
srcs: ["**/*.java"],
|
||||
|
||||
optimize: {
|
||||
enabled: false,
|
||||
},
|
||||
|
||||
platform_apis: true,
|
||||
|
||||
instrumentation_for: "Settings",
|
||||
}
|
||||
54
Settings/tests/anomaly-tester/AndroidManifest.xml
Normal file
54
Settings/tests/anomaly-tester/AndroidManifest.xml
Normal file
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.settings.anomaly.tester">
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
|
||||
<uses-permission android:name="android.permission.BLUETOOTH"/>
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
|
||||
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
|
||||
|
||||
<application
|
||||
android:allowBackup="false"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@android:style/Theme.Material.Light.DarkActionBar">
|
||||
<uses-library android:name="android.test.runner" />
|
||||
<activity
|
||||
android:name=".AnomalyActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<service
|
||||
android:name=".service.AnomalyService"
|
||||
android:exported="false"/>
|
||||
</application>
|
||||
|
||||
<instrumentation
|
||||
android:name="androidx.test.runner.AndroidJUnitRunner"
|
||||
android:targetPackage="com.android.settings"
|
||||
android:label="Settings Test Cases">
|
||||
</instrumentation>
|
||||
|
||||
</manifest>
|
||||
59
Settings/tests/anomaly-tester/res/layout/activity_main.xml
Normal file
59
Settings/tests/anomaly-tester/res/layout/activity_main.xml
Normal file
@@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="4"
|
||||
android:padding="4dp"
|
||||
android:textSize="16sp">
|
||||
<TextView
|
||||
android:id="@+id/displayText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="100000"/>
|
||||
</ScrollView>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="2dp"
|
||||
android:background="#444444"/>
|
||||
|
||||
<ScrollView
|
||||
android:layout_height="0dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_weight="6"
|
||||
android:padding="5dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center">
|
||||
|
||||
<include layout="@layout/bluetooth_anomaly"/>
|
||||
|
||||
<include layout="@layout/wakelock_anomaly"/>
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="6dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Bluetooth Anomaly"
|
||||
android:textSize="16sp"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<EditText
|
||||
android:id="@+id/bluetooth_threshold"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="3"
|
||||
android:layout_height="wrap_content"
|
||||
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:text="6000"
|
||||
android:inputType="number"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/bluetooth_button"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="2"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="START"
|
||||
android:onClick="startBluetoothAnomaly"/>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="6dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Wakelock Anomaly"
|
||||
android:textSize="16sp"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<EditText
|
||||
android:id="@+id/wakelock_threshold"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="3"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Threshold(ms)"
|
||||
android:text="3000"
|
||||
android:inputType="number"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/wakelock_run_time"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="3"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Run time(ms)"
|
||||
android:text="6000"
|
||||
android:inputType="number"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/wakelock_button"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="2"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="START"
|
||||
android:onClick="startWakelockAnomaly"/>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
19
Settings/tests/anomaly-tester/res/values/strings.xml
Normal file
19
Settings/tests/anomaly-tester/res/values/strings.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="app_name" translatable="false">AnomalyTester</string>
|
||||
</resources>
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
38
Settings/tests/componenttests/Android.bp
Normal file
38
Settings/tests/componenttests/Android.bp
Normal file
@@ -0,0 +1,38 @@
|
||||
//############################################################
|
||||
// Settings Component test target. #
|
||||
//############################################################
|
||||
package {
|
||||
default_team: "trendy_team_android_settings_app",
|
||||
// See: http://go/android-license-faq
|
||||
// A large-scale-change added 'default_applicable_licenses' to import
|
||||
// all of the 'license_kinds' from "packages_apps_Settings_license"
|
||||
// to get the below license kinds:
|
||||
// SPDX-license-identifier-Apache-2.0
|
||||
default_applicable_licenses: ["packages_apps_Settings_license"],
|
||||
}
|
||||
|
||||
android_test {
|
||||
name: "SettingsComponentTests",
|
||||
certificate: "platform",
|
||||
privileged: true,
|
||||
srcs: [
|
||||
"src/**/*.java",
|
||||
],
|
||||
|
||||
static_libs: [
|
||||
"truth",
|
||||
"androidx.test.core",
|
||||
"androidx.test.espresso.core",
|
||||
"androidx.test.espresso.intents-nodeps",
|
||||
"androidx.test.runner",
|
||||
"androidx.test.rules",
|
||||
"androidx.test.ext.junit",
|
||||
"mockito-target",
|
||||
],
|
||||
|
||||
test_suites: ["device-tests"],
|
||||
optimize: {
|
||||
enabled: false,
|
||||
},
|
||||
instrumentation_for: "Settings",
|
||||
}
|
||||
43
Settings/tests/componenttests/AndroidManifest.xml
Normal file
43
Settings/tests/componenttests/AndroidManifest.xml
Normal file
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2016 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.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
|
||||
package="com.android.settings.tests.component"
|
||||
android:sharedUserId="android.uid.systemui">
|
||||
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
|
||||
<uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
|
||||
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
|
||||
<application/>
|
||||
|
||||
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
|
||||
android:targetPackage="com.android.settings"
|
||||
android:label="Settings Test Cases">
|
||||
</instrumentation>
|
||||
|
||||
</manifest>
|
||||
30
Settings/tests/componenttests/AndroidTest.xml
Normal file
30
Settings/tests/componenttests/AndroidTest.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
<configuration description="Runs Settings Test Cases.">
|
||||
<option name="test-suite-tag" value="apct" />
|
||||
<option name="test-suite-tag" value="apct-instrumentation" />
|
||||
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
|
||||
<option name="cleanup-apks" value="true" />
|
||||
<option name="test-file-name" value="SettingsComponentTests.apk" />
|
||||
</target_preparer>
|
||||
|
||||
<option name="test-tag" value="SettingsComponentTests" />
|
||||
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
|
||||
<option name="package" value="com.android.settings.tests.component" />
|
||||
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
|
||||
<option name="hidden-api-checks" value="false"/>
|
||||
</test>
|
||||
</configuration>
|
||||
3
Settings/tests/componenttests/OWNERS
Normal file
3
Settings/tests/componenttests/OWNERS
Normal file
@@ -0,0 +1,3 @@
|
||||
# People who can approve changes for submission
|
||||
jyhsu@google.com
|
||||
syaoranx@google.com
|
||||
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.biometrics;
|
||||
|
||||
import static android.hardware.biometrics.BiometricManager.Authenticators.BIOMETRIC_STRONG;
|
||||
import static android.provider.Settings.ACTION_BIOMETRIC_ENROLL;
|
||||
|
||||
import static androidx.test.espresso.intent.Intents.intended;
|
||||
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent;
|
||||
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra;
|
||||
|
||||
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS;
|
||||
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE;
|
||||
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.hardware.biometrics.SensorProperties;
|
||||
import android.hardware.face.FaceManager;
|
||||
import android.hardware.face.FaceSensorPropertiesInternal;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.test.core.app.ActivityScenario;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.espresso.intent.Intents;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.MediumTest;
|
||||
|
||||
import com.android.internal.widget.LockPatternChecker;
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.internal.widget.LockscreenCredential;
|
||||
import com.android.settings.biometrics.face.FaceEnrollIntroduction;
|
||||
import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroduction;
|
||||
import com.android.settings.password.ChooseLockGeneric;
|
||||
import com.android.settings.password.ChooseLockSettingsHelper;
|
||||
import com.android.settings.password.ConfirmLockPassword;
|
||||
import com.android.settings.testutils.AdbUtils;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@MediumTest
|
||||
public class BiometricEnrollActivityTest {
|
||||
|
||||
private static final String TAG = "BiometricEnrollActivityTest";
|
||||
private static final int ADB_TIMEOUT_MS = 5000;
|
||||
private static final String TEST_PIN = "1234";
|
||||
|
||||
private final Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private boolean mHasFace;
|
||||
private boolean mHasFingerprint;
|
||||
private boolean mIsFaceStrong;
|
||||
private boolean mIsFingerprintStrong;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
Intents.init();
|
||||
final PackageManager pm = mContext.getPackageManager();
|
||||
mHasFingerprint = pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT);
|
||||
mHasFace = pm.hasSystemFeature(PackageManager.FEATURE_FACE);
|
||||
|
||||
if (mHasFace) {
|
||||
final FaceManager faceManager = mContext.getSystemService(FaceManager.class);
|
||||
final List<FaceSensorPropertiesInternal> faceProperties =
|
||||
faceManager.getSensorPropertiesInternal();
|
||||
if (!faceProperties.isEmpty()) {
|
||||
final FaceSensorPropertiesInternal faceProp = faceProperties.get(0);
|
||||
mIsFaceStrong = faceProp.sensorStrength == SensorProperties.STRENGTH_STRONG;
|
||||
}
|
||||
}
|
||||
|
||||
if (mHasFingerprint) {
|
||||
final FingerprintManager fingerprintManager = mContext.getSystemService(
|
||||
FingerprintManager.class);
|
||||
final List<FingerprintSensorPropertiesInternal> fingerProperties =
|
||||
fingerprintManager.getSensorPropertiesInternal();
|
||||
if (!fingerProperties.isEmpty()) {
|
||||
final FingerprintSensorPropertiesInternal fingerProp = fingerProperties.get(0);
|
||||
mIsFingerprintStrong =
|
||||
fingerProp.sensorStrength == SensorProperties.STRENGTH_STRONG;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
public void teardown() throws Exception {
|
||||
Intents.release();
|
||||
AdbUtils.checkStringInAdbCommandOutput(TAG, "locksettings clear --old " + TEST_PIN,
|
||||
"", "", ADB_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launchWithoutPin_setsPin() {
|
||||
try (ActivityScenario<BiometricEnrollActivity> scenario =
|
||||
ActivityScenario.launch(getIntent())) {
|
||||
intended(hasComponent(ChooseLockGeneric.class.getName()));
|
||||
if (mHasFace && mHasFingerprint) {
|
||||
intended(hasExtra(EXTRA_KEY_FOR_BIOMETRICS, true));
|
||||
} else if (mHasFace) {
|
||||
intended(hasExtra(EXTRA_KEY_FOR_FACE, true));
|
||||
} else if (mHasFingerprint) {
|
||||
intended(hasExtra(EXTRA_KEY_FOR_FINGERPRINT, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launchWithPin_confirmsPin() throws Exception {
|
||||
setPin();
|
||||
try (ActivityScenario<BiometricEnrollActivity> scenario =
|
||||
ActivityScenario.launch(getIntent())) {
|
||||
intended(hasComponent(ConfirmLockPassword.InternalActivity.class.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launchWithPinAndPwHandle_confirmsPin() throws Exception {
|
||||
assumeTrue(mHasFace || mHasFingerprint);
|
||||
|
||||
setPin();
|
||||
final Intent intent = getIntent(true /* useInternal */);
|
||||
LockPatternChecker.verifyCredential(new LockPatternUtils(mContext),
|
||||
LockscreenCredential.createPin(TEST_PIN), UserHandle.myUserId(),
|
||||
LockPatternUtils.VERIFY_FLAG_REQUEST_GK_PW_HANDLE, (response, timeoutMs) -> {
|
||||
assertThat(response.containsGatekeeperPasswordHandle()).isTrue();
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE,
|
||||
response.getGatekeeperPasswordHandle());
|
||||
}).get();
|
||||
|
||||
try (ActivityScenario<BiometricEnrollActivity> scenario =
|
||||
ActivityScenario.launch(intent)) {
|
||||
intended(hasComponent(mHasFace && !mHasFingerprint
|
||||
? FaceEnrollIntroduction.class.getName()
|
||||
: FingerprintEnrollIntroduction.class.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launchWithStrongBiometricAllowed_doNotEnrollWeak() throws Exception {
|
||||
assumeTrue(mHasFace || mHasFingerprint);
|
||||
|
||||
// Allow only strong biometrics
|
||||
Intent intent = getIntent();
|
||||
intent.putExtra(Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED, BIOMETRIC_STRONG);
|
||||
|
||||
try (ActivityScenario<BiometricEnrollActivity> scenario =
|
||||
ActivityScenario.launch(intent)) {
|
||||
intended(hasComponent(ChooseLockGeneric.class.getName()));
|
||||
if (mIsFaceStrong && mIsFingerprintStrong) {
|
||||
intended(hasExtra(EXTRA_KEY_FOR_BIOMETRICS, true));
|
||||
} else if (mIsFaceStrong) {
|
||||
intended(hasExtra(EXTRA_KEY_FOR_FACE, true));
|
||||
} else if (mIsFingerprintStrong) {
|
||||
intended(hasExtra(EXTRA_KEY_FOR_FINGERPRINT, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Intent getIntent() {
|
||||
return getIntent(false /* useInternal */);
|
||||
}
|
||||
|
||||
private Intent getIntent(boolean useInternal) {
|
||||
final Intent intent = new Intent(mContext, useInternal
|
||||
? BiometricEnrollActivity.InternalActivity.class : BiometricEnrollActivity.class);
|
||||
intent.setAction(ACTION_BIOMETRIC_ENROLL);
|
||||
return intent;
|
||||
}
|
||||
|
||||
private static void setPin() throws Exception {
|
||||
assertThat(AdbUtils.checkStringInAdbCommandOutput(TAG, "locksettings set-pin " + TEST_PIN,
|
||||
"Pin set to ", "'" + TEST_PIN + "'", ADB_TIMEOUT_MS)).isTrue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.display.darkmode;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.app.TimePickerDialog;
|
||||
import android.app.UiModeManager;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.test.core.app.ActivityScenario;
|
||||
import androidx.test.ext.junit.rules.ActivityScenarioRule;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.runner.lifecycle.Stage;
|
||||
|
||||
import com.android.settings.testutils.CommonUtils;
|
||||
import com.android.settings.testutils.UiUtils;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.time.LocalTime;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class DarkThemeScheduleComponentTest {
|
||||
private static final int DIALOG_START_TIME = 0;
|
||||
private static final int DIALOG_END_TIME = 1;
|
||||
/** The identifier for the positive button. */
|
||||
private static final int BUTTON_POSITIVE = -1;
|
||||
public final String TAG = this.getClass().getName();
|
||||
private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
|
||||
@Rule
|
||||
public ActivityScenarioRule<com.android.settings.Settings.DarkThemeSettingsActivity> rule =
|
||||
new ActivityScenarioRule<>(
|
||||
new Intent(
|
||||
Settings.ACTION_DARK_THEME_SETTINGS).setFlags(
|
||||
Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
private UiModeManager mUiModeManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mUiModeManager = mInstrumentation.getTargetContext().getSystemService(UiModeManager.class);
|
||||
if (mUiModeManager.getNightMode() != UiModeManager.MODE_NIGHT_NO) {
|
||||
mUiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO);
|
||||
}
|
||||
}
|
||||
|
||||
private void test_step_for_custom_time(int startTimeDiff, int endTimeDiff) {
|
||||
|
||||
ActivityScenario scenario = rule.getScenario();
|
||||
scenario.onActivity(activity -> {
|
||||
mUiModeManager.setNightMode(UiModeManager.MODE_NIGHT_CUSTOM);
|
||||
Fragment f =
|
||||
((FragmentActivity) activity).getSupportFragmentManager().getFragments().get(0);
|
||||
DarkModeSettingsFragment fragment = (DarkModeSettingsFragment) f;
|
||||
|
||||
setCustomTime(fragment, DIALOG_START_TIME, LocalTime.now().plusMinutes(startTimeDiff));
|
||||
setCustomTime(fragment, DIALOG_END_TIME, LocalTime.now().plusMinutes(endTimeDiff));
|
||||
|
||||
// The night mode need to reopen the screen to trigger UI change after mode change.
|
||||
CommonUtils.reopenScreen();
|
||||
});
|
||||
|
||||
// Relaunch the scenario to make sure UI apply new mode.
|
||||
scenario.onActivity(activity -> {
|
||||
Log.d(TAG, "Activity Recreated!");
|
||||
UiUtils.waitForActivitiesInStage(2000, Stage.RESUMED);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_dark_mode_in_custom_time() {
|
||||
test_step_for_custom_time(-1, 11);
|
||||
assertThat(checkNightMode(true)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_dark_mode_after_custom_time() {
|
||||
test_step_for_custom_time(-11, -1);
|
||||
assertThat(checkNightMode(false)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_dark_mode_before_custom_time() {
|
||||
test_step_for_custom_time(2, 20);
|
||||
assertThat(checkNightMode(false)).isTrue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets custom time for night mode.
|
||||
*
|
||||
* @param fragment The DarkModeSettingsFragment.
|
||||
* @param dialogId Dialog id for start time or end time.
|
||||
* @param time The time to be set.
|
||||
*/
|
||||
private void setCustomTime(DarkModeSettingsFragment fragment, int dialogId, LocalTime time) {
|
||||
Log.d(TAG, "Start to set custom time " + (dialogId == DIALOG_START_TIME ? "StartTime"
|
||||
: "EndTime") + " to " + time.getHour() + ":" + time.getMinute());
|
||||
TimePickerDialog startTimeDialog = (TimePickerDialog) fragment.onCreateDialog(dialogId);
|
||||
startTimeDialog.updateTime(time.getHour(), time.getMinute());
|
||||
startTimeDialog.onClick(startTimeDialog, BUTTON_POSITIVE);
|
||||
}
|
||||
|
||||
private boolean checkNightMode(boolean isNightMode) {
|
||||
int mask = (isNightMode ? Configuration.UI_MODE_NIGHT_YES : Configuration.UI_MODE_NIGHT_NO);
|
||||
int mode = mInstrumentation.getTargetContext().getResources().getConfiguration().uiMode;
|
||||
return (mode & mask) != 0;
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
Log.d(TAG, "tearDown.");
|
||||
if (mUiModeManager.getNightMode() != UiModeManager.MODE_NIGHT_NO) {
|
||||
mUiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.fuelgauge.batterysaver;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assert_;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Instrumentation;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.PowerManager;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.test.core.app.ActivityScenario;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.rules.ActivityScenarioRule;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import com.android.settings.Settings.BatterySaverSettingsActivity;
|
||||
import com.android.settings.SettingsPreferenceFragment;
|
||||
import com.android.settings.testutils.AdbUtils;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class BatterySaverButtonPreferenceControllerComponentTest {
|
||||
private static final String TAG =
|
||||
BatterySaverButtonPreferenceControllerComponentTest.class.getSimpleName();
|
||||
private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
private final PowerManager mManager =
|
||||
(PowerManager) mInstrumentation.getTargetContext().getSystemService(
|
||||
Context.POWER_SERVICE);
|
||||
@Rule
|
||||
public ActivityScenarioRule<BatterySaverSettingsActivity> rule = new ActivityScenarioRule<>(
|
||||
new Intent(
|
||||
Settings.ACTION_BATTERY_SAVER_SETTINGS).setFlags(
|
||||
Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mInstrumentation.getUiAutomation().executeShellCommand("dumpsys battery unplug");
|
||||
mInstrumentation.getUiAutomation().executeShellCommand("settings get global low_power 0");
|
||||
}
|
||||
|
||||
private BatterySaverButtonPreferenceController get_battery_saver_controller(Activity activity) {
|
||||
BatterySaverButtonPreferenceController controller =
|
||||
new BatterySaverButtonPreferenceController(
|
||||
ApplicationProvider.getApplicationContext(), "battery_saver");
|
||||
Fragment f =
|
||||
((FragmentActivity) activity).getSupportFragmentManager().getFragments().get(0);
|
||||
controller.displayPreference(((SettingsPreferenceFragment) f).getPreferenceScreen());
|
||||
return controller;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_check_battery_saver_button() throws Exception {
|
||||
ActivityScenario scenario = rule.getScenario();
|
||||
scenario.onActivity(activity -> {
|
||||
BatterySaverButtonPreferenceController controller =
|
||||
get_battery_saver_controller(activity);
|
||||
controller.setChecked(true);
|
||||
checkPowerSaverMode(true);
|
||||
|
||||
controller.setChecked(false);
|
||||
checkPowerSaverMode(false);
|
||||
});
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
mInstrumentation.getUiAutomation().executeShellCommand("settings get global low_power 0");
|
||||
mInstrumentation.getUiAutomation().executeShellCommand("dumpsys battery reset");
|
||||
}
|
||||
|
||||
private void checkPowerSaverMode(boolean enabled) {
|
||||
//Check through adb. Note that this needs to be done first, or a wait and poll needs to be
|
||||
//done to the manager.isPowerSaveMode(), because calling isPowerSaveMode immediately after
|
||||
//setting it does not return true. It takes a while for isPowerSaveMode() to return the
|
||||
//up-to-date value.
|
||||
try {
|
||||
assertThat(
|
||||
AdbUtils.checkStringInAdbCommandOutput(TAG, "settings get global low_power",
|
||||
null, enabled ? "1" : "0", 1000)).isTrue();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, e.getMessage());
|
||||
assert_().fail();
|
||||
}
|
||||
|
||||
//Check through manager
|
||||
assertThat(mManager.isPowerSaveMode() == enabled).isTrue();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.homepage;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assert_;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class HomepageComponentTest {
|
||||
public final String TAG = this.getClass().getSimpleName();
|
||||
|
||||
private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
|
||||
@Test
|
||||
public void test_launch_all_settings_in_home()
|
||||
throws ClassNotFoundException {
|
||||
|
||||
List<Intent> launchIntents = ImmutableList.of(
|
||||
|
||||
// Wifi
|
||||
// Implemented in WifiSettings2ActivityTest
|
||||
|
||||
// Connected devices
|
||||
new Intent(Settings.ACTION_BLUETOOTH_SETTINGS),
|
||||
|
||||
// Applications
|
||||
new Intent(Settings.ACTION_AUTO_ROTATE_SETTINGS),
|
||||
|
||||
// Notifications
|
||||
new Intent(Settings.ACTION_NOTIFICATION_SETTINGS),
|
||||
|
||||
// Display
|
||||
new Intent(Settings.ACTION_DISPLAY_SETTINGS),
|
||||
|
||||
// Battery
|
||||
// Implemented in fuelgauge.batterysaver
|
||||
|
||||
// Storage
|
||||
new Intent(Settings.ACTION_INTERNAL_STORAGE_SETTINGS),
|
||||
|
||||
// Sound
|
||||
new Intent(Settings.ACTION_SOUND_SETTINGS),
|
||||
|
||||
// Display
|
||||
new Intent(Settings.ACTION_DISPLAY_SETTINGS),
|
||||
|
||||
// Wallpaper
|
||||
new Intent(mInstrumentation.getTargetContext(), Class.forName(
|
||||
"com.android.settings.wallpaper.WallpaperSuggestionActivity")),
|
||||
|
||||
// A11y
|
||||
new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS),
|
||||
|
||||
// Security
|
||||
new Intent(Settings.ACTION_SECURITY_SETTINGS),
|
||||
|
||||
// Privacy
|
||||
new Intent(Settings.ACTION_PRIVACY_SETTINGS),
|
||||
|
||||
// Location
|
||||
new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS),
|
||||
|
||||
// Emergency ? EmergencyDashboardFragment
|
||||
// TODO: find out launch method
|
||||
|
||||
// Password & Account
|
||||
new Intent(Settings.ACTION_SYNC_SETTINGS),
|
||||
|
||||
// Digital wellbeing
|
||||
// Use IA link
|
||||
new Intent().setComponent(
|
||||
new ComponentName(
|
||||
"com.google.android.apps.wellbeing",
|
||||
"com.google.android.apps.wellbeing.settings"
|
||||
+ ".TopLevelSettingsActivity")),
|
||||
|
||||
// Google
|
||||
// Use IA link
|
||||
new Intent().setComponent(
|
||||
new ComponentName(
|
||||
"com.google.android.gms",
|
||||
"com.google.android.gms.app.settings.GoogleSettingsIALink")),
|
||||
|
||||
// System ?
|
||||
// TODO: find out launch method.
|
||||
|
||||
// About
|
||||
new Intent(Settings.ACTION_DEVICE_INFO_SETTINGS)
|
||||
|
||||
);
|
||||
|
||||
for (Intent intent : launchIntents) {
|
||||
Log.d(TAG, "Start to launch intent " + intent.getAction());
|
||||
try {
|
||||
mInstrumentation.getTargetContext()
|
||||
.startActivity(intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Launch with exception. " + e.toString());
|
||||
assert_().fail();
|
||||
}
|
||||
// Launch success without exception.
|
||||
assertThat(Boolean.TRUE).isTrue();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.network;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.provider.Settings;
|
||||
import android.provider.SettingsSlicesContract;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import com.android.settings.testutils.UiUtils;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class AirplaneModePreferenceControllerComponentTest {
|
||||
// Airplane on off status
|
||||
private static final int ON = 1;
|
||||
private static final int OFF = 0;
|
||||
public final String TAG = this.getClass().getName();
|
||||
private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
private boolean mOriginAirplaneModeIsOn;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
// Make sure origin airplane mode is OFF.
|
||||
mOriginAirplaneModeIsOn = is_airplane_mode_on();
|
||||
if (mOriginAirplaneModeIsOn) {
|
||||
Log.d(TAG, "Origin airplane mode is on, turn it off.");
|
||||
Settings.Global.putInt(mInstrumentation.getTargetContext().getContentResolver(),
|
||||
Settings.Global.AIRPLANE_MODE_ON, OFF);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests on/off airplane mode repeatedly.
|
||||
* Previously, a bug describe that crash issue if user on off airplane mode repeatedly.
|
||||
* This case try to switch on & off airplane mode for 10 times to check crash issue.
|
||||
*/
|
||||
@Test
|
||||
public void test_on_off_airplane_mode_multiple_times() {
|
||||
AirplaneModePreferenceController controller =
|
||||
new AirplaneModePreferenceController(mInstrumentation.getTargetContext(),
|
||||
SettingsSlicesContract.KEY_AIRPLANE_MODE);
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
Log.d(TAG, "Test #" + (i + 1));
|
||||
controller.setChecked(true);
|
||||
assertThat(UiUtils.waitUntilCondition(1000,
|
||||
() -> is_airplane_mode_on())).isTrue();
|
||||
|
||||
controller.setChecked(false);
|
||||
assertThat(UiUtils.waitUntilCondition(1000,
|
||||
() -> !is_airplane_mode_on())).isTrue();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean is_airplane_mode_on() {
|
||||
return Settings.System.getInt(
|
||||
mInstrumentation.getTargetContext().getContentResolver(),
|
||||
Settings.Global.AIRPLANE_MODE_ON, OFF) != 0;
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if (is_airplane_mode_on() != mOriginAirplaneModeIsOn) {
|
||||
Settings.Global.putInt(mInstrumentation.getTargetContext().getContentResolver(),
|
||||
Settings.Global.AIRPLANE_MODE_ON, (
|
||||
mOriginAirplaneModeIsOn ? ON : OFF));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.network.telephony;
|
||||
|
||||
import static com.android.settings.testutils.CommonUtils.set_wifi_enabled;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.telecom.TelecomManager;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.test.core.app.ActivityScenario;
|
||||
import androidx.test.ext.junit.rules.ActivityScenarioRule;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import com.android.settings.Settings;
|
||||
import com.android.settings.testutils.CommonUtils;
|
||||
import com.android.settings.testutils.UiUtils;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
import com.android.settingslib.mobile.dataservice.MobileNetworkInfoEntity;
|
||||
import com.android.settingslib.mobile.dataservice.SubscriptionInfoEntity;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class MobileDataPreferenceControllerComponentTest {
|
||||
|
||||
@Mock
|
||||
private Lifecycle mLifecycle;
|
||||
@Mock
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
|
||||
public static final int TIMEOUT = 2000;
|
||||
private static int sSubscriptionId = 2;
|
||||
public final String TAG = this.getClass().getName();
|
||||
private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
private final WifiManager mWifiManager =
|
||||
(WifiManager) mInstrumentation.getTargetContext().getSystemService(
|
||||
Context.WIFI_SERVICE);
|
||||
private final TelephonyManager mTelephonyManager =
|
||||
(TelephonyManager) mInstrumentation.getTargetContext().getSystemService(
|
||||
Context.TELEPHONY_SERVICE);
|
||||
private final TelecomManager mTelecomManager =
|
||||
(TelecomManager) mInstrumentation.getTargetContext().getSystemService(
|
||||
Context.TELECOM_SERVICE);
|
||||
|
||||
@Rule
|
||||
public ActivityScenarioRule<Settings.MobileNetworkActivity>
|
||||
rule = new ActivityScenarioRule<>(
|
||||
new Intent(android.provider.Settings.ACTION_DATA_ROAMING_SETTINGS)
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
private boolean mOriginDataEnabled;
|
||||
private boolean mOriginWifiEnabled;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mOriginWifiEnabled = mWifiManager.isWifiEnabled();
|
||||
// Disable wifi
|
||||
set_wifi_enabled(false);
|
||||
|
||||
// Enable mobile data
|
||||
mOriginDataEnabled = mTelephonyManager.isDataEnabled();
|
||||
if (!mOriginDataEnabled) {
|
||||
mTelephonyManager.enableDataConnectivity();
|
||||
}
|
||||
|
||||
// Current sim card is not available for data network.
|
||||
sSubscriptionId = SubscriptionManager.getDefaultDataSubscriptionId();
|
||||
Assume.assumeTrue("Device cannot mobile network! Should ignore test.",
|
||||
sSubscriptionId != SubscriptionManager.INVALID_SUBSCRIPTION_ID);
|
||||
|
||||
int simState = mTelephonyManager.getSimState();
|
||||
Assume.assumeTrue("Sim card is not ready. Expect: " + TelephonyManager.SIM_STATE_READY
|
||||
+ ", Actual: " + simState, simState == TelephonyManager.SIM_STATE_READY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the mobile network is disabled.
|
||||
* Precondition:
|
||||
* Disabled wifi, and enabled mobile network.
|
||||
* Steps:
|
||||
* 1. Launch mobile data page.
|
||||
* 2. Turn off mobile data from switch.
|
||||
* [Check]
|
||||
* - Mobile data is turned off via TelephonyManager.
|
||||
* - Open socket connection https://www.google.net and check the connection failed.
|
||||
*/
|
||||
@Test
|
||||
public void test_disable_mobile_network() {
|
||||
ActivityScenario scenario = rule.getScenario();
|
||||
scenario.onActivity(activity -> {
|
||||
try {
|
||||
URL url = new URL("https://www.google.net");
|
||||
MobileDataPreferenceController controller = new MobileDataPreferenceController(
|
||||
mInstrumentation.getTargetContext(), "mobile_data", mLifecycle,
|
||||
mLifecycleOwner, sSubscriptionId);
|
||||
FragmentManager manager = ((FragmentActivity) activity).getSupportFragmentManager();
|
||||
controller.init(manager, sSubscriptionId, mock(SubscriptionInfoEntity.class), mock(
|
||||
MobileNetworkInfoEntity.class));
|
||||
|
||||
// Make sure mobile network can connect at first.
|
||||
assertThat(UiUtils.waitUntilCondition(1000,
|
||||
() -> CommonUtils.connectToURL(url))).isTrue();
|
||||
|
||||
Log.d(TAG, "Start to click ");
|
||||
controller.setChecked(false);
|
||||
Log.d(TAG, "Set Checked, wait for fully close.");
|
||||
|
||||
// Assert the configuration is set.
|
||||
assertThat(UiUtils.waitUntilCondition(10000,
|
||||
() -> !mTelephonyManager.isDataEnabled())).isTrue();
|
||||
|
||||
// Assert the network is not connectable.
|
||||
assertThat(UiUtils.waitUntilCondition(1000,
|
||||
() -> CommonUtils.connectToURL(url))).isFalse();
|
||||
|
||||
} catch (IOException e) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
// Restore wifi status wifi
|
||||
set_wifi_enabled(mOriginWifiEnabled);
|
||||
|
||||
// Restore mobile data status
|
||||
if (mOriginDataEnabled != mTelephonyManager.isDataEnabled()) {
|
||||
if (mOriginDataEnabled) {
|
||||
mTelephonyManager.enableDataConnectivity();
|
||||
} else {
|
||||
mTelephonyManager.disableDataConnectivity();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.notification;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.content.Intent;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.test.core.app.ActivityScenario;
|
||||
import androidx.test.ext.junit.rules.ActivityScenarioRule;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.runner.lifecycle.Stage;
|
||||
|
||||
import com.android.settings.testutils.CommonUtils;
|
||||
import com.android.settings.testutils.UiUtils;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class AppNotificationComponentTest {
|
||||
private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
private final String mNoSlientAppName = "com.google.android.dialer";
|
||||
public final String TAG = this.getClass().getName();
|
||||
|
||||
@Rule
|
||||
public ActivityScenarioRule<com.android.settings.Settings.AppNotificationSettingsActivity>
|
||||
rule = new ActivityScenarioRule<>(
|
||||
new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
|
||||
.putExtra(Settings.EXTRA_APP_PACKAGE, mNoSlientAppName)
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
|
||||
/**
|
||||
* Tests user should not able to modify notification settings for some system apps.
|
||||
* In this case, test `phone` app that will disabled notification configuration.
|
||||
* Steps:
|
||||
* 1. Open notification page of phone app.
|
||||
* 2. Checks system privilege notification should not able to be changed.
|
||||
*/
|
||||
@Test
|
||||
public void test_special_app_could_not_disable_notification() {
|
||||
List<String> disabledList = Arrays.asList("Default", "Incoming calls",
|
||||
"Background Processing", "Missed calls",
|
||||
"Ongoing calls", "Voicemails");
|
||||
|
||||
ActivityScenario ac = rule.getScenario();
|
||||
ac.onActivity(
|
||||
activity -> {
|
||||
View recyclerView = activity.findViewById(
|
||||
CommonUtils.getResId("recycler_view"));
|
||||
|
||||
if (recyclerView == null) {
|
||||
Log.d("UI_UTILS",
|
||||
"Target not found: R.id.recycler_view #" + Integer.toHexString(
|
||||
CommonUtils.getResId("recycler_view")));
|
||||
UiUtils.dumpView(UiUtils.getFirstViewFromActivity(activity));
|
||||
assertThat(Boolean.TRUE).isFalse();
|
||||
}
|
||||
|
||||
UiUtils.waitUntilCondition(5000,
|
||||
() -> recyclerView.findViewById(CommonUtils.getResId("recycler_view"))
|
||||
!= null);
|
||||
|
||||
View mainSwitchBar = recyclerView.findViewById(
|
||||
CommonUtils.getResId("main_switch_bar"));
|
||||
|
||||
assertThat(mainSwitchBar.isEnabled()).isEqualTo(false);
|
||||
Log.d(TAG, "main switch bar = " + mainSwitchBar.isEnabled());
|
||||
|
||||
UiUtils.waitForActivitiesInStage(10000, Stage.RESUMED);
|
||||
Log.d(TAG, "In stage!.");
|
||||
|
||||
UiUtils.dumpView(UiUtils.getFirstViewFromActivity(activity));
|
||||
|
||||
// The privileges are under the recycle view. Fetch all of them and check.
|
||||
ViewGroup viewGroup = (ViewGroup) recyclerView;
|
||||
|
||||
for (int i = 0; i < viewGroup.getChildCount(); i++) {
|
||||
if (viewGroup.getChildAt(i) instanceof LinearLayout) {
|
||||
// A notification in Settings should have both switch_widget and text.
|
||||
// There has another circle pin is no belongs to Settings package.
|
||||
// But belongs to Switch in Android.
|
||||
View sWidget = viewGroup.getChildAt(i).findViewById(
|
||||
CommonUtils.getResId("switchWidget"));
|
||||
TextView sText = viewGroup.getChildAt(i).findViewById(
|
||||
android.R.id.title);
|
||||
if (sText != null && sWidget != null
|
||||
&& disabledList.stream().anyMatch(
|
||||
str -> str.equals(sText.getText().toString().trim()))) {
|
||||
|
||||
assertThat(sWidget.isEnabled()).isFalse();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.privacy;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import com.android.settings.testutils.AdbUtils;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class EnabledContentCapturePreferenceControllerComponentTest {
|
||||
private Instrumentation mInstrumentation;
|
||||
private static final String TAG =
|
||||
EnabledContentCapturePreferenceControllerComponentTest.class.getSimpleName();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
if (null == mInstrumentation) {
|
||||
mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_uncheck_content_capture() throws Exception {
|
||||
content_capture_checkbox_test_helper(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_check_content_capture() throws Exception {
|
||||
content_capture_checkbox_test_helper(true);
|
||||
}
|
||||
|
||||
private void content_capture_checkbox_test_helper(boolean check) throws Exception {
|
||||
EnableContentCapturePreferenceController enableContentCapturePreferenceController =
|
||||
new EnableContentCapturePreferenceController(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
"Test_key");
|
||||
enableContentCapturePreferenceController.setChecked(check);
|
||||
|
||||
//Check through adb command
|
||||
assertThat(AdbUtils.checkStringInAdbCommandOutput(TAG, "dumpsys content_capture",
|
||||
"Users disabled by Settings: ", check ? "{}" : "{0=true}", 1000)).isTrue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.testutils;
|
||||
|
||||
import android.os.ParcelFileDescriptor;
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class AdbUtils {
|
||||
public static String getCallerClassName() {
|
||||
StackTraceElement[] stElements = Thread.currentThread().getStackTrace();
|
||||
for (int i = 1; i < stElements.length; i++) {
|
||||
StackTraceElement ste = stElements[i];
|
||||
if (!ste.getClassName().equals(new Object() {
|
||||
}.getClass().getEnclosingClass().getName()) && ste.getClassName().indexOf(
|
||||
"java.lang.Thread") != 0) {
|
||||
return ste.getClassName();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean checkStringInAdbCommandOutput(String logTag, String command,
|
||||
String prefix, String target, int timeoutInMillis) throws Exception {
|
||||
long start = System.nanoTime();
|
||||
|
||||
//Sometimes the change do no reflect in adn output immediately, so need a wait and poll here
|
||||
while (System.nanoTime() - start < (timeoutInMillis * 1000000)) {
|
||||
String result = shell(command);
|
||||
if (result.contains(prefix == null ? "" : prefix)
|
||||
&& result.contains(target == null ? "" : target)) {
|
||||
return true;
|
||||
} else {
|
||||
Thread.sleep(100);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String shell(String shellCommand) {
|
||||
String returnValue = "";
|
||||
try (ParcelFileDescriptor.AutoCloseInputStream in =
|
||||
new ParcelFileDescriptor.AutoCloseInputStream(
|
||||
InstrumentationRegistry.getInstrumentation()
|
||||
.getUiAutomation()
|
||||
.executeShellCommand(shellCommand))) {
|
||||
try (BufferedReader br =
|
||||
new BufferedReader(
|
||||
new InputStreamReader(in, StandardCharsets.UTF_8))) {
|
||||
returnValue = br.lines().collect(Collectors.joining());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.testutils;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Instrumentation;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.Environment;
|
||||
import android.os.PowerManager;
|
||||
import android.os.StrictMode;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
|
||||
public class CommonUtils {
|
||||
private static final String TAG = CommonUtils.class.getSimpleName();
|
||||
private static final Instrumentation sInstrumentation =
|
||||
InstrumentationRegistry.getInstrumentation();
|
||||
private static final WifiManager sWifiManager =
|
||||
(WifiManager) sInstrumentation.getTargetContext().getSystemService(
|
||||
Context.WIFI_SERVICE);
|
||||
private static final PowerManager sPowerManager =
|
||||
(PowerManager) sInstrumentation.getTargetContext().getSystemService(
|
||||
Context.POWER_SERVICE);
|
||||
|
||||
public static void takeScreenshot(Activity activity) {
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
try {
|
||||
// image naming and path to include sd card appending name you choose for file
|
||||
String mPath =
|
||||
Environment.getExternalStorageDirectory().toString() + "/" + now + ".jpg";
|
||||
Log.d(TAG, "screenshot path is " + mPath);
|
||||
|
||||
// create bitmap screen capture
|
||||
View v1 = activity.getWindow().getDecorView().getRootView();
|
||||
v1.setDrawingCacheEnabled(true);
|
||||
Bitmap bitmap = Bitmap.createBitmap(v1.getDrawingCache());
|
||||
v1.setDrawingCacheEnabled(false);
|
||||
|
||||
File imageFile = new File(mPath);
|
||||
|
||||
FileOutputStream outputStream = new FileOutputStream(imageFile);
|
||||
int quality = 100;
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream);
|
||||
outputStream.flush();
|
||||
outputStream.close();
|
||||
} catch (Throwable e) {
|
||||
// Several error may come out with file handling or DOM
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean connectToURL(URL url) {
|
||||
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
|
||||
StrictMode.setThreadPolicy(policy);
|
||||
HttpURLConnection connection = null;
|
||||
try {
|
||||
connection = (HttpsURLConnection) url.openConnection();
|
||||
connection.setRequestMethod("GET");
|
||||
connection.setConnectTimeout(8000);
|
||||
connection.setReadTimeout(8000);
|
||||
connection.connect();
|
||||
if (HttpURLConnection.HTTP_OK == connection.getResponseCode()) {
|
||||
InputStream in = connection.getInputStream();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
|
||||
StringBuilder response = new StringBuilder();
|
||||
String line;
|
||||
while (null != (line = reader.readLine())) {
|
||||
response.append(line);
|
||||
}
|
||||
Log.d(TAG, "Connection success! " + response.toString());
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, e.toString());
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
} finally {
|
||||
if (null != connection) {
|
||||
connection.disconnect();
|
||||
}
|
||||
}
|
||||
Log.d(TAG, "End, return false.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a resource identifier for the given resource name in Settings app.
|
||||
*
|
||||
* @param name The name of the desired resource.
|
||||
* @return int The associated resource identifier. Returns 0 if no such resource was found. (0
|
||||
* is not a valid resource ID.)
|
||||
*/
|
||||
public static int getResId(String name) {
|
||||
return InstrumentationRegistry.getInstrumentation().getTargetContext().getResources()
|
||||
.getIdentifier(name, "id", Constants.SETTINGS_PACKAGE_NAME);
|
||||
}
|
||||
|
||||
public static void reopenScreen() {
|
||||
sPowerManager.goToSleep(SystemClock.uptimeMillis());
|
||||
// According to local test, we need to sleep to wait it fully processed.
|
||||
// 1000 ms is a good value to sleep, otherwise it might cause keyDispatchingTimedOut.
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
UiUtils.waitUntilCondition(1000, () -> !sPowerManager.isInteractive());
|
||||
sPowerManager.wakeUp(SystemClock.uptimeMillis());
|
||||
UiUtils.waitUntilCondition(1000, () -> sPowerManager.isInteractive());
|
||||
|
||||
// After power on screen, need to unlock and goto home page.
|
||||
sPowerManager.wakeUp(1000, PowerManager.WAKE_REASON_POWER_BUTTON, "Wakeup");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets wifi status to given enable / disable via ADB command.
|
||||
*/
|
||||
public static void set_wifi_enabled(boolean enable) {
|
||||
final int timeoutMsec = 10000;
|
||||
Log.d(TAG, "Set wifi status to " + enable);
|
||||
if (sWifiManager.isWifiEnabled() != enable) {
|
||||
AdbUtils.shell("svc wifi " + (enable ? "enable" : "disable"));
|
||||
if (!UiUtils.waitUntilCondition(timeoutMsec,
|
||||
() -> sWifiManager.isWifiEnabled() == enable)) {
|
||||
Log.e(TAG, "Cannot set wifi to " + (enable ? "enabl" : "disable") + ", timeout "
|
||||
+ timeoutMsec + " (ms).");
|
||||
Log.e(TAG, "See logcat for more information.");
|
||||
}
|
||||
Log.d(TAG, "After configuration wifi status = " + sWifiManager.isWifiEnabled());
|
||||
} else {
|
||||
Log.d(TAG, "Wifi is enable is already " + enable + ", no need to change.");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.testutils;
|
||||
|
||||
public class Constants {
|
||||
public static final long ACTIVITY_LAUNCH_WAIT_TIMEOUT = 5000;
|
||||
public static final long VIEW_APPEAR_WAIT_MEDIUM_TIMEOUT = 5000;
|
||||
public static final long WIFI_CONNECT_WAIT_TIMEOUT = 15000;
|
||||
public static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.testutils;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry;
|
||||
import androidx.test.runner.lifecycle.Stage;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class UiUtils {
|
||||
private static final String TAG = "UI_UTILS";
|
||||
|
||||
public static boolean waitUntilCondition(long timeoutInMillis, Supplier<Boolean> condition) {
|
||||
long start = System.nanoTime();
|
||||
while (System.nanoTime() - start < (timeoutInMillis * 1000000)) {
|
||||
try {
|
||||
//Eat NPE from condition because there's a concurrency issue that when calling
|
||||
//findViewById when the view hierarchy is still rendering, it sometimes encounter
|
||||
//null views that may exist few milliseconds before, and causes a NPE.
|
||||
if (condition.get()) {
|
||||
return true;
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
Log.w(TAG, "Condition not match and timeout for waiting " + timeoutInMillis + "(ms).");
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean waitForActivitiesInStage(long timeoutInMillis, Stage stage) {
|
||||
final Collection<Activity> activities = new ArrayList<>();
|
||||
waitUntilCondition(Constants.ACTIVITY_LAUNCH_WAIT_TIMEOUT, () -> {
|
||||
activities.addAll(
|
||||
ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(
|
||||
Stage.RESUMED));
|
||||
return activities.size() > 0;
|
||||
});
|
||||
|
||||
return activities.size() > 0;
|
||||
}
|
||||
|
||||
public static void dumpView(View view) {
|
||||
dumpViewRecursive(view, 0, 0, 0);
|
||||
}
|
||||
|
||||
public static View getFirstViewFromActivity(Activity activity) {
|
||||
return ((FragmentActivity) activity).getSupportFragmentManager().getFragments().get(
|
||||
0).getView();
|
||||
}
|
||||
|
||||
private static void dumpViewRecursive(View view, int layer, int index, int total) {
|
||||
if (view instanceof ViewGroup) {
|
||||
Log.i(TAG, "L[" + layer + "] PARENT -> " + (index + 1) + "/" + total + " >> "
|
||||
+ view.toString());
|
||||
System.out.println(
|
||||
TAG + " L[" + layer + "] PARENT -> " + (index + 1) + "/" + total + " >> "
|
||||
+ view.toString());
|
||||
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
|
||||
dumpViewRecursive(((ViewGroup) view).getChildAt(i), layer + 1, i + 1,
|
||||
((ViewGroup) view).getChildCount());
|
||||
}
|
||||
} else {
|
||||
Log.i(TAG, "L[" + layer + "] =END= -> " + (index + 1) + "/" + total + " >> "
|
||||
+ view.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.users;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.os.UserManager;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.test.core.app.ActivityScenario;
|
||||
import androidx.test.ext.junit.rules.ActivityScenarioRule;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import com.android.settings.Settings;
|
||||
import com.android.settings.testutils.AdbUtils;
|
||||
import com.android.settings.testutils.UiUtils;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Random;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class UserSettingsComponentTest {
|
||||
public static final int TIMEOUT = 2000;
|
||||
private static final int USER_TYPE_RESTRICTED_PROFILE = 2;
|
||||
public final String TAG = this.getClass().getName();
|
||||
private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
private final ArrayList<Integer> mOriginUserIds = new ArrayList<>();
|
||||
private final UserManager mUserManager =
|
||||
(UserManager) mInstrumentation.getTargetContext().getSystemService("user");
|
||||
@Rule
|
||||
public ActivityScenarioRule<Settings.UserSettingsActivity>
|
||||
rule = new ActivityScenarioRule<>(
|
||||
new Intent(android.provider.Settings.ACTION_USER_SETTINGS)
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
for (UserInfo info : mUserManager.getUsers()) {
|
||||
mOriginUserIds.add(info.id);
|
||||
}
|
||||
|
||||
// Enable multiple user switch.
|
||||
if (!mUserManager.isUserSwitcherEnabled()) {
|
||||
android.provider.Settings.Global.putInt(
|
||||
mInstrumentation.getTargetContext().getContentResolver(),
|
||||
android.provider.Settings.Global.USER_SWITCHER_ENABLED, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_new_user_on_multiple_setting_page() throws IOException {
|
||||
String randomUserName = gendrate_random_name(10);
|
||||
ActivityScenario scenario = rule.getScenario();
|
||||
scenario.onActivity(activity -> {
|
||||
Fragment f =
|
||||
((FragmentActivity) activity).getSupportFragmentManager().getFragments().get(0);
|
||||
UserSettings us = (UserSettings) f;
|
||||
Log.d(TAG, "Start to add user :" + randomUserName);
|
||||
us.createUser(USER_TYPE_RESTRICTED_PROFILE, randomUserName);
|
||||
});
|
||||
|
||||
assertThat(
|
||||
UiUtils.waitUntilCondition(5000, () -> mUserManager.getAliveUsers().stream().filter(
|
||||
(user) -> user.name.equals(
|
||||
randomUserName)).findFirst().isPresent())).isTrue();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
int retryNumber = 5;
|
||||
for (int i = 0; i < retryNumber; ++i) {
|
||||
int currentUsersCount = mUserManager.getUserCount();
|
||||
if (currentUsersCount == mOriginUserIds.size()) {
|
||||
break;
|
||||
} else if (i != 0) {
|
||||
Log.d(TAG, "[tearDown] User not fully removed. Retry #" + (i = 1) + " of total "
|
||||
+ mOriginUserIds.size());
|
||||
}
|
||||
|
||||
for (UserInfo info : mUserManager.getUsers()) {
|
||||
if (mOriginUserIds.contains(info.id)) {
|
||||
continue;
|
||||
}
|
||||
Log.d(TAG, "[tearDown] Clean up user {" + info.id + "}:" + info.name);
|
||||
try {
|
||||
AdbUtils.shell("pm remove-user " + info.id);
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "[tearDown] Error occurs while removing user. " + e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String gendrate_random_name(int length) {
|
||||
String seed = "abcdefghijklmnopqrstuvwxyABCDEFGHIJKLMNOPQSTUVWXYZ";
|
||||
Random r1 = new Random();
|
||||
String result = "";
|
||||
for (int i = 0; i < length; ++i) {
|
||||
result = result + seed.charAt(r1.nextInt(seed.length() - 1));
|
||||
}
|
||||
if (mUserManager.getAliveUsers().stream().map(user -> user.name).collect(
|
||||
Collectors.toList()).contains(result)) {
|
||||
Log.d(TAG, "Name repeated! add padding 'rpt' in the end of name.");
|
||||
result += "rpt";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.wifi;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.MediumTest;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry;
|
||||
import androidx.test.runner.lifecycle.Stage;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Settings.NetworkProviderSettingsActivity;
|
||||
import com.android.settings.fuelgauge.batterysaver.BatterySaverButtonPreferenceControllerComponentTest;
|
||||
import com.android.settings.network.NetworkProviderSettings;
|
||||
import com.android.settings.testutils.CommonUtils;
|
||||
import com.android.settings.testutils.Constants;
|
||||
import com.android.settings.testutils.UiUtils;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@MediumTest
|
||||
/*
|
||||
This test is just for demonstration purpose. For component tests, this approach is not recommended.
|
||||
The reason why it is written this way is because the current Settings app wifi codes have tight
|
||||
coupling with UI, so it's not easy to drive from API without binding the test deeply with the code.
|
||||
*/
|
||||
public class WifiSettings2ActivityTest {
|
||||
private static final String TAG =
|
||||
BatterySaverButtonPreferenceControllerComponentTest.class.getSimpleName();
|
||||
private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
|
||||
@Test @Ignore
|
||||
public void test_connect_to_wifi() throws Exception {
|
||||
//For some reason the ActivityScenario gets null activity here
|
||||
mInstrumentation.getTargetContext().startActivity(
|
||||
new Intent(Settings.ACTION_WIFI_SETTINGS).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
UiUtils.waitForActivitiesInStage(Constants.ACTIVITY_LAUNCH_WAIT_TIMEOUT, Stage.RESUMED);
|
||||
|
||||
final NetworkProviderSettings[] settings = new NetworkProviderSettings[1];
|
||||
mInstrumentation.runOnMainSync(() -> {
|
||||
NetworkProviderSettingsActivity activity = (NetworkProviderSettingsActivity)
|
||||
ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(
|
||||
Stage.RESUMED).iterator().next();
|
||||
settings[0] =
|
||||
(NetworkProviderSettings) activity.getSupportFragmentManager().getFragments()
|
||||
.get(0);
|
||||
});
|
||||
|
||||
//For some reason this view does not appear immediately after the fragment is resumed.
|
||||
View root = settings[0].getView();
|
||||
UiUtils.waitUntilCondition(Constants.VIEW_APPEAR_WAIT_MEDIUM_TIMEOUT,
|
||||
() -> root.findViewById(R.id.settings_button) != null);
|
||||
View view = root.findViewById(R.id.settings_button);
|
||||
view.callOnClick();
|
||||
|
||||
UiUtils.waitForActivitiesInStage(Constants.ACTIVITY_LAUNCH_WAIT_TIMEOUT, Stage.RESUMED);
|
||||
Button[] button = new Button[1];
|
||||
mInstrumentation.runOnMainSync(() -> {
|
||||
FragmentActivity activity =
|
||||
(FragmentActivity) ActivityLifecycleMonitorRegistry.getInstance()
|
||||
.getActivitiesInStage(Stage.RESUMED).iterator().next();
|
||||
List<Fragment> fragments = activity.getSupportFragmentManager().getFragments();
|
||||
Log.d(TAG, "fragment class is " + fragments.get(0).getClass());
|
||||
button[0] = fragments.get(0).getView().findViewById(R.id.button3);
|
||||
});
|
||||
|
||||
//HttpURLConnection needs to run outside of main thread, so running it in the test thread
|
||||
final URL url = new URL("https://www.google.net/");
|
||||
|
||||
//Make sure the connectivity is available before disconnecting from wifi
|
||||
assertThat(CommonUtils.connectToURL(url)).isTrue();
|
||||
|
||||
//Disconnect from wifi
|
||||
button[0].callOnClick();
|
||||
|
||||
//Make sure the Internet connectivity is gone
|
||||
assertThat(CommonUtils.connectToURL(url)).isFalse();
|
||||
|
||||
//Connect to wifi
|
||||
button[0].callOnClick();
|
||||
ConnectivityManager manager =
|
||||
(ConnectivityManager) mInstrumentation.getTargetContext().getSystemService(
|
||||
Context.CONNECTIVITY_SERVICE);
|
||||
|
||||
//For some reason I can't find a way to tell the time that the internet connectivity is
|
||||
//actually available with the new, non-deprecated ways, so I still need to use this.
|
||||
UiUtils.waitUntilCondition(Constants.WIFI_CONNECT_WAIT_TIMEOUT,
|
||||
() -> manager.getActiveNetworkInfo().isConnected());
|
||||
|
||||
//Make sure the connectivity is back again
|
||||
assertThat(CommonUtils.connectToURL(url)).isTrue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.wifi.dpp;
|
||||
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
|
||||
import static androidx.test.espresso.intent.Intents.intended;
|
||||
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasAction;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
||||
import android.app.KeyguardManager;
|
||||
|
||||
import androidx.activity.result.ActivityResult;
|
||||
import androidx.test.core.app.ActivityScenario;
|
||||
import androidx.test.espresso.intent.Intents;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class WifiDppConfiguratorAuthActivityTest {
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
Intents.init();
|
||||
}
|
||||
|
||||
@After
|
||||
public void teardown() throws Exception {
|
||||
Intents.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launchActivity_sendAuthIntent() {
|
||||
ActivityScenario<WifiDppConfiguratorAuthActivity> activityScenario =
|
||||
ActivityScenario.launch(WifiDppConfiguratorAuthActivity.class);
|
||||
assertThat(activityScenario).isNotNull();
|
||||
intended(hasAction(equalTo(KeyguardManager.ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launchActivity_sendQrCodeIntent() {
|
||||
ActivityScenario.launch(WifiDppConfiguratorAuthActivity.class).onActivity(activity ->
|
||||
activity.onAuthResult(new ActivityResult(RESULT_OK, /* data= */ null))
|
||||
);
|
||||
intended(hasAction(
|
||||
equalTo(WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_QR_CODE_GENERATOR)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launchActivity_shouldFinish() {
|
||||
ActivityScenario.launch(WifiDppConfiguratorAuthActivity.class).onActivity(activity -> {
|
||||
activity.onAuthResult(new ActivityResult(RESULT_OK, /* data= */ null));
|
||||
assertThat(activity.isFinishing()).isTrue();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.settingslib.applications;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
|
||||
import androidx.test.core.app.ActivityScenario;
|
||||
import androidx.test.ext.junit.rules.ActivityScenarioRule;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.settings.Settings;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class ApplicationStateComponentTest {
|
||||
private static final String TAG =
|
||||
ApplicationStateComponentTest.class.getSimpleName();
|
||||
private Context mRuntimeApplication;
|
||||
private ApplicationsState mApplicationsState;
|
||||
|
||||
@Rule
|
||||
public ActivityScenarioRule<Settings.ManageApplicationsActivity> rule =
|
||||
new ActivityScenarioRule<>(
|
||||
new Intent(
|
||||
android.provider.Settings.ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS)
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
|
||||
private ApplicationsState.AppEntry createAppEntry(String label, String packageName, int id) {
|
||||
ApplicationInfo appInfo = createApplicationInfo(packageName, id);
|
||||
ApplicationsState.AppEntry appEntry = new ApplicationsState.AppEntry(mRuntimeApplication,
|
||||
appInfo, id);
|
||||
appEntry.label = label;
|
||||
appEntry.mounted = true;
|
||||
return appEntry;
|
||||
}
|
||||
|
||||
private ApplicationInfo createApplicationInfo(String packageName, int uid) {
|
||||
ApplicationInfo appInfo = new ApplicationInfo();
|
||||
appInfo.sourceDir = "foo";
|
||||
appInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
|
||||
appInfo.storageUuid = UUID.randomUUID();
|
||||
appInfo.packageName = packageName;
|
||||
appInfo.uid = uid;
|
||||
return appInfo;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_all_apps_sorting_alpha() {
|
||||
// TODO: Potential unit test candidate.
|
||||
// To test all app list has sorted alphabetical, only need to verify sort function.
|
||||
// This case focus on logic in sort function, and ignore origin locale sorting rule by Java.
|
||||
|
||||
ActivityScenario scenario = rule.getScenario();
|
||||
|
||||
scenario.onActivity(activity -> {
|
||||
mRuntimeApplication = activity.getApplication();
|
||||
mApplicationsState = ApplicationsState.getInstance(activity.getApplication());
|
||||
|
||||
ApplicationsState.AppEntry entry1 = createAppEntry("Info01", "Package1", 0);
|
||||
ApplicationsState.AppEntry entry2 = createAppEntry("Info02", "Package1", 0);
|
||||
ApplicationsState.AppEntry entry3 = createAppEntry("Info01", "Package2", 0);
|
||||
ApplicationsState.AppEntry entry4 = createAppEntry("Info02", "Package2", 0);
|
||||
ApplicationsState.AppEntry entry5 = createAppEntry("Info02", "Package2", 1);
|
||||
assertThat(ApplicationsState.ALPHA_COMPARATOR.compare(entry1, entry2)).isEqualTo(-1);
|
||||
assertThat(ApplicationsState.ALPHA_COMPARATOR.compare(entry2, entry3)).isEqualTo(1);
|
||||
assertThat(ApplicationsState.ALPHA_COMPARATOR.compare(entry3, entry2)).isEqualTo(-1);
|
||||
assertThat(ApplicationsState.ALPHA_COMPARATOR.compare(entry3, entry3)).isEqualTo(0);
|
||||
assertThat(ApplicationsState.ALPHA_COMPARATOR.compare(entry1, entry3)).isEqualTo(-1);
|
||||
assertThat(ApplicationsState.ALPHA_COMPARATOR.compare(entry4, entry5)).isEqualTo(-1);
|
||||
assertThat(ApplicationsState.ALPHA_COMPARATOR.compare(entry5, entry3)).isEqualTo(1);
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright (C) 2020 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 {
|
||||
default_team: "trendy_team_android_settings_app",
|
||||
// See: http://go/android-license-faq
|
||||
// A large-scale-change added 'default_applicable_licenses' to import
|
||||
// all of the 'license_kinds' from "packages_apps_Settings_license"
|
||||
// to get the below license kinds:
|
||||
// SPDX-license-identifier-Apache-2.0
|
||||
default_applicable_licenses: ["packages_apps_Settings_license"],
|
||||
}
|
||||
|
||||
android_test {
|
||||
name: "InstrumentedEntitlementApp",
|
||||
srcs: ["src/**/*.java"],
|
||||
test_suites: ["device-tests"],
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
* Copyright (C) 2020 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.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="android.test.entitlement">
|
||||
|
||||
<application>
|
||||
<activity android:name=".InstrumentedEntitlementActivity"
|
||||
android:label="InstrumentedEntitlementActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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 android.test.entitlement;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
// Instrumented activity for TetherProvisioningActivityTest
|
||||
public class InstrumentedEntitlementActivity extends Activity {
|
||||
}
|
||||
1
Settings/tests/legacy_unit/README
Normal file
1
Settings/tests/legacy_unit/README
Normal file
@@ -0,0 +1 @@
|
||||
Directory for legacy settings unit tests, which are no longer maintained.
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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;
|
||||
|
||||
import static com.android.settings.UserCredentialsSettings.Credential;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Process;
|
||||
import android.test.InstrumentationTestCase;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
/**
|
||||
* User credentials settings fragment tests
|
||||
*
|
||||
* To run the test, use command:
|
||||
* adb shell am instrument -e class com.android.settings.UserCredentialsTest
|
||||
* -w com.android.settings.tests.unit/androidx.test.runner.AndroidJUnitRunner
|
||||
*
|
||||
*/
|
||||
public class UserCredentialsTest extends InstrumentationTestCase {
|
||||
private static final String TAG = "UserCredentialsTests";
|
||||
|
||||
@SmallTest
|
||||
public void testCredentialIsParcelable() {
|
||||
final String alias = "credential-test-alias";
|
||||
Credential c = new Credential(alias, Process.SYSTEM_UID);
|
||||
|
||||
c.storedTypes.add(Credential.Type.CA_CERTIFICATE);
|
||||
c.storedTypes.add(Credential.Type.USER_KEY);
|
||||
|
||||
Parcel p = Parcel.obtain();
|
||||
c.writeToParcel(p, /* flags */ 0);
|
||||
p.setDataPosition(0);
|
||||
|
||||
Credential r = Credential.CREATOR.createFromParcel(p);
|
||||
assertEquals(c.alias, r.alias);
|
||||
assertEquals(c.uid, r.uid);
|
||||
assertEquals(c.storedTypes, r.storedTypes);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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;
|
||||
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.pm.UserInfo;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class UtilsTest extends AndroidTestCase {
|
||||
private static final int TEST_PRIMARY_USER_ID = 10;
|
||||
private static final int TEST_MANAGED_PROFILE_ID = 11;
|
||||
|
||||
@Mock private UserManager mUserManager;
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
// // this is necessary for mockito to work
|
||||
System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString());
|
||||
|
||||
MockitoAnnotations.initMocks(this);
|
||||
when(mUserManager.getUserHandle()).thenReturn(TEST_PRIMARY_USER_ID);
|
||||
UserInfo primaryUser = new UserInfo(TEST_PRIMARY_USER_ID, null,
|
||||
UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_PRIMARY);
|
||||
when(mUserManager.getUserInfo(TEST_PRIMARY_USER_ID)).thenReturn(primaryUser);
|
||||
UserInfo managedProfile = new UserInfo(TEST_MANAGED_PROFILE_ID, null,
|
||||
UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_MANAGED_PROFILE);
|
||||
when(mUserManager.getUserInfo(eq(TEST_MANAGED_PROFILE_ID))).thenReturn(managedProfile);
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testGetManagedProfile() {
|
||||
UserHandle[] userHandles = new UserHandle[] {
|
||||
new UserHandle(TEST_PRIMARY_USER_ID),
|
||||
new UserHandle(TEST_MANAGED_PROFILE_ID)
|
||||
};
|
||||
when(mUserManager.getUserProfiles())
|
||||
.thenReturn(new ArrayList<UserHandle>(Arrays.asList(userHandles)));
|
||||
assertEquals(TEST_MANAGED_PROFILE_ID,
|
||||
Utils.getManagedProfile(mUserManager).getIdentifier());
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testGetManagedProfile_notPresent() {
|
||||
UserHandle[] userHandles = new UserHandle[] {
|
||||
new UserHandle(TEST_PRIMARY_USER_ID)
|
||||
};
|
||||
when(mUserManager.getUserProfiles())
|
||||
.thenReturn(new ArrayList<UserHandle>(Arrays.asList(userHandles)));
|
||||
assertNull(Utils.getManagedProfile(mUserManager));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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.accessibility;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.os.Bundle;
|
||||
import android.os.Looper;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.rule.ActivityTestRule;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.settings.Settings.AccessibilitySettingsActivity;
|
||||
import com.android.settings.core.InstrumentedPreferenceFragment;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ToggleFeaturePreferenceFragmentTest {
|
||||
private static final String SUMMARY_TEXT = "Here's some summary text";
|
||||
|
||||
@Rule
|
||||
public final ActivityTestRule<AccessibilitySettingsActivity> mActivityRule =
|
||||
new ActivityTestRule<>(AccessibilitySettingsActivity.class, true);
|
||||
|
||||
private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
|
||||
@BeforeClass
|
||||
public static void oneTimeSetup() {
|
||||
if (Looper.myLooper() == null) {
|
||||
Looper.prepare();
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mInstrumentation.runOnMainSync(() -> {
|
||||
MyToggleFeaturePreferenceFragment fragment = new MyToggleFeaturePreferenceFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putString(AccessibilitySettings.EXTRA_SUMMARY, SUMMARY_TEXT);
|
||||
fragment.setArguments(args);
|
||||
new SubSettingLauncher(mActivityRule.getActivity())
|
||||
.setDestination(MyToggleFeaturePreferenceFragment.class.getName())
|
||||
.setArguments(args)
|
||||
.setSourceMetricsCategory(
|
||||
InstrumentedPreferenceFragment.METRICS_CATEGORY_UNKNOWN)
|
||||
.launch();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSummaryTestDisplayed() {
|
||||
onView(withText(SUMMARY_TEXT)).check(matches(isDisplayed()));
|
||||
}
|
||||
|
||||
public static class MyToggleFeaturePreferenceFragment extends ToggleFeaturePreferenceFragment {
|
||||
@Override
|
||||
protected void onPreferenceToggled(String preferenceKey, boolean enabled) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
int getUserShortcutTypes() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.accounts;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.support.test.uiautomator.UiDevice;
|
||||
import android.support.test.uiautomator.UiObject;
|
||||
import android.support.test.uiautomator.UiObjectNotFoundException;
|
||||
import android.support.test.uiautomator.UiScrollable;
|
||||
import android.support.test.uiautomator.UiSelector;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class AccountsSettingsTest {
|
||||
|
||||
private static final String ACCOUNTS = "Accounts";
|
||||
private static final String ACCOUNT_TYPE = "com.settingstest.account-prefs";
|
||||
private static final String PREF_TITLE = "Test preference for external account";
|
||||
|
||||
private UiDevice mDevice;
|
||||
private Context mContext;
|
||||
private String mTargetPackage;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
|
||||
mContext = InstrumentationRegistry.getTargetContext();
|
||||
mTargetPackage = mContext.getPackageName();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExternalAccountInfoExists() throws UiObjectNotFoundException {
|
||||
// add a test account
|
||||
final String testAccountName = "Test Account";
|
||||
final Account account = new Account(testAccountName, ACCOUNT_TYPE);
|
||||
final AccountManager accountManager = AccountManager.get(mContext);
|
||||
final boolean accountAdded =
|
||||
accountManager.addAccountExplicitly(account, null /* password */, null /* userdata */);
|
||||
assertThat(accountAdded).isTrue();
|
||||
|
||||
// launch Accounts Settings and select the test account
|
||||
launchAccountsSettings();
|
||||
mDevice.findObject(new UiSelector().text(testAccountName)).click();
|
||||
final UiObject testPreference = mDevice.findObject(new UiSelector().text(PREF_TITLE));
|
||||
// remove test account
|
||||
accountManager.removeAccountExplicitly(account);
|
||||
|
||||
assertThat(testPreference.exists()).isTrue();
|
||||
}
|
||||
|
||||
private void launchAccountsSettings() throws UiObjectNotFoundException {
|
||||
// launch settings
|
||||
Intent settingsIntent = new Intent(Intent.ACTION_MAIN)
|
||||
.addCategory(Intent.CATEGORY_LAUNCHER)
|
||||
.setPackage(mTargetPackage)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
mContext.startActivity(settingsIntent);
|
||||
// selects Accounts
|
||||
final UiScrollable settings = new UiScrollable(
|
||||
new UiSelector().packageName(mTargetPackage).scrollable(true));
|
||||
final String titleAccounts = ACCOUNTS;
|
||||
settings.scrollTextIntoView(titleAccounts);
|
||||
mDevice.findObject(new UiSelector().text(titleAccounts)).click();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.accounts;
|
||||
|
||||
import android.accounts.AbstractAccountAuthenticator;
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountAuthenticatorResponse;
|
||||
import android.accounts.AccountManager;
|
||||
import android.accounts.NetworkErrorException;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
|
||||
public class Authenticator extends AbstractAccountAuthenticator {
|
||||
|
||||
public Authenticator(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle editProperties(AccountAuthenticatorResponse r, String s) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle addAccount(AccountAuthenticatorResponse r, String s, String s2, String[] strings,
|
||||
Bundle bundle) throws NetworkErrorException {
|
||||
final Bundle result = new Bundle();
|
||||
result.putString(AccountManager.KEY_ACCOUNT_NAME, "Test Account");
|
||||
result.putString(AccountManager.KEY_ACCOUNT_TYPE, s);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle confirmCredentials(AccountAuthenticatorResponse r, Account account, Bundle bundle)
|
||||
throws NetworkErrorException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle getAuthToken(AccountAuthenticatorResponse r, Account account, String s,
|
||||
Bundle bundle) throws NetworkErrorException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthTokenLabel(String s) {
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle updateCredentials(AccountAuthenticatorResponse r, Account account, String s,
|
||||
Bundle bundle) throws NetworkErrorException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle hasFeatures(AccountAuthenticatorResponse r, Account account, String[] strings)
|
||||
throws NetworkErrorException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.accounts;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
|
||||
public class TestAuthService extends Service {
|
||||
|
||||
private Authenticator mAuthenticator;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
mAuthenticator = new Authenticator(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return mAuthenticator.getIBinder();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* 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.applications.manageapplications;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import android.content.pm.ApplicationInfo;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.settingslib.applications.AppUtils;
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
import com.android.settingslib.applications.ApplicationsState.AppFilter;
|
||||
import com.android.settingslib.applications.ApplicationsState.CompoundFilter;
|
||||
import com.android.settingslib.applications.instantapps.InstantAppDataProvider;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ManageApplicationsUnitTest {
|
||||
@Test
|
||||
public void getCompositeFilter_filtersVolumeForAudio() {
|
||||
AppFilter filter =
|
||||
ManageApplications.getCompositeFilter(
|
||||
ManageApplications.LIST_TYPE_STORAGE,
|
||||
ManageApplications.STORAGE_TYPE_MUSIC,
|
||||
"uuid");
|
||||
final ApplicationInfo info = new ApplicationInfo();
|
||||
info.volumeUuid = "uuid";
|
||||
info.category = ApplicationInfo.CATEGORY_AUDIO;
|
||||
final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
|
||||
appEntry.info = info;
|
||||
|
||||
assertThat(filter.filterApp(appEntry)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCompositeFilter_filtersVolumeForVideo() {
|
||||
AppFilter filter =
|
||||
ManageApplications.getCompositeFilter(
|
||||
ManageApplications.LIST_TYPE_MOVIES,
|
||||
ManageApplications.STORAGE_TYPE_DEFAULT,
|
||||
"uuid");
|
||||
final ApplicationInfo info = new ApplicationInfo();
|
||||
info.volumeUuid = "uuid";
|
||||
info.category = ApplicationInfo.CATEGORY_VIDEO;
|
||||
final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
|
||||
appEntry.info = info;
|
||||
|
||||
assertThat(filter.filterApp(appEntry)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCompositeFilter_filtersVolumeForGames() {
|
||||
ApplicationsState.AppFilter filter =
|
||||
ManageApplications.getCompositeFilter(
|
||||
ManageApplications.LIST_TYPE_GAMES,
|
||||
ManageApplications.STORAGE_TYPE_DEFAULT,
|
||||
"uuid");
|
||||
final ApplicationInfo info = new ApplicationInfo();
|
||||
info.volumeUuid = "uuid";
|
||||
info.category = ApplicationInfo.CATEGORY_GAME;
|
||||
final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
|
||||
appEntry.info = info;
|
||||
|
||||
assertThat(filter.filterApp(appEntry)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCompositeFilter_isEmptyNormally() {
|
||||
ApplicationsState.AppFilter filter =
|
||||
ManageApplications.getCompositeFilter(
|
||||
ManageApplications.LIST_TYPE_MAIN,
|
||||
ManageApplications.STORAGE_TYPE_DEFAULT,
|
||||
"uuid");
|
||||
assertThat(filter).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCompositeFilter_worksWithInstantApps() throws Exception {
|
||||
Field field = AppUtils.class.getDeclaredField("sInstantAppDataProvider");
|
||||
field.setAccessible(true);
|
||||
field.set(AppUtils.class, (InstantAppDataProvider) (i -> true));
|
||||
|
||||
AppFilter filter =
|
||||
ManageApplications.getCompositeFilter(
|
||||
ManageApplications.LIST_TYPE_STORAGE,
|
||||
ManageApplications.STORAGE_TYPE_MUSIC,
|
||||
"uuid");
|
||||
AppFilter composedFilter = new CompoundFilter(ApplicationsState.FILTER_INSTANT, filter);
|
||||
|
||||
final ApplicationInfo info = new ApplicationInfo();
|
||||
info.volumeUuid = "uuid";
|
||||
info.category = ApplicationInfo.CATEGORY_AUDIO;
|
||||
info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT;
|
||||
final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
|
||||
appEntry.info = info;
|
||||
|
||||
assertThat(composedFilter.filterApp(appEntry)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCompositeFilter_worksForLegacyPrivateSettings() throws Exception {
|
||||
ApplicationsState.AppFilter filter =
|
||||
ManageApplications.getCompositeFilter(
|
||||
ManageApplications.LIST_TYPE_STORAGE,
|
||||
ManageApplications.STORAGE_TYPE_LEGACY,
|
||||
"uuid");
|
||||
final ApplicationInfo info = new ApplicationInfo();
|
||||
info.volumeUuid = "uuid";
|
||||
info.category = ApplicationInfo.CATEGORY_GAME;
|
||||
final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
|
||||
appEntry.info = info;
|
||||
|
||||
assertThat(filter.filterApp(appEntry)).isTrue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.backup;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class BackupIntentTest {
|
||||
private static final String INTENT_PRIVACY_SETTINGS = "android.settings.PRIVACY_SETTINGS";
|
||||
private static final String BACKUP_SETTINGS_ACTIVITY =
|
||||
"com.android.settings.Settings$PrivacyDashboardActivity";
|
||||
|
||||
private Context mContext;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
mContext = instrumentation.getTargetContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrivacySettingsIntentResolvesToOnlyOneActivity(){
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
Intent intent = new Intent(INTENT_PRIVACY_SETTINGS);
|
||||
List<ResolveInfo> activities = pm.queryIntentActivities(intent, 0);
|
||||
assertThat(activities).isNotNull();
|
||||
assertThat(activities.size()).isEqualTo(1);
|
||||
assertThat(activities.get(0).activityInfo.getComponentName().getClassName()).
|
||||
isEqualTo(BACKUP_SETTINGS_ACTIVITY);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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.bluetooth;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
import android.text.InputFilter;
|
||||
import android.text.SpannableStringBuilder;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
public class Utf8ByteLengthFilterTest extends AndroidTestCase {
|
||||
|
||||
@SmallTest
|
||||
public void testFilter() {
|
||||
// Define the variables
|
||||
CharSequence source;
|
||||
SpannableStringBuilder dest;
|
||||
// Constructor to create a LengthFilter
|
||||
InputFilter lengthFilter = new Utf8ByteLengthFilter(10);
|
||||
InputFilter[] filters = {lengthFilter};
|
||||
|
||||
// filter() implicitly invoked. If the total length > filter length, the filter will
|
||||
// cut off the source CharSequence from beginning to fit the filter length.
|
||||
source = "abc";
|
||||
dest = new SpannableStringBuilder("abcdefgh");
|
||||
dest.setFilters(filters);
|
||||
|
||||
dest.insert(1, source);
|
||||
String expectedString1 = "aabbcdefgh";
|
||||
assertEquals(expectedString1, dest.toString());
|
||||
|
||||
dest.replace(5, 8, source);
|
||||
String expectedString2 = "aabbcabcgh";
|
||||
assertEquals(expectedString2, dest.toString());
|
||||
|
||||
dest.insert(2, source);
|
||||
assertEquals(expectedString2, dest.toString());
|
||||
|
||||
dest.delete(1, 3);
|
||||
String expectedString3 = "abcabcgh";
|
||||
assertEquals(expectedString3, dest.toString());
|
||||
|
||||
dest.append("12345");
|
||||
String expectedString4 = "abcabcgh12";
|
||||
assertEquals(expectedString4, dest.toString());
|
||||
|
||||
source = "\u60a8\u597d"; // 2 Chinese chars == 6 bytes in UTF-8
|
||||
dest.replace(8, 10, source);
|
||||
assertEquals(expectedString3, dest.toString());
|
||||
|
||||
dest.replace(0, 1, source);
|
||||
String expectedString5 = "\u60a8bcabcgh";
|
||||
assertEquals(expectedString5, dest.toString());
|
||||
|
||||
dest.replace(0, 4, source);
|
||||
String expectedString6 = "\u60a8\u597dbcgh";
|
||||
assertEquals(expectedString6, dest.toString());
|
||||
|
||||
source = "\u00a3\u00a5"; // 2 Latin-1 chars == 4 bytes in UTF-8
|
||||
dest.delete(2, 6);
|
||||
dest.insert(0, source);
|
||||
String expectedString7 = "\u00a3\u00a5\u60a8\u597d";
|
||||
assertEquals(expectedString7, dest.toString());
|
||||
|
||||
dest.replace(2, 3, source);
|
||||
String expectedString8 = "\u00a3\u00a5\u00a3\u597d";
|
||||
assertEquals(expectedString8, dest.toString());
|
||||
|
||||
dest.replace(3, 4, source);
|
||||
String expectedString9 = "\u00a3\u00a5\u00a3\u00a3\u00a5";
|
||||
assertEquals(expectedString9, dest.toString());
|
||||
|
||||
// filter() explicitly invoked
|
||||
dest = new SpannableStringBuilder("abcdefgh");
|
||||
CharSequence beforeFilterSource = "TestLengthFilter";
|
||||
String expectedAfterFilter = "TestLength";
|
||||
CharSequence actualAfterFilter = lengthFilter.filter(beforeFilterSource, 0,
|
||||
beforeFilterSource.length(), dest, 0, dest.length());
|
||||
assertEquals(expectedAfterFilter, actualAfterFilter);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.core;
|
||||
|
||||
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.support.test.uiautomator.By;
|
||||
import android.support.test.uiautomator.Direction;
|
||||
import android.support.test.uiautomator.UiDevice;
|
||||
import android.support.test.uiautomator.UiObject2;
|
||||
import android.support.test.uiautomator.Until;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.settings.development.featureflags.FeatureFlagsDashboard;
|
||||
import com.android.settingslib.core.instrumentation.Instrumentable;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class LifecycleEventHandlingTest {
|
||||
|
||||
private static final long TIMEOUT = 2000;
|
||||
|
||||
private Context mContext;
|
||||
private String mTargetPackage;
|
||||
private UiDevice mDevice;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
|
||||
mDevice.wakeUp();
|
||||
mDevice.executeShellCommand("wm dismiss-keyguard");
|
||||
mContext = InstrumentationRegistry.getTargetContext();
|
||||
mTargetPackage = mContext.getPackageName();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Presubmit
|
||||
@Ignore("b/133334887")
|
||||
public void launchDashboard_shouldSeeFooter() {
|
||||
new SubSettingLauncher(mContext)
|
||||
.setDestination(FeatureFlagsDashboard.class.getName())
|
||||
.setSourceMetricsCategory(Instrumentable.METRICS_CATEGORY_UNKNOWN)
|
||||
.addFlags(FLAG_ACTIVITY_NEW_TASK)
|
||||
.launch();
|
||||
|
||||
final String footerText = "Experimental";
|
||||
// Scroll to bottom
|
||||
final UiObject2 view = mDevice.wait(
|
||||
Until.findObject(By.res(mTargetPackage, "main_content")),
|
||||
TIMEOUT);
|
||||
view.scroll(Direction.DOWN, 100f);
|
||||
|
||||
assertThat(mDevice.wait(Until.findObject(By.text(footerText)), TIMEOUT))
|
||||
.isNotNull();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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.dashboard;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.view.View;
|
||||
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.hamcrest.TypeSafeMatcher;
|
||||
|
||||
/***
|
||||
* Matches on the first view with id if there are multiple views using the same Id.
|
||||
*/
|
||||
public class FirstIdViewMatcher {
|
||||
|
||||
public static Matcher<View> withFirstId(final int id) {
|
||||
return new TypeSafeMatcher<View>() {
|
||||
Resources resources = null;
|
||||
private boolean mMatched;
|
||||
|
||||
public void describeTo(Description description) {
|
||||
String idDescription = Integer.toString(id);
|
||||
if (resources != null) {
|
||||
try {
|
||||
idDescription = resources.getResourceName(id);
|
||||
} catch (Resources.NotFoundException e) {
|
||||
// No big deal, will just use the int value.
|
||||
idDescription = String.format("%s (resource name not found)", id);
|
||||
}
|
||||
}
|
||||
description.appendText("with first id: " + idDescription);
|
||||
}
|
||||
|
||||
public boolean matchesSafely(View view) {
|
||||
this.resources = view.getResources();
|
||||
if (mMatched) {
|
||||
return false;
|
||||
} else {
|
||||
mMatched = id == view.getId();
|
||||
return mMatched;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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.dashboard;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.espresso.matcher.ViewMatchers.Visibility;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class PreferenceThemeTest {
|
||||
|
||||
private Instrumentation mInstrumentation;
|
||||
private Context mTargetContext;
|
||||
private String mTargetPackage;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
mTargetContext = mInstrumentation.getTargetContext();
|
||||
mTargetPackage = mTargetContext.getPackageName();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startSetupWizardLockScreen_preferenceIconSpaceNotReserved() {
|
||||
launchSetupWizardLockScreen();
|
||||
// Icons should not be shown, and the frame should not occupy extra space.
|
||||
onView(allOf(withId(R.id.icon_frame), withEffectiveVisibility(Visibility.VISIBLE)))
|
||||
.check(doesNotExist());
|
||||
onView(withId(R.id.icon_container)).check(doesNotExist());
|
||||
}
|
||||
|
||||
private void launchSetupWizardLockScreen() {
|
||||
final Intent settingsIntent = new Intent("com.android.settings.SETUP_LOCK_SCREEN")
|
||||
.addCategory(Intent.CATEGORY_DEFAULT)
|
||||
.setPackage(mTargetPackage)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
InstrumentationRegistry.getInstrumentation().startActivitySync(settingsIntent);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.dashboard;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.MediumTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@MediumTest
|
||||
public class UiBlockerControllerTest {
|
||||
private static final long TIMEOUT = 600;
|
||||
private static final String KEY_1 = "key1";
|
||||
private static final String KEY_2 = "key2";
|
||||
|
||||
private Instrumentation mInstrumentation;
|
||||
private UiBlockerController mSyncableController;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
|
||||
mSyncableController = new UiBlockerController(Arrays.asList(KEY_1, KEY_2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void start_isSyncedReturnFalseUntilAllWorkDone() throws InterruptedException {
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
mSyncableController.start(() -> latch.countDown());
|
||||
|
||||
// Return false at first
|
||||
assertThat(mSyncableController.isBlockerFinished()).isFalse();
|
||||
|
||||
// Return false if only one job is done
|
||||
mSyncableController.countDown(KEY_1);
|
||||
assertThat(mSyncableController.isBlockerFinished()).isFalse();
|
||||
|
||||
// Return true if all jobs done
|
||||
mSyncableController.countDown(KEY_2);
|
||||
assertThat(latch.await(TIMEOUT, TimeUnit.MILLISECONDS)).isTrue();
|
||||
assertThat(mSyncableController.isBlockerFinished()).isTrue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.datetime.timezone.model;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class TimeZoneDataTest {
|
||||
|
||||
private TimeZoneData mTimeZoneData;
|
||||
@Before
|
||||
public void setUp() {
|
||||
mTimeZoneData = TimeZoneData.getInstance();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lookupCountryTimeZones_shouldReturnAtLeastOneTimeZoneInEveryRegion() {
|
||||
Set<String> regionIds = mTimeZoneData.getRegionIds();
|
||||
for (String regionId : regionIds) {
|
||||
FilteredCountryTimeZones countryTimeZones =
|
||||
mTimeZoneData.lookupCountryTimeZones(regionId);
|
||||
assertThat(countryTimeZones).isNotNull();
|
||||
assertThat(countryTimeZones.getTimeZoneIds().size()).isGreaterThan(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lookupCountryCodesForZoneId_shouldNotReturnHiddenZone() {
|
||||
/*
|
||||
Simferopol is filtered out for two reasons:
|
||||
1) because we specifically exclude it with the picker attribute, and
|
||||
2) because it's the same as Moscow after Oct 2014.
|
||||
*/
|
||||
assertThat(mTimeZoneData.lookupCountryCodesForZoneId("Europe/Simferopol").isEmpty())
|
||||
.isTrue();
|
||||
assertThat(mTimeZoneData.lookupCountryCodesForZoneId("Europe/London").isEmpty())
|
||||
.isFalse();
|
||||
assertThat(mTimeZoneData.lookupCountryCodesForZoneId("America/Los_Angeles").isEmpty())
|
||||
.isFalse();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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.display;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.settings.Settings.NightDisplaySettingsActivity;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class NightDisplaySettingsActivityTest {
|
||||
|
||||
private Context mTargetContext;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
mTargetContext = instrumentation.getTargetContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nightDisplaySettingsIntent_resolvesCorrectly() {
|
||||
final boolean nightDisplayAvailable = mTargetContext.getResources().getBoolean(
|
||||
com.android.internal.R.bool.config_nightDisplayAvailable);
|
||||
final PackageManager pm = mTargetContext.getPackageManager();
|
||||
final Intent intent = new Intent(Settings.ACTION_NIGHT_DISPLAY_SETTINGS);
|
||||
final ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
|
||||
|
||||
if (nightDisplayAvailable) {
|
||||
Assert.assertNotNull("No activity for " + Settings.ACTION_NIGHT_DISPLAY_SETTINGS, ri);
|
||||
Assert.assertEquals(mTargetContext.getPackageName(), ri.activityInfo.packageName);
|
||||
Assert.assertEquals(NightDisplaySettingsActivity.class.getName(),
|
||||
ri.activityInfo.name);
|
||||
} else {
|
||||
Assert.assertNull("Should have no activity for "
|
||||
+ Settings.ACTION_NIGHT_DISPLAY_SETTINGS, ri);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* 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.display;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.om.IOverlayManager;
|
||||
import android.content.om.OverlayInfo;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ThemePreferenceControllerTest {
|
||||
|
||||
private IOverlayManager mMockOverlayManager;
|
||||
private ContextWrapper mContext;
|
||||
private ThemePreferenceController mPreferenceController;
|
||||
private PackageManager mMockPackageManager;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
mMockOverlayManager = mock(IOverlayManager.class);
|
||||
mMockPackageManager = mock(PackageManager.class);
|
||||
mContext = new ContextWrapper(InstrumentationRegistry.getTargetContext()) {
|
||||
@Override
|
||||
public PackageManager getPackageManager() {
|
||||
return mMockPackageManager;
|
||||
}
|
||||
};
|
||||
mPreferenceController = new ThemePreferenceController(mContext, mMockOverlayManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateState() throws Exception {
|
||||
OverlayInfo info1 = new OverlayInfo("com.android.Theme1", "android", "",
|
||||
OverlayInfo.CATEGORY_THEME, "", OverlayInfo.STATE_ENABLED, 0, 0, true);
|
||||
OverlayInfo info2 = new OverlayInfo("com.android.Theme2", "android", "",
|
||||
OverlayInfo.CATEGORY_THEME, "", 0, 0, 0, true);
|
||||
when(mMockPackageManager.getApplicationInfo(any(), anyInt())).thenAnswer(inv -> {
|
||||
ApplicationInfo info = mock(ApplicationInfo.class);
|
||||
if ("com.android.Theme1".equals(inv.getArguments()[0])) {
|
||||
when(info.loadLabel(any())).thenReturn("Theme1");
|
||||
} else {
|
||||
when(info.loadLabel(any())).thenReturn("Theme2");
|
||||
}
|
||||
return info;
|
||||
});
|
||||
when(mMockPackageManager.getPackageInfo(anyString(), anyInt())).thenReturn(
|
||||
new PackageInfo());
|
||||
when(mMockOverlayManager.getOverlayInfosForTarget(any(), anyInt())).thenReturn(
|
||||
list(info1, info2));
|
||||
ListPreference pref = mock(ListPreference.class);
|
||||
mPreferenceController.updateState(pref);
|
||||
ArgumentCaptor<String[]> arg = ArgumentCaptor.forClass(String[].class);
|
||||
verify(pref).setEntries(arg.capture());
|
||||
|
||||
|
||||
CharSequence[] entries = arg.getValue();
|
||||
assertThat(entries).asList().containsExactly("Theme1", "Theme2");
|
||||
|
||||
verify(pref).setEntryValues(arg.capture());
|
||||
CharSequence[] entryValues = arg.getValue();
|
||||
assertThat(entryValues).asList().containsExactly(
|
||||
"com.android.Theme1", "com.android.Theme2");
|
||||
|
||||
verify(pref).setValue(eq("com.android.Theme1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateState_withStaticOverlay() throws Exception {
|
||||
OverlayInfo info1 = new OverlayInfo("com.android.Theme1", "android", "",
|
||||
OverlayInfo.CATEGORY_THEME, "", OverlayInfo.STATE_ENABLED, 0, 0, true);
|
||||
OverlayInfo info2 = new OverlayInfo("com.android.Theme2", "android", "",
|
||||
OverlayInfo.CATEGORY_THEME, "", OverlayInfo.STATE_ENABLED, 0, 0, true);
|
||||
when(mMockPackageManager.getApplicationInfo(any(), anyInt())).thenAnswer(inv -> {
|
||||
ApplicationInfo info = mock(ApplicationInfo.class);
|
||||
if ("com.android.Theme1".equals(inv.getArguments()[0])) {
|
||||
when(info.loadLabel(any())).thenReturn("Theme1");
|
||||
} else {
|
||||
when(info.loadLabel(any())).thenReturn("Theme2");
|
||||
}
|
||||
return info;
|
||||
});
|
||||
PackageInfo pi = mock(PackageInfo.class);
|
||||
when(pi.isStaticOverlayPackage()).thenReturn(true);
|
||||
when(mMockPackageManager.getPackageInfo(eq("com.android.Theme1"), anyInt())).thenReturn(pi);
|
||||
when(mMockPackageManager.getPackageInfo(eq("com.android.Theme2"), anyInt())).thenReturn(
|
||||
new PackageInfo());
|
||||
when(mMockOverlayManager.getOverlayInfosForTarget(any(), anyInt())).thenReturn(
|
||||
list(info1, info2));
|
||||
ListPreference pref = mock(ListPreference.class);
|
||||
mPreferenceController.updateState(pref);
|
||||
ArgumentCaptor<String[]> arg = ArgumentCaptor.forClass(String[].class);
|
||||
verify(pref).setEntries(arg.capture());
|
||||
|
||||
|
||||
CharSequence[] entries = arg.getValue();
|
||||
assertThat(entries).asList().containsExactly("Theme2");
|
||||
|
||||
verify(pref).setEntryValues(arg.capture());
|
||||
CharSequence[] entryValues = arg.getValue();
|
||||
assertThat(entryValues).asList().containsExactly("com.android.Theme2");
|
||||
|
||||
verify(pref).setValue(eq("com.android.Theme2"));
|
||||
}
|
||||
|
||||
private ArrayList<OverlayInfo> list(OverlayInfo... infos) {
|
||||
ArrayList<OverlayInfo> list = new ArrayList<>();
|
||||
for (OverlayInfo info : infos) {
|
||||
list.add(info);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.homepage.contextualcards;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
import androidx.slice.Slice;
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.settings.slices.CustomSliceRegistry;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ContextualCardLoaderTest {
|
||||
|
||||
private static final Uri TEST_URI = Uri.parse("content://test/test");
|
||||
|
||||
private Context mContext;
|
||||
private ContextualCardLoader mContextualCardLoader;
|
||||
private EligibleCardChecker mEligibleCardChecker;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = InstrumentationRegistry.getTargetContext();
|
||||
mContextualCardLoader = new ContextualCardLoader(mContext);
|
||||
mEligibleCardChecker = new EligibleCardChecker(mContext, getContextualCard(TEST_URI));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filterEligibleCards_twoInvalidCards_shouldReturnOneCard() {
|
||||
final String sliceUri1 = "content://com.android.settings.slices/action/flashlight"; //valid
|
||||
final String sliceUri2 = "content://com.android.settings.test.slices/action/flashlight";
|
||||
final String sliceUri3 = "cotent://com.android.settings.slices/action/flashlight";
|
||||
|
||||
final List<ContextualCard> cards = new ArrayList<>();
|
||||
cards.add(getContextualCard(Uri.parse(sliceUri1)));
|
||||
cards.add(getContextualCard(Uri.parse(sliceUri2)));
|
||||
cards.add(getContextualCard(Uri.parse(sliceUri3)));
|
||||
|
||||
final List<ContextualCard> result = mContextualCardLoader.filterEligibleCards(cards);
|
||||
|
||||
assertThat(result).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindSlice_flashlightUri_shouldReturnFlashlightSlice() {
|
||||
final Slice loadedSlice =
|
||||
mEligibleCardChecker.bindSlice(CustomSliceRegistry.FLASHLIGHT_SLICE_URI);
|
||||
|
||||
assertThat(loadedSlice.getUri()).isEqualTo(CustomSliceRegistry.FLASHLIGHT_SLICE_URI);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindSlice_noProvider_shouldReturnNull() {
|
||||
final String sliceUri = "content://com.android.settings.test.slices/action/flashlight";
|
||||
|
||||
final Slice loadedSlice = mEligibleCardChecker.bindSlice(Uri.parse(sliceUri));
|
||||
|
||||
assertThat(loadedSlice).isNull();
|
||||
}
|
||||
|
||||
private ContextualCard getContextualCard(Uri sliceUri) {
|
||||
return new ContextualCard.Builder()
|
||||
.setName("test_card")
|
||||
.setRankingScore(0.5f)
|
||||
.setCardType(ContextualCard.CardType.SLICE)
|
||||
.setSliceUri(sliceUri)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.notification;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.provider.Settings;
|
||||
import android.support.test.uiautomator.UiDevice;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class AppBubbleNotificationSettingsTest {
|
||||
|
||||
private static final String WM_DISMISS_KEYGUARD_COMMAND = "wm dismiss-keyguard";
|
||||
|
||||
private UiDevice mUiDevice;
|
||||
private Context mTargetContext;
|
||||
private Instrumentation mInstrumentation;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
mTargetContext = mInstrumentation.getTargetContext();
|
||||
|
||||
mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
|
||||
mUiDevice.wakeUp();
|
||||
mUiDevice.executeShellCommand(WM_DISMISS_KEYGUARD_COMMAND);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launchBubbleNotificationSetting_shouldNotCrash() {
|
||||
final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_BUBBLE_SETTINGS)
|
||||
.putExtra(Settings.EXTRA_APP_PACKAGE, mTargetContext.getPackageName())
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
|
||||
mInstrumentation.startActivitySync(intent);
|
||||
|
||||
CharSequence name = mTargetContext.getApplicationInfo().loadLabel(
|
||||
mTargetContext.getPackageManager());
|
||||
onView(allOf(withText(name.toString()))).check(matches(isDisplayed()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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.notification;
|
||||
|
||||
import static android.app.NotificationManager.IMPORTANCE_MIN;
|
||||
import static android.app.NotificationManager.IMPORTANCE_NONE;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import android.app.INotificationManager;
|
||||
import android.app.Instrumentation;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Process;
|
||||
import android.os.ServiceManager;
|
||||
import android.provider.Settings;
|
||||
import android.support.test.uiautomator.UiDevice;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class ChannelNotificationSettingsTest {
|
||||
private static final String WM_DISMISS_KEYGUARD_COMMAND = "wm dismiss-keyguard";
|
||||
|
||||
private UiDevice mUiDevice;
|
||||
private Context mTargetContext;
|
||||
private Instrumentation mInstrumentation;
|
||||
private NotificationChannel mNotificationChannel;
|
||||
private NotificationManager mNm;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
mTargetContext = mInstrumentation.getTargetContext();
|
||||
|
||||
mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
|
||||
mUiDevice.wakeUp();
|
||||
mUiDevice.executeShellCommand(WM_DISMISS_KEYGUARD_COMMAND);
|
||||
|
||||
mNm = (NotificationManager) mTargetContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
mNotificationChannel = new NotificationChannel(this.getClass().getName(),
|
||||
this.getClass().getName(), IMPORTANCE_MIN);
|
||||
mNm.createNotificationChannel(mNotificationChannel);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launchNotificationSetting_shouldNotCrash() {
|
||||
final Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
|
||||
.putExtra(Settings.EXTRA_APP_PACKAGE, mTargetContext.getPackageName())
|
||||
.putExtra(Settings.EXTRA_CHANNEL_ID, mNotificationChannel.getId())
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
mInstrumentation.startActivitySync(intent);
|
||||
|
||||
onView(allOf(withText(mNotificationChannel.getName().toString()))).check(
|
||||
matches(isDisplayed()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launchNotificationSettings_blockedChannel() throws Exception {
|
||||
NotificationChannel blocked =
|
||||
new NotificationChannel("blocked", "blocked", IMPORTANCE_NONE);
|
||||
mNm.createNotificationChannel(blocked);
|
||||
|
||||
INotificationManager sINM = INotificationManager.Stub.asInterface(
|
||||
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
|
||||
blocked.setImportance(IMPORTANCE_NONE);
|
||||
sINM.updateNotificationChannelForPackage(
|
||||
mTargetContext.getPackageName(), Process.myUid(), blocked);
|
||||
|
||||
final Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
|
||||
.putExtra(Settings.EXTRA_APP_PACKAGE, mTargetContext.getPackageName())
|
||||
.putExtra(Settings.EXTRA_CHANNEL_ID, blocked.getId())
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
mInstrumentation.startActivitySync(intent);
|
||||
|
||||
onView(allOf(withText("At your request, Android is blocking this category of notifications"
|
||||
+ " from appearing on this device"))).check(matches(isDisplayed()));
|
||||
|
||||
try {
|
||||
onView(allOf(withText("On the lock screen"))).check(matches(isDisplayed()));
|
||||
fail("settings appearing for blocked channel");
|
||||
} catch (Exception e) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
# Default reviewers for this and subdirectories.
|
||||
asc@google.com
|
||||
dsandler@android.com
|
||||
juliacr@google.com
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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.password;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.action.ViewActions.click;
|
||||
import static androidx.test.espresso.action.ViewActions.pressKey;
|
||||
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isEnabled;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.espresso.action.ViewActions;
|
||||
import androidx.test.espresso.matcher.ViewMatchers;
|
||||
import androidx.test.filters.MediumTest;
|
||||
import androidx.test.rule.ActivityTestRule;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
import com.google.android.setupcompat.PartnerCustomizationLayout;
|
||||
import com.google.android.setupcompat.template.FooterBarMixin;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@MediumTest
|
||||
public class SetupChooseLockPasswordAppTest {
|
||||
|
||||
private Context mContext;
|
||||
|
||||
@Rule
|
||||
public ActivityTestRule<SetupChooseLockPassword> mActivityTestRule =
|
||||
new ActivityTestRule<>(
|
||||
SetupChooseLockPassword.class,
|
||||
true /* enable touch at launch */,
|
||||
false /* don't launch at every test */);
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = InstrumentationRegistry.getTargetContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSkipDialogIsShown() throws Throwable {
|
||||
SetupChooseLockPassword activity = mActivityTestRule.launchActivity(null);
|
||||
PartnerCustomizationLayout layout = activity.findViewById(R.id.setup_wizard_layout);
|
||||
final Button skipOrClearButton =
|
||||
layout.getMixin(FooterBarMixin.class).getSecondaryButtonView();
|
||||
|
||||
assertThat(skipOrClearButton.getText()).isEqualTo(mContext.getString(R.string.skip_label));
|
||||
assertThat(skipOrClearButton.getVisibility()).isEqualTo(View.VISIBLE);
|
||||
skipOrClearButton.performClick();
|
||||
assertWithMessage("Is finishing").that(activity.isFinishing()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clearIsNotShown_when_activityLaunchedInitially() {
|
||||
SetupChooseLockPassword activity = mActivityTestRule.launchActivity(null);
|
||||
PartnerCustomizationLayout layout = activity.findViewById(R.id.setup_wizard_layout);
|
||||
assertThat(layout.getMixin(FooterBarMixin.class).getSecondaryButtonView().getText())
|
||||
.isEqualTo(mContext.getString(R.string.lockpassword_clear_label));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clearIsNotShown_when_nothingEntered() throws Throwable {
|
||||
SetupChooseLockPassword activity = mActivityTestRule.launchActivity(null);
|
||||
PartnerCustomizationLayout layout = activity.findViewById(R.id.setup_wizard_layout);
|
||||
onView(withId(R.id.password_entry)).perform(ViewActions.typeText("1234"))
|
||||
.perform(pressKey(KeyEvent.KEYCODE_ENTER));
|
||||
assertThat(
|
||||
layout.getMixin(FooterBarMixin.class).getSecondaryButtonView().getVisibility())
|
||||
.isEqualTo(View.GONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clearIsShown_when_somethingEnteredToConfirm() {
|
||||
SetupChooseLockPassword activity = mActivityTestRule.launchActivity(null);
|
||||
PartnerCustomizationLayout layout = activity.findViewById(R.id.setup_wizard_layout);
|
||||
onView(withId(R.id.password_entry)).perform(ViewActions.typeText("1234"))
|
||||
.perform(pressKey(KeyEvent.KEYCODE_ENTER));
|
||||
mActivityTestRule.launchActivity(null);
|
||||
onView(withId(R.id.password_entry)).perform(ViewActions.typeText("1234"))
|
||||
.perform(pressKey(KeyEvent.KEYCODE_ENTER))
|
||||
.perform(ViewActions.typeText("1"));
|
||||
// clear should be present if text field contains content
|
||||
assertThat(
|
||||
layout.getMixin(FooterBarMixin.class).getSecondaryButtonView().getVisibility())
|
||||
.isEqualTo(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.print;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.CancellationSignal;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.print.PageRange;
|
||||
import android.print.PrintAttributes;
|
||||
import android.print.PrintDocumentAdapter;
|
||||
import android.print.PrintDocumentInfo;
|
||||
import android.print.PrintJob;
|
||||
import android.print.PrintManager;
|
||||
import android.support.test.uiautomator.By;
|
||||
import android.support.test.uiautomator.UiDevice;
|
||||
import android.support.test.uiautomator.UiObject2;
|
||||
import android.support.test.uiautomator.Until;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.LargeTest;
|
||||
import androidx.test.rule.ActivityTestRule;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.settings.Settings;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.UUID;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class PrintJobSettingsActivityTest {
|
||||
private static final String EXTRA_PRINT_JOB_ID = "EXTRA_PRINT_JOB_ID";
|
||||
private static final String LOG_TAG = PrintJobSettingsActivityTest.class.getSimpleName();
|
||||
|
||||
// Any activity is fine
|
||||
@Rule
|
||||
public final ActivityTestRule<Settings.PrintSettingsActivity> mActivityRule =
|
||||
new ActivityTestRule<>(Settings.PrintSettingsActivity.class, true);
|
||||
|
||||
public static void runShellCommand(@NonNull String cmd) throws IOException {
|
||||
ParcelFileDescriptor stdOut =
|
||||
InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
|
||||
cmd);
|
||||
|
||||
try (FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(stdOut)) {
|
||||
byte[] buf = new byte[512];
|
||||
while (fis.read(buf) != -1) {
|
||||
// keep reading
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void requirePrintFeature() {
|
||||
assumeTrue(InstrumentationRegistry.getTargetContext().getPackageManager().hasSystemFeature(
|
||||
PackageManager.FEATURE_PRINTING));
|
||||
}
|
||||
|
||||
@Before
|
||||
public void wakeUpScreen() throws Exception {
|
||||
runShellCommand("input keyevent KEYCODE_WAKEUP");
|
||||
}
|
||||
|
||||
@Test
|
||||
@LargeTest
|
||||
public void viewPrintJobSettings() throws Exception {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
Object isWriteCalled = new Object();
|
||||
|
||||
// Create adapter that is good enough to start a print preview
|
||||
PrintDocumentAdapter adapter = new PrintDocumentAdapter() {
|
||||
@Override
|
||||
public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
|
||||
CancellationSignal cancellationSignal,
|
||||
LayoutResultCallback callback, Bundle extras) {
|
||||
callback.onLayoutFinished(new PrintDocumentInfo.Builder(uuid.toString()).build(),
|
||||
true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWrite(PageRange[] pages, ParcelFileDescriptor destination,
|
||||
CancellationSignal cancellationSignal,
|
||||
WriteResultCallback callback) {
|
||||
synchronized (isWriteCalled) {
|
||||
isWriteCalled.notify();
|
||||
}
|
||||
callback.onWriteFailed(null);
|
||||
}
|
||||
};
|
||||
|
||||
Activity activity = mActivityRule.getActivity();
|
||||
PrintManager pm = mActivityRule.getActivity().getSystemService(PrintManager.class);
|
||||
|
||||
// Start printing
|
||||
PrintJob printJob = pm.print(uuid.toString(), adapter, null);
|
||||
|
||||
// Wait until print preview is up
|
||||
synchronized (isWriteCalled) {
|
||||
isWriteCalled.wait();
|
||||
}
|
||||
|
||||
// Start print job settings
|
||||
Intent intent = new Intent(android.provider.Settings.ACTION_PRINT_SETTINGS);
|
||||
intent.putExtra(EXTRA_PRINT_JOB_ID, printJob.getId().flattenToString());
|
||||
intent.setData(Uri.fromParts("printjob", printJob.getId().flattenToString(), null));
|
||||
activity.startActivity(intent);
|
||||
|
||||
UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
|
||||
UiObject2 printPrefTitle = uiDevice.wait(Until.findObject(By.text("Configuring "
|
||||
+ uuid.toString())), 5000);
|
||||
assertNotNull(printPrefTitle);
|
||||
|
||||
Log.i(LOG_TAG, "Found " + printPrefTitle.getText());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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.search;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.provider.SearchIndexablesContract;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class SearchIndexablesContractTest {
|
||||
|
||||
@Test
|
||||
public void testRawColumns_matchContractIndexing() {
|
||||
assertThat(SearchIndexablesContract.RawData.COLUMN_RANK)
|
||||
.isEqualTo(SearchIndexablesContract.INDEXABLES_RAW_COLUMNS[0]);
|
||||
assertThat(SearchIndexablesContract.RawData.COLUMN_TITLE)
|
||||
.isEqualTo(SearchIndexablesContract.INDEXABLES_RAW_COLUMNS[1]);
|
||||
assertThat(SearchIndexablesContract.RawData.COLUMN_SUMMARY_ON)
|
||||
.isEqualTo(SearchIndexablesContract.INDEXABLES_RAW_COLUMNS[2]);
|
||||
assertThat(SearchIndexablesContract.RawData.COLUMN_SUMMARY_OFF)
|
||||
.isEqualTo(SearchIndexablesContract.INDEXABLES_RAW_COLUMNS[3]);
|
||||
assertThat(SearchIndexablesContract.RawData.COLUMN_ENTRIES)
|
||||
.isEqualTo(SearchIndexablesContract.INDEXABLES_RAW_COLUMNS[4]);
|
||||
assertThat(SearchIndexablesContract.RawData.COLUMN_KEYWORDS)
|
||||
.isEqualTo(SearchIndexablesContract.INDEXABLES_RAW_COLUMNS[5]);
|
||||
assertThat(SearchIndexablesContract.RawData.COLUMN_SCREEN_TITLE)
|
||||
.isEqualTo(SearchIndexablesContract.INDEXABLES_RAW_COLUMNS[6]);
|
||||
assertThat(SearchIndexablesContract.RawData.COLUMN_CLASS_NAME)
|
||||
.isEqualTo(SearchIndexablesContract.INDEXABLES_RAW_COLUMNS[7]);
|
||||
assertThat(SearchIndexablesContract.RawData.COLUMN_ICON_RESID)
|
||||
.isEqualTo(SearchIndexablesContract.INDEXABLES_RAW_COLUMNS[8]);
|
||||
assertThat(SearchIndexablesContract.RawData.COLUMN_INTENT_ACTION)
|
||||
.isEqualTo(SearchIndexablesContract.INDEXABLES_RAW_COLUMNS[9]);
|
||||
assertThat(SearchIndexablesContract.RawData.COLUMN_INTENT_TARGET_PACKAGE)
|
||||
.isEqualTo(SearchIndexablesContract.INDEXABLES_RAW_COLUMNS[10]);
|
||||
assertThat(SearchIndexablesContract.RawData.COLUMN_INTENT_TARGET_CLASS)
|
||||
.isEqualTo(SearchIndexablesContract.INDEXABLES_RAW_COLUMNS[11]);
|
||||
assertThat(SearchIndexablesContract.RawData.COLUMN_KEY)
|
||||
.isEqualTo(SearchIndexablesContract.INDEXABLES_RAW_COLUMNS[12]);
|
||||
assertThat(SearchIndexablesContract.RawData.COLUMN_USER_ID)
|
||||
.isEqualTo(SearchIndexablesContract.INDEXABLES_RAW_COLUMNS[13]);
|
||||
assertThat(SearchIndexablesContract.RawData.PAYLOAD_TYPE)
|
||||
.isEqualTo(SearchIndexablesContract.INDEXABLES_RAW_COLUMNS[14]);
|
||||
assertThat(SearchIndexablesContract.RawData.PAYLOAD)
|
||||
.isEqualTo(SearchIndexablesContract.INDEXABLES_RAW_COLUMNS[15]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.search;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class SearchResultTrampolineTest {
|
||||
|
||||
private Context mContext;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = InstrumentationRegistry.getTargetContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canLaunchSettingsTrampolineWithIntentAction() {
|
||||
final PackageManager pm = mContext.getPackageManager();
|
||||
final ResolveInfo info =
|
||||
pm.resolveActivity(new Intent("com.android.settings.SEARCH_RESULT_TRAMPOLINE"), 0);
|
||||
|
||||
assertThat(info.activityInfo.name)
|
||||
.isEqualTo(SearchResultTrampoline.class.getName());
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.search;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.provider.SearchIndexablesContract;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class SettingsSearchIndexablesProviderTest {
|
||||
|
||||
private Context mContext;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = InstrumentationRegistry.getTargetContext();
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanUp() {
|
||||
System.clearProperty(SettingsSearchIndexablesProvider.SYSPROP_CRASH_ON_ERROR);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSiteMapPairsFetched() {
|
||||
final Uri uri = Uri.parse("content://" + mContext.getPackageName() + "/" +
|
||||
SearchIndexablesContract.SITE_MAP_PAIRS_PATH);
|
||||
final Cursor cursor = mContext.getContentResolver().query(uri, null, null, null, null);
|
||||
|
||||
final int size = cursor.getCount();
|
||||
assertThat(size).isGreaterThan(0);
|
||||
while (cursor.moveToNext()) {
|
||||
assertThat(cursor.getString(cursor.getColumnIndexOrThrow(
|
||||
SearchIndexablesContract.SiteMapColumns.PARENT_CLASS)))
|
||||
.isNotEmpty();
|
||||
assertThat(cursor.getString(cursor.getColumnIndexOrThrow(
|
||||
SearchIndexablesContract.SiteMapColumns.CHILD_CLASS)))
|
||||
.isNotEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* All {@link Indexable.SearchIndexProvider} should collect a list of non-indexable keys
|
||||
* without crashing. This test enables crashing of individual providers in the indexing pipeline
|
||||
* and checks that there are no crashes.
|
||||
*/
|
||||
@Test
|
||||
@Presubmit
|
||||
public void nonIndexableKeys_shouldNotCrash() {
|
||||
// Allow crashes in the indexing pipeline.
|
||||
System.setProperty(SettingsSearchIndexablesProvider.SYSPROP_CRASH_ON_ERROR,
|
||||
"enabled");
|
||||
|
||||
final Uri uri = Uri.parse("content://" + mContext.getPackageName() + "/" +
|
||||
SearchIndexablesContract.NON_INDEXABLES_KEYS_PATH);
|
||||
mContext.getContentResolver().query(uri, null, null, null, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
include /src/com/android/settings/sim/OWNERS
|
||||
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright (C) 2009 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.tests;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.ListView;
|
||||
|
||||
import com.android.settings.tests.unit.R;
|
||||
|
||||
public class BluetoothRequestPermissionTest extends Activity {
|
||||
private static final String TAG = "BluetoothRequestPermissionTest";
|
||||
BluetoothAdapter mAdapter;
|
||||
private ArrayAdapter<String> mMsgAdapter;
|
||||
|
||||
// Discoverable button alternates between 20 second timeout and no timeout.
|
||||
private boolean mDiscoveryWithTimeout = true;
|
||||
|
||||
private class BtOnClickListener implements OnClickListener {
|
||||
final boolean mEnableOnly; // enable or enable + discoverable
|
||||
|
||||
public BtOnClickListener(boolean enableOnly) {
|
||||
mEnableOnly = enableOnly;
|
||||
}
|
||||
|
||||
public void onClick(View v) {
|
||||
requestPermission(mEnableOnly);
|
||||
}
|
||||
}
|
||||
|
||||
private class BtScanOnClickListener implements OnClickListener {
|
||||
public void onClick(View v) {
|
||||
Button scanButton = (Button) v;
|
||||
if (mAdapter.isDiscovering()) {
|
||||
mAdapter.cancelDiscovery();
|
||||
scanButton.setText(R.string.start_scan);
|
||||
} else {
|
||||
mAdapter.startDiscovery();
|
||||
scanButton.setText(R.string.stop_scan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
setContentView(R.layout.bluetooth_request_permission_test);
|
||||
mAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||
|
||||
Button enable = (Button) findViewById(R.id.enable);
|
||||
enable.setOnClickListener(new BtOnClickListener(true /* enable */));
|
||||
|
||||
Button discoverable = (Button) findViewById(R.id.discoverable);
|
||||
discoverable.setOnClickListener(new BtOnClickListener(false /* enable & discoverable */));
|
||||
|
||||
Button scanButton = (Button) findViewById(R.id.scan);
|
||||
scanButton.setOnClickListener(new BtScanOnClickListener());
|
||||
if (mAdapter.isDiscovering()) {
|
||||
scanButton.setText(R.string.stop_scan);
|
||||
} else {
|
||||
scanButton.setText(R.string.start_scan);
|
||||
}
|
||||
|
||||
mMsgAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1);
|
||||
|
||||
ListView listView = (ListView) findViewById(R.id.msg_container);
|
||||
listView.setAdapter(mMsgAdapter);
|
||||
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
|
||||
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
|
||||
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
|
||||
filter.addAction(BluetoothDevice.ACTION_FOUND);
|
||||
registerReceiver(mReceiver, filter);
|
||||
addMsg("Initialized");
|
||||
}
|
||||
|
||||
void requestPermission(boolean enableOnly) {
|
||||
Intent i = new Intent();
|
||||
if (enableOnly) {
|
||||
addMsg("Starting activity to enable bt");
|
||||
i.setAction(BluetoothAdapter.ACTION_REQUEST_ENABLE);
|
||||
} else {
|
||||
addMsg("Starting activity to enable bt + discovery");
|
||||
i.setAction(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
|
||||
// Discoverability duration toggles between 20 seconds and no timeout.
|
||||
int timeout = (mDiscoveryWithTimeout ? 20 : 0);
|
||||
i.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, timeout);
|
||||
mDiscoveryWithTimeout = !mDiscoveryWithTimeout;
|
||||
}
|
||||
startActivityForResult(i, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (requestCode != 1) {
|
||||
Log.e(TAG, "Unexpected onActivityResult " + requestCode + " " + resultCode);
|
||||
return;
|
||||
}
|
||||
|
||||
if (resultCode == Activity.RESULT_CANCELED) {
|
||||
addMsg("Result = RESULT_CANCELED");
|
||||
} else if (resultCode == Activity.RESULT_OK) {
|
||||
addMsg("Result = RESULT_OK (not expected for discovery)");
|
||||
} else {
|
||||
addMsg("Result = " + resultCode);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
unregisterReceiver(mReceiver);
|
||||
}
|
||||
|
||||
private void addMsg(String msg) {
|
||||
mMsgAdapter.add(msg);
|
||||
Log.d(TAG, "msg");
|
||||
}
|
||||
|
||||
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent == null)
|
||||
return;
|
||||
String action = intent.getAction();
|
||||
if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
|
||||
String stateStr = "???";
|
||||
switch (intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothDevice.ERROR)) {
|
||||
case BluetoothAdapter.STATE_OFF:
|
||||
stateStr = "off";
|
||||
break;
|
||||
case BluetoothAdapter.STATE_TURNING_ON:
|
||||
stateStr = "turning on";
|
||||
break;
|
||||
case BluetoothAdapter.STATE_ON:
|
||||
stateStr = "on";
|
||||
break;
|
||||
case BluetoothAdapter.STATE_TURNING_OFF:
|
||||
stateStr = "turning off";
|
||||
break;
|
||||
}
|
||||
addMsg("Bluetooth status = " + stateStr);
|
||||
} else if (action.equals(BluetoothDevice.ACTION_FOUND)) {
|
||||
String name = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
|
||||
addMsg("Found: " + name);
|
||||
} else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_STARTED)) {
|
||||
addMsg("Scan started...");
|
||||
} else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
|
||||
addMsg("Scan ended");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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.tests;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.android.settings.tests.unit.R;
|
||||
|
||||
public class Manufacturer extends Activity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.manufacturer_main);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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.tests;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.android.settings.tests.unit.R;
|
||||
|
||||
public class Operator extends Activity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.operator_main);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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.utils;
|
||||
|
||||
import static com.android.settings.utils.FileSizeFormatter.GIGABYTE_IN_BYTES;
|
||||
import static com.android.settings.utils.FileSizeFormatter.MEGABYTE_IN_BYTES;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.icu.util.MeasureUnit;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class FileSizeFormatterTest {
|
||||
private Context mContext;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mContext = InstrumentationRegistry.getTargetContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void formatFileSize_zero() throws Exception {
|
||||
assertThat(
|
||||
FileSizeFormatter.formatFileSize(
|
||||
mContext,
|
||||
0 /* size */,
|
||||
MeasureUnit.GIGABYTE,
|
||||
GIGABYTE_IN_BYTES))
|
||||
.isEqualTo("0.00 GB");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void formatFileSize_smallSize() throws Exception {
|
||||
assertThat(
|
||||
FileSizeFormatter.formatFileSize(
|
||||
mContext,
|
||||
MEGABYTE_IN_BYTES * 11 /* size */,
|
||||
MeasureUnit.GIGABYTE,
|
||||
GIGABYTE_IN_BYTES))
|
||||
.isEqualTo("0.01 GB");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void formatFileSize_lessThanOneSize() throws Exception {
|
||||
assertThat(
|
||||
FileSizeFormatter.formatFileSize(
|
||||
mContext,
|
||||
MEGABYTE_IN_BYTES * 155 /* size */,
|
||||
MeasureUnit.GIGABYTE,
|
||||
GIGABYTE_IN_BYTES))
|
||||
.isEqualTo("0.16 GB");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void formatFileSize_greaterThanOneSize() throws Exception {
|
||||
assertThat(
|
||||
FileSizeFormatter.formatFileSize(
|
||||
mContext,
|
||||
MEGABYTE_IN_BYTES * 1551 /* size */,
|
||||
MeasureUnit.GIGABYTE,
|
||||
GIGABYTE_IN_BYTES))
|
||||
.isEqualTo("1.6 GB");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void formatFileSize_greaterThanTen() throws Exception {
|
||||
// Should round down due to truncation
|
||||
assertThat(
|
||||
FileSizeFormatter.formatFileSize(
|
||||
mContext,
|
||||
GIGABYTE_IN_BYTES * 15 + MEGABYTE_IN_BYTES * 50 /* size */,
|
||||
MeasureUnit.GIGABYTE,
|
||||
GIGABYTE_IN_BYTES))
|
||||
.isEqualTo("15 GB");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void formatFileSize_handlesNegativeFileSizes() throws Exception {
|
||||
assertThat(
|
||||
FileSizeFormatter.formatFileSize(
|
||||
mContext,
|
||||
MEGABYTE_IN_BYTES * -155 /* size */,
|
||||
MeasureUnit.GIGABYTE,
|
||||
GIGABYTE_IN_BYTES))
|
||||
.isEqualTo("-0.16 GB");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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.testutils;
|
||||
|
||||
import android.os.IBinder;
|
||||
import android.os.ServiceManager;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
|
||||
// This class is for replacing existing system service with the mocked service.
|
||||
// Copied from CellBroadcastReceiver app.
|
||||
public final class MockedServiceManager {
|
||||
|
||||
private final String TAG = MockedServiceManager.class.getSimpleName();
|
||||
|
||||
private final HashMap<String, IBinder> mServiceManagerMockedServices = new HashMap<>();
|
||||
|
||||
private final HashMap<InstanceKey, Object> mOldInstances = new HashMap<>();
|
||||
|
||||
private final LinkedList<InstanceKey> mInstanceKeys = new LinkedList<>();
|
||||
|
||||
private static class InstanceKey {
|
||||
final Class mClass;
|
||||
final String mInstName;
|
||||
final Object mObj;
|
||||
|
||||
InstanceKey(final Class c, final String instName, final Object obj) {
|
||||
mClass = c;
|
||||
mInstName = instName;
|
||||
mObj = obj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (mClass.getName().hashCode() * 31 + mInstName.hashCode()) * 31;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null || obj.getClass() != getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
InstanceKey other = (InstanceKey) obj;
|
||||
return (other.mClass == mClass && other.mInstName.equals(mInstName)
|
||||
&& other.mObj == mObj);
|
||||
}
|
||||
}
|
||||
|
||||
public MockedServiceManager() throws Exception {
|
||||
replaceInstance(ServiceManager.class, "sCache", null, mServiceManagerMockedServices);
|
||||
}
|
||||
|
||||
public void replaceService(String key, IBinder binder) {
|
||||
mServiceManagerMockedServices.put(key, binder);
|
||||
}
|
||||
|
||||
public void restoreAllServices() throws Exception {
|
||||
restoreInstances();
|
||||
}
|
||||
|
||||
public synchronized void replaceInstance(final Class c, final String instanceName,
|
||||
final Object obj, final Object newValue)
|
||||
throws Exception {
|
||||
Field field = c.getDeclaredField(instanceName);
|
||||
field.setAccessible(true);
|
||||
|
||||
InstanceKey key = new InstanceKey(c, instanceName, obj);
|
||||
if (!mOldInstances.containsKey(key)) {
|
||||
mOldInstances.put(key, field.get(obj));
|
||||
mInstanceKeys.add(key);
|
||||
}
|
||||
field.set(obj, newValue);
|
||||
}
|
||||
|
||||
public synchronized void restoreInstances() throws Exception {
|
||||
Iterator<InstanceKey> it = mInstanceKeys.descendingIterator();
|
||||
|
||||
while (it.hasNext()) {
|
||||
InstanceKey key = it.next();
|
||||
Field field = key.mClass.getDeclaredField(key.mInstName);
|
||||
field.setAccessible(true);
|
||||
field.set(key.mObj, mOldInstances.get(key));
|
||||
}
|
||||
|
||||
mInstanceKeys.clear();
|
||||
mOldInstances.clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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.vpn2;
|
||||
|
||||
import static com.android.settings.vpn2.AppManagementFragment.appHasVpnPermission;
|
||||
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.AppOpsManager;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.os.Process;
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
public class AppSettingsTest extends AndroidTestCase {
|
||||
private static final String TAG = AppSettingsTest.class.getSimpleName();
|
||||
|
||||
@Mock private Context mContext;
|
||||
@Mock private AppOpsManager mAppOps;
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps);
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testAppOpsRequiredToOpenFragment() {
|
||||
ApplicationInfo mockApp = createMockApp();
|
||||
|
||||
final AppOpsManager.PackageOps[] blankOps = {
|
||||
new AppOpsManager.PackageOps(mockApp.packageName, mockApp.uid, new ArrayList<>()),
|
||||
new AppOpsManager.PackageOps(mockApp.packageName, mockApp.uid, new ArrayList<>())
|
||||
};
|
||||
|
||||
// List with one package op
|
||||
when(mAppOps.getOpsForPackage(eq(mockApp.uid), eq(mockApp.packageName),
|
||||
any(int[].class))).thenReturn(Arrays.asList(
|
||||
new AppOpsManager.PackageOps[] {blankOps[0]}));
|
||||
assertTrue(appHasVpnPermission(mContext, mockApp));
|
||||
|
||||
// List with more than one package op
|
||||
when(mAppOps.getOpsForPackage(eq(mockApp.uid), eq(mockApp.packageName),
|
||||
any(int[].class))).thenReturn(Arrays.asList(blankOps));
|
||||
assertTrue(appHasVpnPermission(mContext, mockApp));
|
||||
|
||||
// Empty list
|
||||
when(mAppOps.getOpsForPackage(eq(mockApp.uid), eq(mockApp.packageName),
|
||||
any(int[].class))).thenReturn(Collections.emptyList());
|
||||
assertFalse(appHasVpnPermission(mContext, mockApp));
|
||||
|
||||
// Null list (may be returned in place of an empty list)
|
||||
when(mAppOps.getOpsForPackage(eq(mockApp.uid), eq(mockApp.packageName),
|
||||
any(int[].class))).thenReturn(null);
|
||||
assertFalse(appHasVpnPermission(mContext, mockApp));
|
||||
}
|
||||
|
||||
private static ApplicationInfo createMockApp() {
|
||||
final ApplicationInfo app = new ApplicationInfo();
|
||||
app.packageName = "com.example.mockvpn";
|
||||
app.uid = Process.FIRST_APPLICATION_UID;
|
||||
return app;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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.vpn2;
|
||||
|
||||
import static org.mockito.AdditionalMatchers.not;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.anyBoolean;
|
||||
import static org.mockito.Mockito.argThat;
|
||||
import static org.mockito.Mockito.atLeast;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.internal.net.LegacyVpnInfo;
|
||||
import com.android.internal.net.VpnProfile;
|
||||
|
||||
import org.mockito.ArgumentMatcher;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class PreferenceListTest extends AndroidTestCase {
|
||||
private static final String TAG = "PreferenceListTest";
|
||||
|
||||
@Mock VpnSettings mSettings;
|
||||
|
||||
final Map<String, LegacyVpnPreference> mLegacyMocks = new HashMap<>();
|
||||
final Map<AppVpnInfo, AppPreference> mAppMocks = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mLegacyMocks.clear();
|
||||
mAppMocks.clear();
|
||||
|
||||
doAnswer(invocation -> {
|
||||
final String key = ((VpnProfile)(invocation.getArguments()[0])).key;
|
||||
if (!mLegacyMocks.containsKey(key)) {
|
||||
mLegacyMocks.put(key, mock(LegacyVpnPreference.class));
|
||||
}
|
||||
return mLegacyMocks.get(key);
|
||||
}).when(mSettings).findOrCreatePreference(any(VpnProfile.class), anyBoolean());
|
||||
|
||||
doAnswer(invocation -> {
|
||||
final AppVpnInfo key = (AppVpnInfo)(invocation.getArguments()[0]);
|
||||
if (!mAppMocks.containsKey(key)) {
|
||||
mAppMocks.put(key, mock(AppPreference.class));
|
||||
}
|
||||
return mAppMocks.get(key);
|
||||
}).when(mSettings).findOrCreatePreference(any(AppVpnInfo.class));
|
||||
|
||||
doNothing().when(mSettings).setShownPreferences(any());
|
||||
doReturn(true).when(mSettings).canAddPreferences();
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testNothingShownByDefault() {
|
||||
final VpnSettings.UpdatePreferences updater = new VpnSettings.UpdatePreferences(mSettings);
|
||||
updater.run();
|
||||
|
||||
verify(mSettings, never()).findOrCreatePreference(any(VpnProfile.class), anyBoolean());
|
||||
assertEquals(0, mLegacyMocks.size());
|
||||
assertEquals(0, mAppMocks.size());
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testDisconnectedLegacyVpnShown() {
|
||||
final VpnProfile vpnProfile = new VpnProfile("test-disconnected");
|
||||
|
||||
final VpnSettings.UpdatePreferences updater = new VpnSettings.UpdatePreferences(mSettings);
|
||||
updater.legacyVpns(
|
||||
/* vpnProfiles */ Collections.<VpnProfile>singletonList(vpnProfile),
|
||||
/* connectedLegacyVpns */ Collections.<String, LegacyVpnInfo>emptyMap(),
|
||||
/* lockdownVpnKey */ null);
|
||||
updater.run();
|
||||
|
||||
verify(mSettings, times(1)).findOrCreatePreference(any(VpnProfile.class), eq(true));
|
||||
assertEquals(1, mLegacyMocks.size());
|
||||
assertEquals(0, mAppMocks.size());
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testConnectedLegacyVpnShownIfDeleted() {
|
||||
final LegacyVpnInfo connectedLegacyVpn =new LegacyVpnInfo();
|
||||
connectedLegacyVpn.key = "test-connected";
|
||||
|
||||
final VpnSettings.UpdatePreferences updater = new VpnSettings.UpdatePreferences(mSettings);
|
||||
updater.legacyVpns(
|
||||
/* vpnProfiles */ Collections.<VpnProfile>emptyList(),
|
||||
/* connectedLegacyVpns */ new HashMap<String, LegacyVpnInfo>() {{
|
||||
put(connectedLegacyVpn.key, connectedLegacyVpn);
|
||||
}},
|
||||
/* lockdownVpnKey */ null);
|
||||
updater.run();
|
||||
|
||||
verify(mSettings, times(1)).findOrCreatePreference(any(VpnProfile.class), eq(false));
|
||||
assertEquals(1, mLegacyMocks.size());
|
||||
assertEquals(0, mAppMocks.size());
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testConnectedLegacyVpnShownExactlyOnce() {
|
||||
final VpnProfile vpnProfile = new VpnProfile("test-no-duplicates");
|
||||
final LegacyVpnInfo connectedLegacyVpn = new LegacyVpnInfo();
|
||||
connectedLegacyVpn.key = new String(vpnProfile.key);
|
||||
|
||||
final VpnSettings.UpdatePreferences updater = new VpnSettings.UpdatePreferences(mSettings);
|
||||
updater.legacyVpns(
|
||||
/* vpnProfiles */ Collections.<VpnProfile>singletonList(vpnProfile),
|
||||
/* connectedLegacyVpns */ new HashMap<String, LegacyVpnInfo>() {{
|
||||
put(connectedLegacyVpn.key, connectedLegacyVpn);
|
||||
}},
|
||||
/* lockdownVpnKey */ null);
|
||||
updater.run();
|
||||
|
||||
final ArgumentMatcher<VpnProfile> equalsFake = arg -> {
|
||||
if (arg == vpnProfile) return true;
|
||||
if (arg == null) return false;
|
||||
return TextUtils.equals(arg.key, vpnProfile.key);
|
||||
};
|
||||
|
||||
// The VPN profile should have been used to create a preference and set up at laest once
|
||||
// with update=true to fill in all the fields.
|
||||
verify(mSettings, atLeast(1)).findOrCreatePreference(argThat(equalsFake), eq(true));
|
||||
|
||||
// ...But no other VPN profile key should ever have been passed in.
|
||||
verify(mSettings, never()).findOrCreatePreference(not(argThat(equalsFake)), anyBoolean());
|
||||
|
||||
// And so we should still have exactly 1 preference created.
|
||||
assertEquals(1, mLegacyMocks.size());
|
||||
assertEquals(0, mAppMocks.size());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
include /src/com/android/settings/wifi/calling/OWNERS
|
||||
32
Settings/tests/perftests/Android.bp
Normal file
32
Settings/tests/perftests/Android.bp
Normal file
@@ -0,0 +1,32 @@
|
||||
package {
|
||||
default_team: "trendy_team_android_settings_app",
|
||||
// See: http://go/android-license-faq
|
||||
// A large-scale-change added 'default_applicable_licenses' to import
|
||||
// all of the 'license_kinds' from "packages_apps_Settings_license"
|
||||
// to get the below license kinds:
|
||||
// SPDX-license-identifier-Apache-2.0
|
||||
default_applicable_licenses: ["packages_apps_Settings_license"],
|
||||
}
|
||||
|
||||
android_test {
|
||||
name: "SettingsPerfTests",
|
||||
|
||||
certificate: "platform",
|
||||
|
||||
libs: [
|
||||
"android.test.runner",
|
||||
],
|
||||
|
||||
static_libs: [
|
||||
"androidx.test.rules",
|
||||
"androidx.test.uiautomator_uiautomator",
|
||||
],
|
||||
|
||||
// Include all test java files.
|
||||
srcs: ["src/**/*.java"],
|
||||
|
||||
platform_apis: true,
|
||||
test_suites: ["device-tests"],
|
||||
|
||||
instrumentation_for: "Settings",
|
||||
}
|
||||
29
Settings/tests/perftests/AndroidManifest.xml
Normal file
29
Settings/tests/perftests/AndroidManifest.xml
Normal file
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2020 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.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.settings.tests.perf">
|
||||
|
||||
<application>
|
||||
<uses-library android:name="android.test.runner" />
|
||||
</application>
|
||||
|
||||
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
|
||||
android:targetPackage="com.android.settings.tests.perf"
|
||||
android:label="Settings Performance Test Cases">
|
||||
</instrumentation>
|
||||
|
||||
</manifest>
|
||||
30
Settings/tests/perftests/AndroidTest.xml
Normal file
30
Settings/tests/perftests/AndroidTest.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2020 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.
|
||||
-->
|
||||
<configuration description="Runs Settings Performance Test Cases.">
|
||||
<option name="test-suite-tag" value="apct" />
|
||||
<option name="test-suite-tag" value="apct-instrumentation" />
|
||||
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
|
||||
<option name="cleanup-apks" value="true" />
|
||||
<option name="test-file-name" value="SettingsPerfTests.apk" />
|
||||
</target_preparer>
|
||||
|
||||
<option name="test-tag" value="SettingsPerfTests" />
|
||||
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
|
||||
<option name="package" value="com.android.settings.tests.perf" />
|
||||
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
|
||||
<option name="hidden-api-checks" value="false"/>
|
||||
</test>
|
||||
</configuration>
|
||||
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.tests.perf;
|
||||
|
||||
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||
|
||||
import static junit.framework.TestCase.fail;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
import androidx.test.uiautomator.By;
|
||||
import androidx.test.uiautomator.UiDevice;
|
||||
import androidx.test.uiautomator.UiSelector;
|
||||
import androidx.test.uiautomator.Until;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Collections;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class LaunchSettingsTest {
|
||||
private static class Page {
|
||||
String action;
|
||||
String displayName;
|
||||
String title;
|
||||
|
||||
Page(String action, String displayName, String title) {
|
||||
this.action = action;
|
||||
this.displayName = displayName;
|
||||
this.title = title;
|
||||
}
|
||||
}
|
||||
|
||||
private static final String SCREEN_TIME_OUT = "7200000";
|
||||
private static final String DEFAULT_SCREEN_TIMEOUT = "15000";
|
||||
private static final int TIME_OUT = 5000;
|
||||
private static final int TEST_TIME = 10;
|
||||
private static final Pattern PATTERN = Pattern.compile("TotalTime:\\s[0-9]*");
|
||||
private static final Page[] PAGES;
|
||||
private static final String TAG = "SettingsPerfTests";
|
||||
|
||||
static {
|
||||
PAGES = new Page[]{
|
||||
new Page("android.settings.SETTINGS", "Search settings", "Settings"),
|
||||
new Page("android.settings.WIFI_SETTINGS", "Use Wi‑Fi", "Wi-Fi"),
|
||||
new Page("android.settings.BLUETOOTH_SETTINGS", "Connected devices", "BlueTooth"),
|
||||
new Page("android.settings.APPLICATION_SETTINGS", "App info", "Application"),
|
||||
new Page("android.intent.action.POWER_USAGE_SUMMARY", "Battery", "Battery"),
|
||||
new Page("android.settings.INTERNAL_STORAGE_SETTINGS", "Storage", "Storage")
|
||||
};
|
||||
}
|
||||
|
||||
private Bundle mBundle;
|
||||
private UiDevice mDevice;
|
||||
private Instrumentation mInstrumentation;
|
||||
private Map<String, ArrayList<Integer>> mResult;
|
||||
private String mDefaultScreenTimeout;
|
||||
private String mDefaultAirplaneModeStatus;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mBundle = new Bundle();
|
||||
mDevice = UiDevice.getInstance(getInstrumentation());
|
||||
mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
mResult = new LinkedHashMap<>();
|
||||
mDefaultScreenTimeout = mDevice.executeShellCommand(
|
||||
"settings get system screen_off_timeout");
|
||||
mDefaultAirplaneModeStatus = getAirplaneModeStatus();
|
||||
setScreenTimeOut(SCREEN_TIME_OUT);
|
||||
setAirplaneMode();
|
||||
mDevice.pressHome();
|
||||
mDevice.waitForIdle(TIME_OUT);
|
||||
|
||||
for (Page page : PAGES) {
|
||||
mResult.put(page.title, new ArrayList<Integer>());
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
putResultToBundle();
|
||||
mInstrumentation.sendStatus(0, mBundle);
|
||||
resetScreenTimeout();
|
||||
resetAirplaneMode();
|
||||
closeApp();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void settingsPerformanceTest() throws Exception {
|
||||
for (int i = 0; i < TEST_TIME; i++) {
|
||||
for (Page page : PAGES) {
|
||||
executePreformanceTest(page.action, page.displayName, page.title);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void executePreformanceTest(String action, String displayName, String title)
|
||||
throws Exception {
|
||||
closeApp();
|
||||
mDevice.waitForIdle(TIME_OUT);
|
||||
final String mString = mDevice.executeShellCommand("am start -W -a" + action);
|
||||
mDevice.wait(Until.findObject(By.text(displayName)), TIME_OUT);
|
||||
handleLaunchResult(title, mString);
|
||||
}
|
||||
|
||||
private void handleLaunchResult(String title, String shellCommandResult) {
|
||||
Matcher mMatcher = PATTERN.matcher(shellCommandResult);
|
||||
if (mMatcher.find()) {
|
||||
mResult.get(title).add(Integer.valueOf(mMatcher.group().split("\\s")[1]));
|
||||
} else {
|
||||
fail(String.format("Not found %s.\n %s", title, shellCommandResult));
|
||||
}
|
||||
}
|
||||
|
||||
private void closeApp() throws Exception {
|
||||
mDevice.executeShellCommand("am force-stop com.android.settings");
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
|
||||
private void putResultToBundle() {
|
||||
for (String string : mResult.keySet()) {
|
||||
mBundle.putString(String.format("LaunchSettingsTest_%s_%s", string, "max"),
|
||||
getMax(string));
|
||||
mBundle.putString(String.format("LaunchSettingsTest_%s_%s", string, "min"),
|
||||
getMin(string));
|
||||
mBundle.putString(String.format("LaunchSettingsTest_%s_%s", string, "avg"),
|
||||
getAvg(string));
|
||||
mBundle.putString(String.format("LaunchSettingsTest_%s_%s", string, "25 Percentile"),
|
||||
getPercentile(string, 25));
|
||||
mBundle.putString(String.format("LaunchSettingsTest_%s_%s", string, "50 Percentile"),
|
||||
getPercentile(string, 50));
|
||||
mBundle.putString(String.format("LaunchSettingsTest_%s_%s", string, "75 Percentile"),
|
||||
getPercentile(string, 75));
|
||||
mBundle.putString(String.format("LaunchSettingsTest_%s_%s", string, "all_results"),
|
||||
mResult.get(string).toString());
|
||||
mBundle.putString(String.format("LaunchSettingsTest_%s_%s", string, "results_count"),
|
||||
String.valueOf(mResult.get(string).size()));
|
||||
}
|
||||
}
|
||||
|
||||
private String getMax(String page) {
|
||||
if (mResult.get(page).size() == TEST_TIME) {
|
||||
return String.format("%s", Collections.max(mResult.get(page)));
|
||||
}
|
||||
Log.e(TAG, String.format("Fail to get max of %s.", page));
|
||||
return "0";
|
||||
|
||||
}
|
||||
|
||||
private String getMin(String page) {
|
||||
if (mResult.get(page).size() == TEST_TIME) {
|
||||
return String.format("%s", Collections.min(mResult.get(page)));
|
||||
}
|
||||
Log.e(TAG, String.format("Fail to get min of %s.", page));
|
||||
return "0";
|
||||
}
|
||||
|
||||
private String getAvg(String page) {
|
||||
if (mResult.get(page).size() == TEST_TIME) {
|
||||
return String.valueOf((int) mResult.get(page).stream().mapToInt(
|
||||
i -> i).average().orElse(0));
|
||||
}
|
||||
Log.e(TAG, String.format("Fail to get avg of %s.", page));
|
||||
return "0";
|
||||
}
|
||||
|
||||
private void setScreenTimeOut(String timeout) throws Exception {
|
||||
mDevice.executeShellCommand("settings put system screen_off_timeout " + timeout);
|
||||
}
|
||||
|
||||
private void resetScreenTimeout() throws Exception {
|
||||
String timeout = DEFAULT_SCREEN_TIMEOUT;
|
||||
if (!mDefaultScreenTimeout.isEmpty()) {
|
||||
timeout = mDefaultScreenTimeout;
|
||||
}
|
||||
setScreenTimeOut(timeout);
|
||||
}
|
||||
|
||||
private void setAirplaneMode() throws Exception {
|
||||
if (mDefaultAirplaneModeStatus.equals("0\n")) {
|
||||
clickAirplaneMode();
|
||||
}
|
||||
}
|
||||
|
||||
private void resetAirplaneMode() throws Exception {
|
||||
if (!getAirplaneModeStatus().equals(mDefaultAirplaneModeStatus)) {
|
||||
clickAirplaneMode();
|
||||
}
|
||||
}
|
||||
|
||||
private void clickAirplaneMode() throws Exception {
|
||||
mDevice.executeShellCommand("am start -W -a android.settings.AIRPLANE_MODE_SETTINGS");
|
||||
mDevice.waitForIdle(TIME_OUT);
|
||||
mDevice.findObject(By.textContains("Airplane")).click();
|
||||
mDevice.waitForIdle(TIME_OUT);
|
||||
}
|
||||
|
||||
private String getAirplaneModeStatus() throws Exception {
|
||||
return mDevice.executeShellCommand("settings get global airplane_mode_on");
|
||||
}
|
||||
|
||||
private String getPercentile(String page, double position) {
|
||||
Collections.sort(mResult.get(page));
|
||||
if (mResult.get(page).size() == TEST_TIME) {
|
||||
return String.valueOf(
|
||||
mResult.get(page).get((int) (Math.ceil(TEST_TIME * position / 100)) - 1));
|
||||
}
|
||||
Log.e(TAG, String.format("Fail to get percentile of %s.", page));
|
||||
return "0";
|
||||
}
|
||||
}
|
||||
112
Settings/tests/robotests/Android.bp
Normal file
112
Settings/tests/robotests/Android.bp
Normal file
@@ -0,0 +1,112 @@
|
||||
package {
|
||||
default_team: "trendy_team_android_settings_app",
|
||||
// See: http://go/android-license-faq
|
||||
// A large-scale-change added 'default_applicable_licenses' to import
|
||||
// all of the 'license_kinds' from "packages_apps_Settings_license"
|
||||
// to get the below license kinds:
|
||||
// SPDX-license-identifier-Apache-2.0
|
||||
default_applicable_licenses: ["packages_apps_Settings_license"],
|
||||
}
|
||||
|
||||
// Build SettingsRoboTestStub.apk which includes test-only resources.
|
||||
android_app {
|
||||
name: "SettingsRoboTestStub",
|
||||
defaults: [
|
||||
"SettingsLibDefaults",
|
||||
"SettingsLib-search-defaults",
|
||||
],
|
||||
platform_apis: true,
|
||||
certificate: "platform",
|
||||
privileged: true,
|
||||
use_resource_processor: true,
|
||||
resource_dirs: ["res"],
|
||||
|
||||
static_libs: [
|
||||
"Settings-core",
|
||||
"androidx.fragment_fragment-testing",
|
||||
"frameworks-base-testutils",
|
||||
"androidx.fragment_fragment",
|
||||
"androidx.lifecycle_lifecycle-runtime-testing",
|
||||
"kotlinx_coroutines_test",
|
||||
],
|
||||
|
||||
aaptflags: ["--extra-packages com.android.settings"],
|
||||
|
||||
libs: [
|
||||
"telephony-common",
|
||||
"ims-common",
|
||||
],
|
||||
uses_libs: ["org.apache.http.legacy"],
|
||||
optional_uses_libs: [
|
||||
"androidx.window.extensions",
|
||||
"androidx.window.sidecar",
|
||||
],
|
||||
}
|
||||
|
||||
// Settings Robolectric test target.
|
||||
android_robolectric_test {
|
||||
name: "SettingsRoboTests",
|
||||
srcs: [
|
||||
"src/**/*.java",
|
||||
"src/**/*.kt",
|
||||
],
|
||||
|
||||
// test_suites attribute is not needed. This module will be configured in ATP GCL file.
|
||||
|
||||
static_libs: [
|
||||
"Robolectric_shadows_androidx_fragment_upstream",
|
||||
"Settings_robolectric_meta_service_file",
|
||||
"SettingsLib-robo-testutils",
|
||||
"Settings-robo-testutils",
|
||||
"android.webkit.flags-aconfig-java",
|
||||
"androidx.test.core",
|
||||
"androidx.test.espresso.core",
|
||||
"androidx.test.ext.junit",
|
||||
"androidx.test.rules",
|
||||
"androidx.test.runner",
|
||||
"flag-junit",
|
||||
"flag-junit-base",
|
||||
"aconfig_settings_flags_lib",
|
||||
"platform-test-annotations",
|
||||
"Settings-testutils2",
|
||||
"notification_flags_lib",
|
||||
"com_android_server_accessibility_flags_lib",
|
||||
"testables",
|
||||
],
|
||||
|
||||
libs: [
|
||||
"ims-common",
|
||||
"android.test.mock",
|
||||
],
|
||||
|
||||
java_resource_dirs: [
|
||||
"config",
|
||||
"resources",
|
||||
],
|
||||
|
||||
instrumentation_for: "SettingsRoboTestStub",
|
||||
|
||||
test_options: {
|
||||
timeout: 36000,
|
||||
shards: 10,
|
||||
},
|
||||
|
||||
coverage_libs: [
|
||||
"Settings-core",
|
||||
"SettingsLib",
|
||||
"SettingsLib-search",
|
||||
],
|
||||
|
||||
upstream: true,
|
||||
}
|
||||
|
||||
java_library {
|
||||
name: "Settings-robo-testutils",
|
||||
srcs: ["testutils/**/*.java"],
|
||||
libs: [
|
||||
"Robolectric_all-target_upstream",
|
||||
"Settings-core",
|
||||
"mockito-robolectric-prebuilt",
|
||||
"truth",
|
||||
],
|
||||
}
|
||||
28
Settings/tests/robotests/AndroidManifest.xml
Normal file
28
Settings/tests/robotests/AndroidManifest.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2022 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.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
|
||||
coreApp="true"
|
||||
package="com.android.settings">
|
||||
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
|
||||
|
||||
<application>
|
||||
<activity android:name="com.android.settings.security.TestActivity" android:exported="true" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
2
Settings/tests/robotests/OWNERS
Normal file
2
Settings/tests/robotests/OWNERS
Normal file
@@ -0,0 +1,2 @@
|
||||
# We do not guard tests - everyone is welcomed to contribute to tests.
|
||||
per-file *.java=*
|
||||
24
Settings/tests/robotests/README.md
Normal file
24
Settings/tests/robotests/README.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# Running Settings Robolectric tests
|
||||
|
||||
|
||||
## The full suite
|
||||
```
|
||||
$ croot
|
||||
$ make RunSettingsRoboTests
|
||||
```
|
||||
|
||||
## Running a single test class
|
||||
|
||||
```
|
||||
$ croot
|
||||
$ make RunSettingsRoboTests ROBOTEST_FILTER=<ClassName>
|
||||
```
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
make RunSettingsRoboTests ROBOTEST_FILTER=CodeInspectionTest
|
||||
```
|
||||
|
||||
You can also use partial class name in ROBOTEST_FILTER. If the partial class name matches
|
||||
multiple file names, all of them will be executed.
|
||||
BIN
Settings/tests/robotests/assets/empty_payload_ota.zip
Normal file
BIN
Settings/tests/robotests/assets/empty_payload_ota.zip
Normal file
Binary file not shown.
@@ -0,0 +1,14 @@
|
||||
com.android.settings.applications.appinfo.AppButtonsPreferenceController
|
||||
com.android.settings.applications.appinfo.AppBatteryPreferenceController
|
||||
com.android.settings.applications.appinfo.AppHeaderViewPreferenceController
|
||||
com.android.settings.applications.appinfo.AppMemoryPreferenceController
|
||||
com.android.settings.applications.appinfo.InstantAppButtonsPreferenceController
|
||||
com.android.settings.bluetooth.BluetoothDeviceNamePreferenceController
|
||||
com.android.settings.bluetooth.BluetoothDeviceRenamePreferenceController
|
||||
com.android.settings.datausage.DataUsageSummaryPreferenceController
|
||||
com.android.settings.datausage.WifiDataUsageSummaryPreferenceController
|
||||
com.android.settings.fuelgauge.RestrictAppPreferenceController
|
||||
com.android.settings.fuelgauge.batterysaver.BatterySaverButtonPreferenceController
|
||||
com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController
|
||||
com.android.settings.security.VisiblePatternProfilePreferenceController
|
||||
com.android.settings.wifi.details2.WifiMeteredPreferenceController2
|
||||
@@ -0,0 +1,94 @@
|
||||
com.android.settings.accessibility.AccessibilitySettingsForSetupWizard
|
||||
com.android.settings.accessibility.ToggleAccessibilityServicePreferenceFragment
|
||||
com.android.settings.accessibility.ToggleScreenMagnificationPreferenceFragment
|
||||
com.android.settings.accessibility.ToggleScreenMagnificationPreferenceFragmentForSetupWizard
|
||||
com.android.settings.accessibility.ToggleScreenReaderPreferenceFragmentForSetupWizard
|
||||
com.android.settings.accessibility.ToggleSelectToSpeakPreferenceFragmentForSetupWizard
|
||||
com.android.settings.accounts.AccountDetailDashboardFragment
|
||||
com.android.settings.accounts.AccountPersonalDashboardFragment
|
||||
com.android.settings.accounts.AccountWorkProfileDashboardFragment
|
||||
com.android.settings.accounts.AccountSyncSettings
|
||||
com.android.settings.accounts.ChooseAccountFragment
|
||||
com.android.settings.applications.appinfo.AppInfoDashboardFragment
|
||||
com.android.settings.applications.appinfo.DrawOverlayDetails
|
||||
com.android.settings.applications.appinfo.ExternalSourcesDetails
|
||||
com.android.settings.applications.appinfo.WriteSettingsDetails
|
||||
com.android.settings.applications.AppLaunchSettings
|
||||
com.android.settings.applications.AppStorageSettings
|
||||
com.android.settings.applications.ProcessStatsDetail
|
||||
com.android.settings.applications.ProcessStatsSummary
|
||||
com.android.settings.applications.ProcessStatsUi
|
||||
com.android.settings.applications.RunningServices
|
||||
com.android.settings.applications.specialaccess.pictureinpicture.PictureInPictureDetails
|
||||
com.android.settings.applications.specialaccess.zenaccess.ZenAccessDetails
|
||||
com.android.settings.applications.UsageAccessDetails
|
||||
com.android.settings.backup.ToggleBackupSettingFragment
|
||||
com.android.settings.biometrics.fingerprint.FingerprintSettings$FingerprintSettingsFragment
|
||||
com.android.settings.bluetooth.BluetoothDeviceDetailsFragment
|
||||
com.android.settings.bluetooth.BluetoothPairingDetail
|
||||
com.android.settings.bluetooth.DevicePickerFragment
|
||||
com.android.settings.dashboard.profileselector.ProfileSelectAccountFragment
|
||||
com.android.settings.dashboard.profileselector.ProfileSelectManageApplications
|
||||
com.android.settings.dashboard.profileselector.ProfileSelectLocationFragment
|
||||
com.android.settings.datausage.AppDataUsage
|
||||
com.android.settings.datausage.DataUsageList
|
||||
com.android.settings.datausage.DataUsageSummary
|
||||
com.android.settings.datetime.timezone.TimeZoneSettings
|
||||
com.android.settings.development.compat.PlatformCompatDashboard
|
||||
com.android.settings.deviceinfo.PublicVolumeSettings
|
||||
com.android.settings.deviceinfo.StorageDashboardNoHeaderFragment
|
||||
com.android.settings.deviceinfo.legal.ModuleLicensesDashboard
|
||||
com.android.settings.enterprise.ApplicationListFragment$AdminGrantedPermissionCamera
|
||||
com.android.settings.enterprise.ApplicationListFragment$AdminGrantedPermissionLocation
|
||||
com.android.settings.enterprise.ApplicationListFragment$AdminGrantedPermissionMicrophone
|
||||
com.android.settings.enterprise.ApplicationListFragment$EnterpriseInstalledPackages
|
||||
com.android.settings.enterprise.EnterpriseSetDefaultAppsListFragment
|
||||
com.android.settings.fuelgauge.AdvancedPowerUsageDetail
|
||||
com.android.settings.fuelgauge.InactiveApps
|
||||
com.android.settings.fuelgauge.RestrictedAppDetails
|
||||
com.android.settings.IccLockSettings
|
||||
com.android.settings.inputmethod.InputMethodAndSubtypeEnabler
|
||||
com.android.settings.inputmethod.KeyboardLayoutPickerFragment
|
||||
com.android.settings.inputmethod.SpellCheckersSettings
|
||||
com.android.settings.location.LocationPersonalSettings
|
||||
com.android.settings.location.LocationWorkProfileSettings
|
||||
com.android.settings.network.apn.ApnEditor
|
||||
com.android.settings.network.apn.ApnSettings
|
||||
com.android.settings.network.telephony.NetworkSelectSettings
|
||||
com.android.settings.notification.app.AppNotificationSettings
|
||||
com.android.settings.notification.app.ChannelNotificationSettings
|
||||
com.android.settings.notification.history.NotificationStation
|
||||
com.android.settings.notification.RedactionInterstitial$RedactionInterstitialFragment
|
||||
com.android.settings.notification.zen.ZenModeEventRuleSettings
|
||||
com.android.settings.notification.zen.ZenModeScheduleRuleSettings
|
||||
com.android.settings.notification.zen.ZenCustomRuleNotificationsSettings
|
||||
com.android.settings.notification.zen.ZenCustomRuleCallsSettings
|
||||
com.android.settings.notification.zen.ZenCustomRuleConfigSettings
|
||||
com.android.settings.notification.zen.ZenCustomRuleSettings
|
||||
com.android.settings.notification.zen.ZenCustomRuleBlockedEffectsSettings
|
||||
com.android.settings.notification.zen.ZenCustomRuleMessagesSettings
|
||||
com.android.settings.password.ChooseLockGeneric$ChooseLockGenericFragment
|
||||
com.android.settings.password.SetupChooseLockGeneric$InternalActivity$InternalSetupChooseLockGenericFragment
|
||||
com.android.settings.password.SetupChooseLockGeneric$SetupChooseLockGenericFragment
|
||||
com.android.settings.print.PrintJobSettingsFragment
|
||||
com.android.settings.print.PrintServiceSettingsFragment
|
||||
com.android.settings.SetupRedactionInterstitial$SetupRedactionInterstitialFragment
|
||||
com.android.settings.shortcut.CreateShortcut
|
||||
com.android.settings.TestingSettings
|
||||
com.android.settings.UserCredentialsSettings
|
||||
com.android.settings.users.AppRestrictionsFragment
|
||||
com.android.settings.users.RestrictedProfileSettings
|
||||
com.android.settings.users.UserDetailsSettings
|
||||
com.android.settings.vpn2.AppManagementFragment
|
||||
com.android.settings.vpn2.VpnSettings
|
||||
com.android.settings.wallpaper.WallpaperTypeSettings
|
||||
com.android.settings.wifi.ChangeWifiStateDetails
|
||||
com.android.settings.wifi.calling.WifiCallingSettingsForSub
|
||||
com.android.settings.wifi.details.WifiNetworkDetailsFragment
|
||||
com.android.settings.wifi.dpp.WifiNetworkListFragment
|
||||
com.android.settings.wifi.p2p.WifiP2pSettings
|
||||
com.android.settings.wifi.savedaccesspoints.SavedAccessPointsWifiSettings
|
||||
com.android.settings.wifi.WifiInfo
|
||||
com.android.settings.applications.specialaccess.notificationaccess.NotificationAccessDetails
|
||||
com.android.settings.wifi.details2.WifiNetworkDetailsFragment2
|
||||
com.android.settings.wifi.savedaccesspoints2.SavedAccessPointsWifiSettings2
|
||||
@@ -0,0 +1,9 @@
|
||||
com.android.settings.deletionhelper.ActivationWarningFragment
|
||||
com.android.settings.applications.appops.AppOpsCategory
|
||||
com.android.settings.CustomListPreference$CustomListPreferenceDialogFragment
|
||||
com.android.settings.password.SaveAndFinishWorker
|
||||
com.android.settings.RestrictedListPreference$RestrictedListPreferenceDialogFragment
|
||||
com.android.settings.password.ConfirmDeviceCredentialBaseFragment$LastTryDialog
|
||||
com.android.settings.password.CredentialCheckResultTracker
|
||||
com.android.settings.dashboard.profileselector.ProfileSelectDialog
|
||||
com.android.settings.panel.PanelFragment
|
||||
@@ -0,0 +1 @@
|
||||
com.android.settings.search.FakeSettingsFragment
|
||||
@@ -0,0 +1,20 @@
|
||||
com.android.settings.accessibility.AccessibilitySlicePreferenceController
|
||||
com.android.settings.accessibility.MagnificationAlwaysOnPreferenceController
|
||||
com.android.settings.accessibility.MagnificationFollowTypingPreferenceController
|
||||
com.android.settings.accessibility.MagnificationJoystickPreferenceController
|
||||
com.android.settings.accessibility.ReduceBrightColorsIntensityPreferenceController
|
||||
com.android.settings.accessibility.ReduceBrightColorsPersistencePreferenceController
|
||||
com.android.settings.biometrics.face.FaceSettingsAttentionPreferenceController
|
||||
com.android.settings.core.TogglePreferenceControllerTest$FakeToggle
|
||||
com.android.settings.display.DeviceStateAutoRotateSettingController
|
||||
com.android.settings.display.SmartAutoRotatePreferenceController
|
||||
com.android.settings.gestures.OneHandedMainSwitchPreferenceController
|
||||
com.android.settings.network.telephony.AutoDataSwitchPreferenceController
|
||||
com.android.settings.network.telephony.Enhanced4gBasePreferenceController
|
||||
com.android.settings.network.telephony.MmsMessagePreferenceController
|
||||
com.android.settings.notification.RingVolumePreferenceController
|
||||
com.android.settings.testutils.FakeInvalidSliderController
|
||||
com.android.settings.testutils.FakeSliderController
|
||||
com.android.settings.testutils.FakeToggleController
|
||||
com.android.settings.users.GuestTelephonyPreferenceController
|
||||
com.android.settings.wifi.details2.WifiAutoConnectPreferenceController2
|
||||
BIN
Settings/tests/robotests/assets/no_payload_ota.zip
Normal file
BIN
Settings/tests/robotests/assets/no_payload_ota.zip
Normal file
Binary file not shown.
BIN
Settings/tests/robotests/assets/no_properties_ota.zip
Normal file
BIN
Settings/tests/robotests/assets/no_properties_ota.zip
Normal file
Binary file not shown.
BIN
Settings/tests/robotests/assets/valid_ota.zip
Normal file
BIN
Settings/tests/robotests/assets/valid_ota.zip
Normal file
Binary file not shown.
5
Settings/tests/robotests/config/robolectric.properties
Normal file
5
Settings/tests/robotests/config/robolectric.properties
Normal file
@@ -0,0 +1,5 @@
|
||||
sdk=NEWEST_SDK
|
||||
shadows=\
|
||||
com.android.settings.testutils.shadow.ShadowThreadUtils \
|
||||
com.android.settings.network.ShadowServiceManagerExtend
|
||||
instrumentedPackages=androidx.preference
|
||||
16
Settings/tests/robotests/new_tests_hook.sh
Normal file
16
Settings/tests/robotests/new_tests_hook.sh
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script detects the presence of new robolectric java tests within
|
||||
# commits to be uploaded. If a new file is detected the script will print an
|
||||
# error message and return an error code. Intended to be used as a repo hook.
|
||||
|
||||
new_robolectric_tests=$(
|
||||
git diff --name-status $REPO_LREV | grep "^A.*tests/robotests.*\.java")
|
||||
if [ $new_robolectric_tests != "" ]
|
||||
then
|
||||
echo "New Robolectric unit tests detected. Please submit junit tests" \
|
||||
"instead, in the tests/junit directory." \
|
||||
"See go/android-platform-robolectric-cleanup."
|
||||
echo $new_robolectric_tests
|
||||
exit 1
|
||||
fi
|
||||
@@ -0,0 +1,79 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<com.google.android.setupdesign.GlifLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/setup_wizard_layout"
|
||||
style="?attr/fingerprint_layout_theme"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:clipToPadding="false"
|
||||
android:clipChildren="false">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="@dimen/fingerprint_find_sensor_graphic_size"
|
||||
android:layout_height="@dimen/fingerprint_find_sensor_graphic_size"
|
||||
android:layout_gravity="center_horizontal|bottom">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/fingerprint_sensor_location_animation"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:contentDescription="@string/security_settings_fingerprint_enroll_find_sensor_content_description"
|
||||
android:src="@drawable/fingerprint_sensor_location"
|
||||
android:scaleType="centerInside"/>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
style="@style/SudContentFrame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:clipToPadding="false"
|
||||
android:clipChildren="false">
|
||||
|
||||
<TextView
|
||||
style="@style/SudDescription.Glif"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/sud_description_glif_margin_top"
|
||||
android:text="@string/security_settings_fingerprint_enroll_find_sensor_message"/>
|
||||
|
||||
<View
|
||||
android:layout_height="0dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
<Button
|
||||
style="@style/SudGlifButton.Secondary"
|
||||
android:id="@+id/next_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:layout_gravity="end"
|
||||
android:text="@string/fingerprint_enroll_button_next" />
|
||||
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
</com.google.android.setupdesign.GlifLayout>
|
||||
134
Settings/tests/robotests/res/layout/main_clear.xml
Normal file
134
Settings/tests/robotests/res/layout/main_clear.xml
Normal file
@@ -0,0 +1,134 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2021 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.
|
||||
-->
|
||||
|
||||
<com.google.android.setupdesign.GlifLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/setup_wizard_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:theme="@style/GlifV3Theme.Footer"
|
||||
android:orientation="vertical"
|
||||
android:icon="@drawable/ic_delete_accent"
|
||||
app:sucHeaderText="@string/main_clear_title">
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/main_clear_scrollview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/main_clear_container"
|
||||
style="@style/SudContentFrame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
style="@style/TextAppearance.SudGlifItemSummary"
|
||||
android:id="@+id/sud_layout_description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/main_clear_desc"/>
|
||||
<TextView
|
||||
android:id="@+id/also_erases_external"
|
||||
style="@style/TextAppearance.SudGlifItemSummary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
android:text="@string/main_clear_desc_also_erases_external"/>
|
||||
<TextView
|
||||
android:id="@+id/also_erases_esim"
|
||||
style="@style/TextAppearance.SudGlifItemSummary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
android:text="@string/main_clear_desc_also_erases_esim"/>
|
||||
<TextView
|
||||
android:id="@+id/accounts_label"
|
||||
style="@style/TextAppearance.SudGlifItemSummary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
android:text="@string/main_clear_accounts"/>
|
||||
<LinearLayout
|
||||
android:id="@+id/accounts"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
<!-- Do not add any children here as they will be removed in the MainClear.java
|
||||
code. A list of accounts will be inserted programmatically. -->
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
android:id="@+id/other_users_present"
|
||||
style="@style/TextAppearance.SudGlifItemSummary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
android:text="@string/main_clear_other_users_present"/>
|
||||
<TextView
|
||||
android:id="@+id/no_cancel_mobile_plan"
|
||||
style="@style/TextAppearance.SudGlifItemSummary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
android:text="@string/main_clear_desc_no_cancel_mobile_plan"/>
|
||||
<TextView
|
||||
android:id="@+id/erase_external_option_text"
|
||||
style="@style/TextAppearance.SudGlifItemSummary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/main_clear_desc_erase_external_storage"/>
|
||||
<LinearLayout
|
||||
android:id="@+id/erase_external_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:focusable="true"
|
||||
android:clickable="true">
|
||||
<CheckBox
|
||||
android:id="@+id/erase_external"
|
||||
style="@style/SudCheckBox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:focusable="false"
|
||||
android:clickable="false"
|
||||
android:duplicateParentState="true"/>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:orientation="vertical">
|
||||
<TextView
|
||||
style="@style/TextAppearance.SudGlifItemTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/erase_external_storage"/>
|
||||
<TextView
|
||||
style="@style/TextAppearance.SudGlifItemSummary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/erase_external_storage_description"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<include layout="@layout/reset_esim_checkbox"/>
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
</com.google.android.setupdesign.GlifLayout>
|
||||
40
Settings/tests/robotests/res/layout/main_clear_confirm.xml
Normal file
40
Settings/tests/robotests/res/layout/main_clear_confirm.xml
Normal file
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2021 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.
|
||||
-->
|
||||
<com.google.android.setupdesign.GlifLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:theme="@style/SudThemeGlifV3.DayNight"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/setup_wizard_layout"
|
||||
android:icon="@drawable/ic_delete_accent"
|
||||
app:sucHeaderText="@string/main_clear_confirm_title">
|
||||
|
||||
<LinearLayout
|
||||
style="@style/SudContentFrame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sud_layout_description"
|
||||
style="@style/SudItemTitle.GlifDescription"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/main_clear_final_desc"/>
|
||||
</LinearLayout>
|
||||
</com.google.android.setupdesign.GlifLayout>
|
||||
58
Settings/tests/robotests/res/layout/preference.xml
Normal file
58
Settings/tests/robotests/res/layout/preference.xml
Normal file
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
|
||||
<!-- A test preference layout containing all required widgets -->
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:id="@android:id/icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:ellipsize="marquee"
|
||||
android:fadingEdge="horizontal" />
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/summary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@android:id/title"
|
||||
android:layout_alignStart="@android:id/title"
|
||||
android:visibility="gone"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:maxLines="10" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@android:id/widget_frame"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:minWidth="58dip"
|
||||
android:gravity="end|center_vertical"
|
||||
android:orientation="vertical" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2018 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.
|
||||
-->
|
||||
|
||||
<!-- Since Robolectric can't inflate @*android:layout/alert_dialog_button_bar_material in
|
||||
../res/layout/wifi_add_network_view.xml, so this Layout overrides button bar part. -->
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
layout="@layout/wifi_dialog"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true">
|
||||
<Button
|
||||
android:id="@android:id/button2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
<Button
|
||||
android:id="@android:id/button1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
BIN
Settings/tests/robotests/res/raw/sample_video.mp4
Normal file
BIN
Settings/tests/robotests/res/raw/sample_video.mp4
Normal file
Binary file not shown.
20
Settings/tests/robotests/res/values-mcc998/config.xml
Normal file
20
Settings/tests/robotests/res/values-mcc998/config.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<!--
|
||||
Copyright (C) 2018 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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<!-- List of packages that should be allowlisted for slice uri access. Do not translate -->
|
||||
<string-array name="slice_allowlist_package_names" translatable="false"/>
|
||||
</resources>
|
||||
103
Settings/tests/robotests/res/values-mcc999/config.xml
Normal file
103
Settings/tests/robotests/res/values-mcc999/config.xml
Normal file
@@ -0,0 +1,103 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<bool name="config_enableColorTemperature">false</bool>
|
||||
<bool name="config_show_camera_laser_sensor">false</bool>
|
||||
<bool name="config_show_connectivity_monitor">false</bool>
|
||||
<bool name="config_additional_system_update_setting_enable">true</bool>
|
||||
<bool name="config_show_wifi_settings">false</bool>
|
||||
<bool name="config_show_toggle_airplane">false</bool>
|
||||
<bool name="config_show_private_dns_settings">false</bool>
|
||||
<bool name="config_show_app_info_settings_memory">true</bool>
|
||||
<bool name="config_show_app_info_settings_battery">false</bool>
|
||||
<bool name="config_show_high_power_apps">false</bool>
|
||||
<bool name="config_show_alarm_volume">false</bool>
|
||||
<bool name="config_show_charging_sounds">false</bool>
|
||||
<bool name="config_show_media_volume">false</bool>
|
||||
<bool name="config_show_notification_ringtone">false</bool>
|
||||
<bool name="config_show_notification_volume">false</bool>
|
||||
<bool name="config_show_screen_locking_sounds">false</bool>
|
||||
<bool name="config_show_touch_sounds">false</bool>
|
||||
<bool name="config_show_encryption_and_credentials_encryption_status">false</bool>
|
||||
<bool name="config_show_premium_sms">false</bool>
|
||||
<bool name="config_show_data_saver">false</bool>
|
||||
<bool name="config_show_enabled_vr_listeners">false</bool>
|
||||
<bool name="config_location_mode_available">false</bool>
|
||||
<bool name="config_show_location_scanning">false</bool>
|
||||
<bool name="config_show_location_services">false</bool>
|
||||
<bool name="config_show_manage_device_admin">false</bool>
|
||||
<bool name="config_show_unlock_set_or_change">false</bool>
|
||||
<bool name="config_show_screen_pinning_settings">false</bool>
|
||||
<bool name="config_show_manage_trust_agents">false</bool>
|
||||
<bool name="config_show_show_password">false</bool>
|
||||
<bool name="config_show_trust_agent_click_intent">false</bool>
|
||||
<bool name="config_show_wallpaper_attribution">false</bool>
|
||||
<bool name="config_show_assist_and_voice_input">false</bool>
|
||||
<bool name="config_show_phone_language">false</bool>
|
||||
<bool name="config_show_virtual_keyboard_pref">false</bool>
|
||||
<bool name="config_show_physical_keyboard_pref">false</bool>
|
||||
<bool name="config_show_tts_settings_summary">false</bool>
|
||||
<bool name="config_show_pointer_speed">false</bool>
|
||||
<bool name="config_show_vibrate_input_devices">false</bool>
|
||||
<bool name="config_show_reset_dashboard">false</bool>
|
||||
<bool name="config_show_device_model">false</bool>
|
||||
<bool name="config_show_top_level_accessibility">false</bool>
|
||||
<bool name="config_show_top_level_battery">false</bool>
|
||||
<bool name="config_show_top_level_connected_devices">false</bool>
|
||||
<bool name="config_show_top_level_display">false</bool>
|
||||
<bool name="config_show_wifi_ip_address">false</bool>
|
||||
<bool name="config_show_wifi_mac_address">false</bool>
|
||||
<bool name="config_disable_uninstall_update">true</bool>
|
||||
<bool name="config_show_device_name">false</bool>
|
||||
<bool name="config_use_legacy_suggestion">false</bool>
|
||||
<bool name="config_show_avatar_in_homepage">true</bool>
|
||||
<bool name="config_show_branded_account_in_device_info">false</bool>
|
||||
<bool name="config_show_emergency_info_in_device_info">false</bool>
|
||||
<bool name="config_show_smooth_display">false</bool>
|
||||
<bool name="config_settingsintelligence_slice_supported">true</bool>
|
||||
|
||||
<!-- Whether or not extra preview panels should be used for screen zoom setting. -->
|
||||
<bool name="config_enable_extra_screen_zoom_preview">false</bool>
|
||||
|
||||
<!-- Whether dismissal timestamp should be kept before deletion -->
|
||||
<bool name="config_keep_contextual_card_dismissal_timestamp">true</bool>
|
||||
|
||||
<!-- List of a11y components on the device allowed to be enabled by Settings Slices -->
|
||||
<string-array name="config_settings_slices_accessibility_components" translatable="false">
|
||||
<item>fake_package/fake_service</item>
|
||||
</string-array>
|
||||
|
||||
<!-- List of packages that should be allowlisted for slice uri access. Do not translate -->
|
||||
<string-array name="slice_allowlist_package_names" translatable="false">
|
||||
<item>com.android.settings.slice_allowlist_package</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Email address for the homepage contextual cards feedback -->
|
||||
<string name="config_contextual_card_feedback_email" translatable="false">test@test.test</string>
|
||||
|
||||
<!-- Grayscale settings intent -->
|
||||
<string name="config_grayscale_settings_intent" translatable="false">intent:#Intent;action=test.test;end</string>
|
||||
|
||||
<!-- List containing the injected tile keys which are suppressed. -->
|
||||
<string-array name="config_suppress_injected_tile_keys" translatable="false">
|
||||
<item>injected_tile_key</item>
|
||||
<item>injected_tile_key2</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Uri to query non-public Slice Uris. -->
|
||||
<string name="config_non_public_slice_query_uri" translatable="false">content://com.android.settings.slices/test</string>
|
||||
</resources>
|
||||
24
Settings/tests/robotests/res/values/config.xml
Normal file
24
Settings/tests/robotests/res/values/config.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<!-- Whether or not new device intro suggestion is supported for this device -->
|
||||
<bool name="config_enableColorTemperature">true</bool>
|
||||
<bool name="config_show_camera_laser_sensor">true</bool>
|
||||
<bool name="config_show_connectivity_monitor">true</bool>
|
||||
<bool name="config_show_smooth_display">true</bool>
|
||||
<bool name="config_show_location_services">true</bool>
|
||||
</resources>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user