Snap for 9321750 from 66284b5528 to udc-release

Change-Id: Ia826bdc12209da07090151f8610b177cc3dd1137
This commit is contained in:
Android Build Coastguard Worker
2022-11-23 02:31:28 +00:00
33 changed files with 488 additions and 171 deletions

View File

@@ -125,6 +125,7 @@
<uses-permission android:name="android.permission.READ_SAFETY_CENTER_STATUS" />
<uses-permission android:name="android.permission.SEND_SAFETY_CENTER_UPDATE" />
<uses-permission android:name="android.permission.START_VIEW_APP_FEATURES" />
<uses-permission android:name="android.permission.ACCESS_KEYGUARD_QUICK_AFFORDANCES" />
<application
android:name=".SettingsApplication"

View File

@@ -615,6 +615,9 @@
<item>android.uid.system:1000</item>
</string-array>
<!-- The default value for RedactionInterstitial in SUW -->
<bool name="default_allow_sensitive_lockscreen_content">true</bool>
<!-- Whether to enable the app battery usage list page feature. -->
<bool name="config_app_battery_usage_list_enabled">false</bool>

View File

@@ -10486,8 +10486,8 @@
<!-- Title for the button to reboot with MTE enabled. [CHAR LIMIT=NONE] -->
<string name="reboot_with_mte_title">Reboot with MTE</string>
<string name="reboot_with_mte_message">System will reboot and allow to experiment with Memory Tagging Extension (MTE). MTE may negatively impact system performance and stability. Will be reset on next subsequent reboot.</string>
<string name="reboot_with_mte_summary">Try MTE for a single boot for app development.</string>
<string name="reboot_with_mte_already_enabled">MTE is enabled through Advanced memory protection.</string>
<string name="reboot_with_mte_summary">Try MTE for a single boot for app development</string>
<string name="reboot_with_mte_already_enabled">MTE is enabled through Advanced memory protection</string>
<!-- Toast that is shown when the user initiates capturing a heap dump for the system server. [CHAR LIMIT=NONE] -->
<string name="capturing_system_heap_dump_message">Capturing system heap dump</string>
<!-- Toast that is shown if there's an error capturing the user initiated heap dump. [CHAR LIMIT=NONE] -->
@@ -10627,6 +10627,14 @@
<string name="lockscreen_double_line_clock_summary">Show double-line clock when available</string>
<!-- Lockscreen double-line clock toggle [CHAR LIMIT=60] -->
<string name="lockscreen_double_line_clock_setting_toggle">Double-line clock</string>
<!-- Lock screen buttons preference [CHAR LIMIT=60] -->
<string name="lockscreen_quick_affordances_title">Buttons</string>
<!-- Summary for the lock screen button preference [CHAR LIMIT=60] -->
<plurals name="lockscreen_quick_affordances_summary">
<item quantity="zero">None</item>
<item quantity="one"><xliff:g id="first">%1$s</xliff:g></item>
<item quantity="other"><xliff:g id="first">%1$s</xliff:g>, <xliff:g id="second">%2$s</xliff:g></item>
</plurals>
<!-- Title for RTT setting. [CHAR LIMIT=NONE] -->
<string name="rtt_settings_title"></string>

View File

@@ -69,6 +69,11 @@
android:summary="@string/lockscreen_trivial_controls_summary"
settings:controller="com.android.settings.display.ControlsTrivialPrivacyPreferenceController"/>
<Preference
android:key="customizable_lock_screen_quick_affordances"
android:title="@string/lockscreen_quick_affordances_title"
settings:controller="com.android.settings.display.CustomizableLockScreenQuickAffordancesPreferenceController" />
<SwitchPreference
android:key="lockscreen_double_line_clock_switch"
android:title="@string/lockscreen_double_line_clock_setting_toggle"

View File

@@ -25,7 +25,6 @@ import android.annotation.UiThread;
import android.app.Activity;
import android.app.KeyguardManager;
import android.app.admin.DevicePolicyManager;
import android.app.settings.SettingsEnums;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -68,7 +67,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.UnlaunchableAppActivity;
import com.android.internal.widget.LockPatternUtils;
import com.android.settings.TrustedCredentialsSettings.Tab;
import com.android.settings.core.InstrumentedFragment;
import com.android.settingslib.core.lifecycle.ObservableFragment;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
@@ -81,7 +80,7 @@ import java.util.function.IntConsumer;
/**
* Fragment to display trusted credentials settings for one tab.
*/
public class TrustedCredentialsFragment extends InstrumentedFragment
public class TrustedCredentialsFragment extends ObservableFragment
implements TrustedCredentialsDialogBuilder.DelegateInterface {
public static final String ARG_POSITION = "tab";
@@ -176,11 +175,6 @@ public class TrustedCredentialsFragment extends InstrumentedFragment
return mFragmentView;
}
@Override
public int getMetricsCategory() {
return SettingsEnums.TRUSTED_CREDENTIALS;
}
private void createChildView(
LayoutInflater inflater, ViewGroup parent, Bundle childState, int i) {
boolean isWork = mGroupAdapter.getUserInfoByGroup(i).isManagedProfile();

View File

@@ -113,7 +113,7 @@ public class WriteSettingsDetails extends AppInfoWithHeader implements OnPrefere
@Override
public int getMetricsCategory() {
return SettingsEnums.SYSTEM_ALERT_WINDOW_APPS;
return SettingsEnums.MODIFY_SYSTEM_SETTINGS;
}
public static CharSequence getSummary(Context context, AppEntry entry) {

View File

@@ -527,7 +527,7 @@ public class ManageApplications extends InstrumentedFragment
case LIST_TYPE_OVERLAY:
return SettingsEnums.SYSTEM_ALERT_WINDOW_APPS;
case LIST_TYPE_WRITE_SETTINGS:
return SettingsEnums.SYSTEM_ALERT_WINDOW_APPS;
return SettingsEnums.MODIFY_SYSTEM_SETTINGS;
case LIST_TYPE_MANAGE_SOURCES:
return SettingsEnums.MANAGE_EXTERNAL_SOURCES;
case LIST_TYPE_WIFI_ACCESS:

View File

@@ -62,6 +62,11 @@ public class ControlsPrivacyPreferenceController extends TogglePreferenceControl
@Override
public int getAvailabilityStatus() {
// hide if we should use customizable lock screen quick affordances
if (CustomizableLockScreenUtils.isFeatureEnabled(mContext)) {
return UNSUPPORTED_ON_DEVICE;
}
// hide if lockscreen isn't secure for this user
return isEnabled() && isSecure() ? AVAILABLE : DISABLED_DEPENDENT_SETTING;
}

View File

@@ -70,6 +70,10 @@ public class ControlsTrivialPrivacyPreferenceController extends TogglePreference
@Override
public int getAvailabilityStatus() {
if (CustomizableLockScreenUtils.isFeatureEnabled(mContext)) {
return UNSUPPORTED_ON_DEVICE;
}
return showDeviceControlsSettingsEnabled() ? AVAILABLE : DISABLED_DEPENDENT_SETTING;
}

View File

@@ -0,0 +1,71 @@
/*
* 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.
*/
package com.android.settings.display;
import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.PreferenceControllerMixin;
/**
* Preference for accessing an experience to customize lock screen quick affordances.
*/
public class CustomizableLockScreenQuickAffordancesPreferenceController extends
BasePreferenceController implements PreferenceControllerMixin {
public CustomizableLockScreenQuickAffordancesPreferenceController(Context context, String key) {
super(context, key);
}
@Override
public int getAvailabilityStatus() {
return CustomizableLockScreenUtils.isFeatureEnabled(mContext)
? AVAILABLE
: UNSUPPORTED_ON_DEVICE;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
final Preference preference = screen.findPreference(getPreferenceKey());
if (preference != null) {
preference.setOnPreferenceClickListener(preference1 -> {
// TODO(b/258471384): open the buttons destination within wallpaper picker.
final Intent intent = new Intent(Intent.ACTION_SET_WALLPAPER);
final String packageName =
mContext.getString(R.string.config_wallpaper_picker_package);
if (!TextUtils.isEmpty(packageName)) {
intent.setPackage(packageName);
}
mContext.startActivity(intent);
return true;
});
refreshSummary(preference);
}
}
@Override
public CharSequence getSummary() {
return CustomizableLockScreenUtils.getQuickAffordanceSummary(mContext);
}
}

View File

@@ -0,0 +1,152 @@
/*
* 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.
*/
package com.android.settings.display;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.settings.R;
import java.util.ArrayList;
import java.util.List;
/** Utilities for display settings related to customizable lock screen features. */
public final class CustomizableLockScreenUtils {
private static final String TAG = "CustomizableLockScreenUtils";
private static final Uri BASE_URI = new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority("com.android.systemui.keyguard.quickaffordance")
.build();
@VisibleForTesting
static final Uri FLAGS_URI = BASE_URI.buildUpon()
.path("flags")
.build();
@VisibleForTesting
static final Uri SELECTIONS_URI = BASE_URI.buildUpon()
.path("selections")
.build();
@VisibleForTesting
static final String NAME = "name";
@VisibleForTesting
static final String VALUE = "value";
@VisibleForTesting
static final String ENABLED_FLAG = "is_feature_enabled";
@VisibleForTesting
static final String AFFORDANCE_NAME = "affordance_name";
private CustomizableLockScreenUtils() {}
/**
* Queries and returns whether the customizable lock screen quick affordances feature is enabled
* on the device.
*
* <p>This is a slow, blocking call that shouldn't be made on the main thread.
*/
public static boolean isFeatureEnabled(Context context) {
try (Cursor cursor = context.getContentResolver().query(
FLAGS_URI,
null,
null,
null)) {
if (cursor == null) {
Log.w(TAG, "Cursor was null!");
return false;
}
final int indexOfNameColumn = cursor.getColumnIndex(NAME);
final int indexOfValueColumn = cursor.getColumnIndex(VALUE);
if (indexOfNameColumn == -1 || indexOfValueColumn == -1) {
Log.w(TAG, "Cursor doesn't contain " + NAME + " or " + VALUE + "!");
return false;
}
while (cursor.moveToNext()) {
final String name = cursor.getString(indexOfNameColumn);
final int value = cursor.getInt(indexOfValueColumn);
if (TextUtils.equals(ENABLED_FLAG, name)) {
Log.d(TAG, ENABLED_FLAG + "=" + value);
return value == 1;
}
}
Log.w(TAG, "Flag with name \"" + ENABLED_FLAG + "\" not found!");
return false;
} catch (Exception e) {
Log.e(TAG, "Exception while querying quick affordance content provider", e);
return false;
}
}
/**
* Queries and returns a summary text for the currently-selected lock screen quick affordances.
*
* <p>This is a slow, blocking call that shouldn't be made on the main thread.
*/
@Nullable
public static CharSequence getQuickAffordanceSummary(Context context) {
try (Cursor cursor = context.getContentResolver().query(
SELECTIONS_URI,
null,
null,
null)) {
if (cursor == null) {
Log.w(TAG, "Cursor was null!");
return null;
}
final int columnIndex = cursor.getColumnIndex(AFFORDANCE_NAME);
if (columnIndex == -1) {
Log.w(TAG, "Cursor doesn't contain \"" + AFFORDANCE_NAME + "\" column!");
return null;
}
final List<String> affordanceNames = new ArrayList<>(cursor.getCount());
while (cursor.moveToNext()) {
final String affordanceName = cursor.getString(columnIndex);
if (!TextUtils.isEmpty(affordanceName)) {
affordanceNames.add(affordanceName);
}
}
// We don't display more than the first two items.
final int usableAffordanceNameCount = Math.min(2, affordanceNames.size());
final List<String> arguments = new ArrayList<>(usableAffordanceNameCount);
if (!affordanceNames.isEmpty()) {
arguments.add(affordanceNames.get(0));
}
if (affordanceNames.size() > 1) {
arguments.add(affordanceNames.get(1));
}
return context.getResources().getQuantityString(
R.plurals.lockscreen_quick_affordances_summary,
usableAffordanceNameCount,
arguments.toArray());
} catch (Exception e) {
Log.e(TAG, "Exception while querying quick affordance content provider", e);
return null;
}
}
}

View File

@@ -87,6 +87,10 @@ public class QRCodeScannerPreferenceController extends TogglePreferenceControlle
@Override
public int getAvailabilityStatus() {
if (CustomizableLockScreenUtils.isFeatureEnabled(mContext)) {
return UNSUPPORTED_ON_DEVICE;
}
return isScannerActivityAvailable() ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
}

View File

@@ -62,6 +62,10 @@ public class WalletPrivacyPreferenceController extends TogglePreferenceControlle
@Override
public int getAvailabilityStatus() {
if (CustomizableLockScreenUtils.isFeatureEnabled(mContext)) {
return UNSUPPORTED_ON_DEVICE;
}
return isEnabled() && isSecure() ? AVAILABLE : DISABLED_DEPENDENT_SETTING;
}

View File

@@ -43,7 +43,6 @@ import com.android.settings.fuelgauge.batterytip.tips.HighUsageTip;
import com.android.settings.fuelgauge.batterytip.tips.RestrictAppTip;
import com.android.settings.fuelgauge.batterytip.tips.UnrestrictAppTip;
import java.text.NumberFormat;
import java.util.List;
/**
@@ -142,29 +141,6 @@ public class BatteryTipDialogFragment extends InstrumentedDialogFragment impleme
.setPositiveButton(R.string.battery_tip_unrestrict_app_dialog_ok, this)
.setNegativeButton(R.string.battery_tip_unrestrict_app_dialog_cancel, null)
.create();
case BatteryTip.TipType.BATTERY_DEFENDER:
mMetricsFeatureProvider.action(context,
SettingsEnums.ACTION_TIP_BATTERY_DEFENDER, mMetricsKey);
final double chargeLimitLevel = 0.8f;
final String percentage =
NumberFormat.getPercentInstance().format(chargeLimitLevel);
final String message = context.getString(
R.string.battery_tip_limited_temporarily_dialog_msg, percentage);
final boolean isPluggedIn = isPluggedIn();
final AlertDialog.Builder dialogBuilder =
new AlertDialog.Builder(context)
.setTitle(R.string.battery_tip_limited_temporarily_title)
.setMessage(message);
if (isPluggedIn) {
dialogBuilder
.setPositiveButton(
R.string.battery_tip_limited_temporarily_dialog_resume_charge,
this)
.setNegativeButton(R.string.okay, null);
} else {
dialogBuilder.setPositiveButton(R.string.okay, null);
}
return dialogBuilder.create();
default:
throw new IllegalArgumentException("unknown type " + mBatteryTip.getType());
}

View File

@@ -1,43 +0,0 @@
/*
* 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.batterytip.actions;
import android.content.Intent;
import com.android.settings.SettingsActivity;
import com.android.settings.overlay.FeatureFactory;
/**
* Action to open the Support Center article
*/
public class BatteryDefenderAction extends BatteryTipAction {
private SettingsActivity mSettingsActivity;
public BatteryDefenderAction(SettingsActivity settingsActivity) {
super(settingsActivity.getApplicationContext());
mSettingsActivity = settingsActivity;
}
@Override
public void handlePositiveAction(int metricsKey) {
final Intent intent = FeatureFactory.getFactory(mContext)
.getPowerUsageFeatureProvider(mContext).getResumeChargeIntent();
if (intent != null) {
mContext.sendBroadcast(intent);
}
}
}

View File

@@ -189,13 +189,16 @@ public class RedactionInterstitial extends SettingsActivity {
}
private void loadFromSettings() {
final boolean showUnRedactedDefault = getContext().getResources().getBoolean(
R.bool.default_allow_sensitive_lockscreen_content);
final boolean managedProfile = UserManager.get(getContext()).isManagedProfile(mUserId);
// Hiding all notifications is device-wide setting, managed profiles can only set
// whether their notifications are show in full or redacted.
final boolean showNotifications = managedProfile || Settings.Secure.getIntForUser(
getContentResolver(), LOCK_SCREEN_SHOW_NOTIFICATIONS, 0, mUserId) != 0;
final boolean showUnredacted = Settings.Secure.getIntForUser(
getContentResolver(), LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 1, mUserId) != 0;
getContentResolver(), LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
showUnRedactedDefault ? 1 : 0, mUserId) != 0;
int checkedButtonId = R.id.hide_all;
if (showNotifications) {

View File

@@ -0,0 +1,153 @@
/*
* 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.
*/
package com.android.settings.display;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.database.MatrixCursor;
import android.text.TextUtils;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.SmallTest;
import com.android.settings.R;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
@SmallTest
@RunWith(RobolectricTestRunner.class)
public class CustomizableLockScreenQuickAffordancesPreferenceControllerTest {
private static final String KEY = "key";
@Mock private Context mContext;
@Mock private ContentResolver mContentResolver;
private CustomizableLockScreenQuickAffordancesPreferenceController mUnderTest;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mContext.getContentResolver()).thenReturn(mContentResolver);
when(mContext.getResources())
.thenReturn(ApplicationProvider.getApplicationContext().getResources());
mUnderTest = new CustomizableLockScreenQuickAffordancesPreferenceController(mContext, KEY);
}
@Test
public void getAvailabilityStatus_whenEnabled() {
setEnabled(true);
assertThat(mUnderTest.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
public void getAvailabilityStatus_whenNotEnabled() {
setEnabled(false);
assertThat(mUnderTest.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
}
@Test
public void displayPreference_click() {
setSelectedAffordanceNames("one", "two");
final PreferenceScreen screen = mock(PreferenceScreen.class);
final Preference preference = mock(Preference.class);
when(screen.findPreference(KEY)).thenReturn(preference);
mUnderTest.displayPreference(screen);
final ArgumentCaptor<Preference.OnPreferenceClickListener> clickCaptor =
ArgumentCaptor.forClass(Preference.OnPreferenceClickListener.class);
verify(preference).setOnPreferenceClickListener(clickCaptor.capture());
clickCaptor.getValue().onPreferenceClick(preference);
final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(preference).setOnPreferenceClickListener(clickCaptor.capture());
verify(mContext).startActivity(intentCaptor.capture());
assertThat(intentCaptor.getValue().getPackage()).isEqualTo(
mContext.getString(R.string.config_wallpaper_picker_package));
assertThat(intentCaptor.getValue().getAction()).isEqualTo(Intent.ACTION_SET_WALLPAPER);
}
@Test
public void getSummary_whenNoneAreSelected() {
setSelectedAffordanceNames();
assertThat(mUnderTest.getSummary()).isNull();
}
@Test
public void getSummary_whenOneIsSelected() {
setSelectedAffordanceNames("one");
assertThat(TextUtils.equals(mUnderTest.getSummary(), "one")).isTrue();
}
@Test
public void getSummary_whenTwoAreSelected() {
setSelectedAffordanceNames("one", "two");
assertThat(TextUtils.equals(mUnderTest.getSummary(), "one, two")).isTrue();
}
private void setEnabled(boolean isEnabled) {
final MatrixCursor cursor = new MatrixCursor(
new String[] {
CustomizableLockScreenUtils.NAME,
CustomizableLockScreenUtils.VALUE
});
cursor.addRow(new Object[] { CustomizableLockScreenUtils.ENABLED_FLAG, isEnabled ? 1 : 0 });
when(
mContentResolver.query(
CustomizableLockScreenUtils.FLAGS_URI, null, null, null))
.thenReturn(cursor);
}
private void setSelectedAffordanceNames(String... affordanceNames) {
final MatrixCursor cursor = new MatrixCursor(
new String[] { CustomizableLockScreenUtils.AFFORDANCE_NAME });
for (final String name : affordanceNames) {
cursor.addRow(new Object[] { name });
}
when(
mContentResolver.query(
CustomizableLockScreenUtils.SELECTIONS_URI, null, null, null))
.thenReturn(cursor);
}
}

View File

@@ -244,20 +244,4 @@ public class BatteryTipDialogFragmentTest {
assertThat(shadowDialog.getMessage()).isEqualTo(
mContext.getText(R.string.battery_tip_dialog_summary_message));
}
@Test
public void testOnCreateDialog_defenderTip_fireDialog() {
mDialogFragment = BatteryTipDialogFragment.newInstance(mDefenderTip, METRICS_KEY);
FragmentController.setupFragment(mDialogFragment, FragmentActivity.class,
0 /* containerViewId */, null /* bundle */);
final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog);
assertThat(shadowDialog.getTitle()).isEqualTo(
mContext.getString(R.string.battery_tip_limited_temporarily_title));
assertThat(shadowDialog.getMessage()).isEqualTo(
mContext.getString(R.string.battery_tip_limited_temporarily_dialog_msg, "80%"));
}
}

View File

@@ -21,6 +21,7 @@ import android.widget.RadioButton;
import com.android.settings.R;
import com.android.settings.RestrictedRadioButton;
import com.android.settings.notification.RedactionInterstitial.RedactionInterstitialFragment;
import com.android.settings.testutils.shadow.SettingsShadowResources;
import com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal;
import com.android.settings.testutils.shadow.ShadowUtils;
@@ -38,6 +39,7 @@ import org.robolectric.shadows.ShadowUserManager;
@Config(shadows = {
ShadowUtils.class,
ShadowRestrictedLockUtilsInternal.class,
SettingsShadowResources.class,
})
public class RedactionInterstitialTest {
private RedactionInterstitial mActivity;
@@ -134,6 +136,28 @@ public class RedactionInterstitialTest {
assertSelectedButton(R.id.redact_sensitive);
}
@Test
public void defaultShowSensitiveContent_configDeny() {
final ContentResolver resolver = RuntimeEnvironment.application.getContentResolver();
Settings.Secure.putIntForUser(resolver,
LOCK_SCREEN_SHOW_NOTIFICATIONS, 1, UserHandle.myUserId());
setupConfig(false);
setupActivity();
assertSelectedButton(R.id.redact_sensitive);
}
@Test
public void defaultShowSensitiveContent_configAllow() {
final ContentResolver resolver = RuntimeEnvironment.application.getContentResolver();
Settings.Secure.putIntForUser(resolver,
LOCK_SCREEN_SHOW_NOTIFICATIONS, 1, UserHandle.myUserId());
setupConfig(true);
setupActivity();
assertSelectedButton(R.id.show_all);
}
private void setupActivity() {
mActivity = buildActivity(RedactionInterstitial.class, new Intent()).setup().get();
mFragment = (RedactionInterstitialFragment)
@@ -142,6 +166,11 @@ public class RedactionInterstitialTest {
assertThat(mFragment).isNotNull();
}
private void setupConfig(boolean allowSensitiveContent) {
SettingsShadowResources.overrideResource(
R.bool.default_allow_sensitive_lockscreen_content, allowSensitiveContent);
}
private void setupSettings(int show, int showUnredacted) {
final ContentResolver resolver = RuntimeEnvironment.application.getContentResolver();
Settings.Secure.putIntForUser(resolver,

View File

@@ -30,13 +30,11 @@ android_test {
static_libs: [
"Settings-core",
"SpaLibTestUtils",
"androidx.compose.runtime_runtime",
"androidx.compose.ui_ui-test-junit4",
"androidx.compose.ui_ui-test-manifest",
"androidx.test.ext.junit",
"androidx.test.runner",
"mockito-target-extended-minus-junit4",
"truth-prebuilt",
],
jni_libs: [
"libdexmakerjvmtiagent",

View File

@@ -30,6 +30,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsEnabled
import androidx.compose.ui.test.assertIsNotDisplayed
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.onRoot
@@ -38,6 +39,8 @@ import androidx.core.os.bundleOf
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.R
import com.android.settingslib.spa.testutils.delay
import com.android.settingslib.spa.testutils.waitUntilExists
import com.android.settingslib.spaprivileged.model.app.userHandle
import com.android.settingslib.spaprivileged.model.app.userId
import com.google.common.truth.Truth.assertThat
@@ -140,7 +143,7 @@ class AppAllServicesPreferenceTest {
setContent()
composeTestRule.onNodeWithText(SUMMARY).assertIsDisplayed()
composeTestRule.waitUntilExists(hasText(SUMMARY))
}
@Test
@@ -149,6 +152,7 @@ class AppAllServicesPreferenceTest {
setContent()
composeTestRule.onRoot().performClick()
composeTestRule.delay()
val intentCaptor = ArgumentCaptor.forClass(Intent::class.java)
verify(context).startActivityAsUser(intentCaptor.capture(), eq(APP.userHandle))

View File

@@ -31,8 +31,8 @@ import androidx.compose.ui.test.onRoot
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.dx.mockito.inline.extended.ExtendedMockito
import com.android.settings.testutils.delay
import com.android.settingslib.applications.AppUtils
import com.android.settingslib.spa.testutils.delay
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.stateIn
import org.junit.After

View File

@@ -30,7 +30,6 @@ import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.onRoot
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.printToLog
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.dx.mockito.inline.extended.ExtendedMockito
@@ -39,9 +38,9 @@ import com.android.settings.R
import com.android.settings.Utils
import com.android.settings.applications.appinfo.AppInfoDashboardFragment
import com.android.settings.datausage.AppDataUsage
import com.android.settings.testutils.waitUntilExists
import com.android.settingslib.net.NetworkCycleDataForUid
import com.android.settingslib.net.NetworkCycleDataForUidLoader
import com.android.settingslib.spa.testutils.waitUntilExists
import org.junit.After
import org.junit.Before
import org.junit.Rule
@@ -134,9 +133,7 @@ class AppDataUsagePreferenceTest {
setContent()
composeTestRule.onRoot().printToLog("AAA")
composeTestRule.onNodeWithText(context.getString(R.string.no_data_usage))
.assertIsDisplayed()
composeTestRule.waitUntilExists(hasText(context.getString(R.string.no_data_usage)))
}
@Test

View File

@@ -61,7 +61,7 @@ class AppDisableButtonTest {
private lateinit var devicePolicyManager: DevicePolicyManager
private val fakeFeatureFactory = FakeFeatureFactory()
private val appFeatureProvider = fakeFeatureFactory.applicationFeatureProvider
private val appFeatureProvider = fakeFeatureFactory.mockApplicationFeatureProvider
private lateinit var appDisableButton: AppDisableButton

View File

@@ -38,8 +38,8 @@ import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
import com.android.settings.R
import com.android.settings.Utils
import com.android.settings.applications.AppStoreUtil
import com.android.settings.testutils.waitUntilExists
import com.android.settingslib.applications.AppUtils
import com.android.settingslib.spa.testutils.waitUntilExists
import com.android.settingslib.spaprivileged.framework.common.userManager
import com.android.settingslib.spaprivileged.model.app.userHandle
import org.junit.After

View File

@@ -24,6 +24,7 @@ import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsNotDisplayed
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.onRoot
@@ -36,6 +37,8 @@ import com.android.settings.applications.AppInfoBase
import com.android.settings.applications.AppLocaleUtil
import com.android.settings.applications.appinfo.AppLocaleDetails
import com.android.settings.localepicker.AppLocalePickerActivity
import com.android.settingslib.spa.testutils.delay
import com.android.settingslib.spa.testutils.waitUntilExists
import com.android.settingslib.spaprivileged.model.app.userHandle
import com.google.common.truth.Truth.assertThat
import org.junit.After
@@ -103,15 +106,16 @@ class AppLocalePreferenceTest {
composeTestRule.onNodeWithText(context.getString(R.string.app_locale_preference_title))
.assertIsDisplayed()
composeTestRule.onNodeWithText(SUMMARY).assertIsDisplayed()
composeTestRule.waitUntilExists(hasText(SUMMARY))
}
@Test
fun whenCanDisplayLocalUi_click_startsActivity() {
fun whenCanDisplayLocalUi_click_startActivity() {
doNothing().`when`(context).startActivityAsUser(any(), any())
setContent()
composeTestRule.onRoot().performClick()
composeTestRule.delay()
val intentCaptor = ArgumentCaptor.forClass(Intent::class.java)
verify(context).startActivityAsUser(intentCaptor.capture(), eq(APP.userHandle))

View File

@@ -29,18 +29,14 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsEnabled
import androidx.compose.ui.test.assertIsNotDisplayed
import androidx.compose.ui.test.assertIsNotEnabled
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.onRoot
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.printToLog
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.R
import com.android.settings.testutils.waitUntilExists
import com.android.settingslib.applications.AppUtils
import com.android.settingslib.spa.testutils.delay
import com.android.settingslib.spaprivileged.model.app.userHandle
import com.android.settingslib.spaprivileged.model.app.userId
import com.google.common.truth.Truth.assertThat
@@ -49,7 +45,6 @@ import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers
import org.mockito.Mock
import org.mockito.Mockito.any
import org.mockito.Mockito.eq
@@ -135,6 +130,7 @@ class AppSettingsPreferenceTest {
setContent()
composeTestRule.onRoot().performClick()
composeTestRule.delay()
val intentCaptor = ArgumentCaptor.forClass(Intent::class.java)
verify(context).startActivityAsUser(intentCaptor.capture(), eq(APP.userHandle))

View File

@@ -63,7 +63,7 @@ class AppTimeSpentPreferenceTest {
private lateinit var packageManager: PackageManager
private val fakeFeatureFactory = FakeFeatureFactory()
private val appFeatureProvider = fakeFeatureFactory.applicationFeatureProvider
private val appFeatureProvider = fakeFeatureFactory.mockApplicationFeatureProvider
@Before
fun setUp() {

View File

@@ -24,10 +24,6 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsEnabled
import androidx.compose.ui.test.assertIsNotDisplayed
import androidx.compose.ui.test.filterToOne
import androidx.compose.ui.test.hasAnyAncestor
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.isDialog
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.onRoot
@@ -37,7 +33,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.dx.mockito.inline.extended.ExtendedMockito
import com.android.settings.R
import com.android.settings.Utils
import com.android.settings.testutils.delay
import com.android.settingslib.spa.testutils.delay
import com.android.settingslib.spa.testutils.onDialogText
import org.junit.After
import org.junit.Before
import org.junit.Rule
@@ -141,18 +138,14 @@ class InstantAppDomainsPreferenceTest {
composeTestRule.onRoot().performClick()
composeTestRule.delay()
assertDialogHasText(context.getString(R.string.app_launch_supported_domain_urls_title))
assertDialogHasText("abc")
assertDialogHasText("def")
composeTestRule.onDialogText(
context.getString(R.string.app_launch_supported_domain_urls_title)
).assertIsDisplayed()
composeTestRule.onDialogText("abc").assertIsDisplayed()
composeTestRule.onDialogText("def").assertIsDisplayed()
}
private fun assertDialogHasText(text: String) {
composeTestRule.onAllNodes(hasAnyAncestor(isDialog()))
.filterToOne(hasText(text))
.assertIsDisplayed()
}
private fun setContent(app:ApplicationInfo = INSTANT_APP) {
private fun setContent(app: ApplicationInfo = INSTANT_APP) {
composeTestRule.setContent {
CompositionLocalProvider(LocalContext provides context) {
InstantAppDomainsPreference(app)

View File

@@ -24,6 +24,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsEnabled
import androidx.compose.ui.test.assertIsNotDisplayed
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.onRoot
@@ -34,6 +35,8 @@ import com.android.dx.mockito.inline.extended.ExtendedMockito
import com.android.settings.R
import com.android.settings.applications.appinfo.AppInfoDashboardFragment
import com.android.settings.applications.specialaccess.interactacrossprofiles.InteractAcrossProfilesDetails
import com.android.settingslib.spa.testutils.delay
import com.android.settingslib.spa.testutils.waitUntilExists
import com.android.settingslib.spaprivileged.framework.common.crossProfileApps
import org.junit.After
import org.junit.Before
@@ -110,7 +113,7 @@ class InteractAcrossProfilesDetailsPreferenceTest {
setContent()
composeTestRule.onNodeWithText(SUMMARY).assertIsDisplayed()
composeTestRule.waitUntilExists(hasText(SUMMARY))
}
@Test
@@ -119,6 +122,7 @@ class InteractAcrossProfilesDetailsPreferenceTest {
setContent()
composeTestRule.onRoot().performClick()
composeTestRule.delay()
ExtendedMockito.verify {
AppInfoDashboardFragment.startAppInfoFragment(

View File

@@ -1,33 +0,0 @@
/*
* 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.
*/
package com.android.settings.testutils
import androidx.compose.ui.test.ComposeTimeoutException
import androidx.compose.ui.test.SemanticsMatcher
import androidx.compose.ui.test.junit4.ComposeContentTestRule
/** Blocks until the found a semantics node that match the given condition. */
fun ComposeContentTestRule.waitUntilExists(matcher: SemanticsMatcher) = waitUntil {
onAllNodes(matcher).fetchSemanticsNodes().isNotEmpty()
}
/** Blocks until the timeout is reached. */
fun ComposeContentTestRule.delay(timeoutMillis: Long = 1_000) = try {
waitUntil(timeoutMillis) { false }
} catch (_: ComposeTimeoutException) {
// Expected
}

View File

@@ -51,7 +51,9 @@ import org.mockito.Mockito.mock
class FakeFeatureFactory : FeatureFactory() {
val applicationFeatureProvider: ApplicationFeatureProvider =
private val mockMetricsFeatureProvider: MetricsFeatureProvider =
mock(MetricsFeatureProvider::class.java)
val mockApplicationFeatureProvider: ApplicationFeatureProvider =
mock(ApplicationFeatureProvider::class.java)
init {
@@ -70,9 +72,7 @@ class FakeFeatureFactory : FeatureFactory() {
TODO("Not yet implemented")
}
override fun getMetricsFeatureProvider(): MetricsFeatureProvider {
TODO("Not yet implemented")
}
override fun getMetricsFeatureProvider(): MetricsFeatureProvider = mockMetricsFeatureProvider
override fun getPowerUsageFeatureProvider(context: Context?): PowerUsageFeatureProvider {
TODO("Not yet implemented")
@@ -96,7 +96,7 @@ class FakeFeatureFactory : FeatureFactory() {
TODO("Not yet implemented")
}
override fun getApplicationFeatureProvider(context: Context?) = applicationFeatureProvider
override fun getApplicationFeatureProvider(context: Context?) = mockApplicationFeatureProvider
override fun getLocaleFeatureProvider(): LocaleFeatureProvider {
TODO("Not yet implemented")

View File

@@ -0,0 +1 @@
include /src/com/android/settings/biometrics/OWNERS