Snap for 11401641 from 2eba5be9b4 to 24Q2-release

Change-Id: I57bba30c0bbb7d7a02375e7b1d531e8259fdade3
This commit is contained in:
Android Build Coastguard Worker
2024-02-03 22:20:42 +00:00
20 changed files with 634 additions and 623 deletions

View File

@@ -46,6 +46,7 @@ import android.provider.Settings;
import android.service.autofill.AutofillServiceInfo;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import android.view.View;
import android.widget.CompoundButton;
@@ -77,6 +78,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Executor;
@@ -114,7 +116,7 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
private @Nullable String mFlagOverrideForTest = null;
private @Nullable PreferenceScreen mPreferenceScreen = null;
private boolean mVisibility = false;
private Optional<Boolean> mSimulateHiddenForTests = Optional.empty();
private boolean mIsWorkProfile = false;
private boolean mSimulateConnectedForTests = false;
@@ -159,7 +161,9 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
return UNSUPPORTED_ON_DEVICE;
}
if (!mVisibility) {
// If there is no top provider or any providers in the list then
// we should hide this pref.
if (isHiddenDueToNoProviderSet()) {
return CONDITIONALLY_UNAVAILABLE;
}
@@ -378,20 +382,29 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
}
@VisibleForTesting
public void setVisibility(boolean newVisibility) {
if (newVisibility == mVisibility) {
return;
}
mVisibility = newVisibility;
public void forceDelegateRefresh() {
if (mDelegate != null) {
mDelegate.forceDelegateRefresh();
}
}
@VisibleForTesting
public boolean getVisibility() {
return mVisibility;
public void setSimulateHiddenForTests(Optional<Boolean> simulateHiddenForTests) {
mSimulateHiddenForTests = simulateHiddenForTests;
}
@VisibleForTesting
public boolean isHiddenDueToNoProviderSet() {
return isHiddenDueToNoProviderSet(getProviders());
}
private boolean isHiddenDueToNoProviderSet(
Pair<List<CombinedProviderInfo>, CombinedProviderInfo> providerPair) {
if (mSimulateHiddenForTests.isPresent()) {
return mSimulateHiddenForTests.get();
}
return (providerPair.first.size() == 0 || providerPair.second == null);
}
@VisibleForTesting
@@ -459,10 +472,11 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
return preference;
}
/** Aggregates the list of services and builds a list of UI prefs to show. */
@VisibleForTesting
public Map<String, CombiPreference> buildPreferenceList(
Context context, PreferenceGroup group) {
/**
* Returns a pair that contains a list of the providers in the first position and the top
* provider in the second position.
*/
private Pair<List<CombinedProviderInfo>, CombinedProviderInfo> getProviders() {
// Get the selected autofill provider. If it is the placeholder then replace it with an
// empty string.
String selectedAutofillProvider =
@@ -475,15 +489,25 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
// Get the list of combined providers.
List<CombinedProviderInfo> providers =
CombinedProviderInfo.buildMergedList(
AutofillServiceInfo.getAvailableServices(context, getUser()),
AutofillServiceInfo.getAvailableServices(mContext, getUser()),
mServices,
selectedAutofillProvider);
return new Pair<>(providers, CombinedProviderInfo.getTopProvider(providers));
}
// Get the provider that is displayed at the top. If there is none then hide
// everything.
CombinedProviderInfo topProvider = CombinedProviderInfo.getTopProvider(providers);
if (topProvider == null) {
setVisibility(false);
/** Aggregates the list of services and builds a list of UI prefs to show. */
@VisibleForTesting
public @NonNull Map<String, CombiPreference> buildPreferenceList(
@NonNull Context context, @NonNull PreferenceGroup group) {
// Get the providers and extract the values.
Pair<List<CombinedProviderInfo>, CombinedProviderInfo> providerPair = getProviders();
CombinedProviderInfo topProvider = providerPair.second;
List<CombinedProviderInfo> providers = providerPair.first;
// If the provider is set to "none" or there are no providers then we should not
// return any providers.
if (isHiddenDueToNoProviderSet(providerPair)) {
forceDelegateRefresh();
return new HashMap<>();
}
@@ -520,7 +544,7 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
}
// Set the visibility if we have services.
setVisibility(!output.isEmpty());
forceDelegateRefresh();
return output;
}

View File

@@ -38,7 +38,8 @@ import com.google.common.annotations.VisibleForTesting;
public class BluetoothDetailsHearingDeviceControlsController extends BluetoothDetailsController
implements Preference.OnPreferenceClickListener {
private static final String KEY_DEVICE_CONTROLS_GENERAL_GROUP = "device_controls_general";
@VisibleForTesting
static final String KEY_DEVICE_CONTROLS_GENERAL_GROUP = "device_controls_general";
@VisibleForTesting
static final String KEY_HEARING_DEVICE_CONTROLS = "hearing_device_controls";

View File

@@ -22,6 +22,7 @@ import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.content.Intent;
import android.content.res.TypedArray;
import android.hardware.input.InputManager;
import android.net.Uri;
@@ -53,6 +54,7 @@ import com.android.settings.slices.SlicePreferenceController;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
import java.util.ArrayList;
@@ -324,8 +326,11 @@ public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment
lifecycle));
controllers.add(new BluetoothDetailsPairOtherController(context, this, mCachedDevice,
lifecycle));
controllers.add(new BluetoothDetailsHearingDeviceControlsController(context, this,
mCachedDevice, lifecycle));
// Don't need to show hearing device again when launched from the same page.
if (!isLaunchFromHearingDevicePage()) {
controllers.add(new BluetoothDetailsHearingDeviceControlsController(context, this,
mCachedDevice, lifecycle));
}
controllers.add(new BluetoothDetailsDataSyncController(context, this,
mCachedDevice, lifecycle));
controllers.add(
@@ -348,6 +353,16 @@ public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment
return width;
}
private boolean isLaunchFromHearingDevicePage() {
final Intent intent = getIntent();
if (intent == null) {
return false;
}
return intent.getIntExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY,
SettingsEnums.PAGE_UNKNOWN) == SettingsEnums.ACCESSIBILITY_HEARING_AID_SETTINGS;
}
@VisibleForTesting
void setTitleForInputDevice() {
if (StylusDevicesController.isDeviceStylus(mInputDevice, mCachedDevice)) {

View File

@@ -18,6 +18,7 @@ package com.android.settings.fuelgauge;
import android.content.Context;
import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
import java.util.List;
@@ -35,5 +36,9 @@ public interface BatterySettingsFeatureProvider {
boolean isBatteryInfoEnabled(Context context);
/** A way to add more battery tip detectors. */
void addBatteryTipDetector(Context context, List<BatteryTip> tips, BatteryInfo batteryInfo);
void addBatteryTipDetector(
Context context,
List<BatteryTip> batteryTips,
BatteryInfo batteryInfo,
BatteryTipPolicy batteryTipPolicy);
}

View File

@@ -18,6 +18,8 @@ package com.android.settings.fuelgauge;
import android.content.Context;
import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
import com.android.settings.fuelgauge.batterytip.detectors.LowBatteryDetector;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
import java.util.List;
@@ -42,5 +44,10 @@ public class BatterySettingsFeatureProviderImpl implements BatterySettingsFeatur
@Override
public void addBatteryTipDetector(
Context context, List<BatteryTip> tips, BatteryInfo batteryInfo) {}
Context context,
List<BatteryTip> batteryTips,
BatteryInfo batteryInfo,
BatteryTipPolicy batteryTipPolicy) {
batteryTips.add(new LowBatteryDetector(context, batteryTipPolicy, batteryInfo).detect());
}
}

View File

@@ -18,7 +18,6 @@ package com.android.settings.fuelgauge.batterytip;
import android.content.Context;
import android.os.BatteryUsageStats;
import android.os.PowerManager;
import androidx.annotation.VisibleForTesting;
@@ -27,7 +26,6 @@ import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.fuelgauge.batterytip.detectors.BatteryDefenderDetector;
import com.android.settings.fuelgauge.batterytip.detectors.HighUsageDetector;
import com.android.settings.fuelgauge.batterytip.detectors.IncompatibleChargerDetector;
import com.android.settings.fuelgauge.batterytip.detectors.LowBatteryDetector;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.utils.AsyncLoaderCompat;
@@ -56,19 +54,18 @@ public class BatteryTipLoader extends AsyncLoaderCompat<List<BatteryTip>> {
@Override
public List<BatteryTip> loadInBackground() {
final List<BatteryTip> tips = new ArrayList<>();
final BatteryTipPolicy policy = new BatteryTipPolicy(getContext());
final BatteryTipPolicy batteryTipPolicy = new BatteryTipPolicy(getContext());
final BatteryInfo batteryInfo = mBatteryUtils.getBatteryInfo(TAG);
final Context context = getContext().getApplicationContext();
final boolean isPowerSaveMode =
context.getSystemService(PowerManager.class).isPowerSaveMode();
tips.add(new LowBatteryDetector(context, policy, batteryInfo, isPowerSaveMode).detect());
tips.add(new HighUsageDetector(context, policy, mBatteryUsageStats, batteryInfo).detect());
tips.add(
new HighUsageDetector(context, batteryTipPolicy, mBatteryUsageStats, batteryInfo)
.detect());
tips.add(new BatteryDefenderDetector(batteryInfo, context).detect());
tips.add(new IncompatibleChargerDetector(context).detect());
FeatureFactory.getFeatureFactory()
.getBatterySettingsFeatureProvider()
.addBatteryTipDetector(context, tips, batteryInfo);
.addBatteryTipDetector(context, tips, batteryInfo, batteryTipPolicy);
Collections.sort(tips);
return tips;
}

View File

@@ -17,6 +17,7 @@
package com.android.settings.fuelgauge.batterytip.detectors;
import android.content.Context;
import android.os.PowerManager;
import com.android.settings.fuelgauge.BatteryInfo;
import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
@@ -26,37 +27,33 @@ import com.android.settings.fuelgauge.batterytip.tips.LowBatteryTip;
/** Detect whether the battery is too low */
public class LowBatteryDetector implements BatteryTipDetector {
private final BatteryInfo mBatteryInfo;
private final BatteryTipPolicy mPolicy;
private final BatteryTipPolicy mBatteryTipPolicy;
private final boolean mIsPowerSaveMode;
private final int mWarningLevel;
public LowBatteryDetector(
Context context,
BatteryTipPolicy policy,
BatteryInfo batteryInfo,
boolean isPowerSaveMode) {
mPolicy = policy;
Context context, BatteryTipPolicy batteryTipPolicy, BatteryInfo batteryInfo) {
mBatteryTipPolicy = batteryTipPolicy;
mBatteryInfo = batteryInfo;
mWarningLevel =
context.getResources()
.getInteger(com.android.internal.R.integer.config_lowBatteryWarningLevel);
mIsPowerSaveMode = isPowerSaveMode;
mIsPowerSaveMode = context.getSystemService(PowerManager.class).isPowerSaveMode();
}
@Override
public BatteryTip detect() {
final boolean lowBattery = mBatteryInfo.batteryLevel <= mWarningLevel;
final boolean lowBatteryEnabled = mPolicy.lowBatteryEnabled && !mIsPowerSaveMode;
final boolean lowBatteryEnabled = mBatteryTipPolicy.lowBatteryEnabled && !mIsPowerSaveMode;
final boolean dischargingLowBatteryState =
mPolicy.testLowBatteryTip || (mBatteryInfo.discharging && lowBattery);
int state = BatteryTip.StateType.INVISIBLE;
mBatteryTipPolicy.testLowBatteryTip || (mBatteryInfo.discharging && lowBattery);
// Show it as new if in test or in discharging low battery state,
// dismiss it if battery saver is on or disabled by config.
if (lowBatteryEnabled && dischargingLowBatteryState) {
state = BatteryTip.StateType.NEW;
}
final int state =
lowBatteryEnabled && dischargingLowBatteryState
? BatteryTip.StateType.NEW
: BatteryTip.StateType.INVISIBLE;
return new LowBatteryTip(state, mIsPowerSaveMode);
}

View File

@@ -16,12 +16,14 @@
package com.android.settings.fuelgauge.batterytip.tips;
import android.app.Activity;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.Intent;
import android.os.Parcel;
import android.util.Log;
import androidx.core.app.ActivityCompat;
import androidx.preference.Preference;
import com.android.settings.R;
@@ -30,6 +32,8 @@ import com.android.settings.widget.CardPreference;
import com.android.settingslib.HelpUtils;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import kotlin.Unit;
/** Tip to show current battery is overheated */
public class BatteryDefenderTip extends BatteryTip {
@@ -83,28 +87,39 @@ public class BatteryDefenderTip extends BatteryTip {
}
cardPreference.setSelectable(false);
cardPreference.setIconResId(getIconId());
cardPreference.setPrimaryButtonText(context.getString(R.string.learn_more));
cardPreference.setPrimaryButtonClickListener(
button ->
button.startActivityForResult(
HelpUtils.getHelpIntent(
context,
context.getString(R.string.help_url_battery_defender),
/* backupContext */ ""), /* requestCode */
0));
cardPreference.setPrimaryButtonVisible(true);
cardPreference.setPrimaryButtonAction(
() -> {
var helpIntent =
HelpUtils.getHelpIntent(
context,
context.getString(R.string.help_url_battery_defender),
/* backupContext= */ "");
ActivityCompat.startActivityForResult(
(Activity) preference.getContext(),
helpIntent,
/* requestCode= */ 0,
/* options= */ null);
return Unit.INSTANCE;
});
cardPreference.setPrimaryButtonVisibility(true);
cardPreference.setPrimaryButtonContentDescription(
context.getString(
R.string.battery_tip_limited_temporarily_sec_button_content_description));
cardPreference.setSecondaryButtonText(
context.getString(R.string.battery_tip_charge_to_full_button));
cardPreference.setSecondaryButtonClickListener(
unused -> {
cardPreference.setSecondaryButtonAction(
() -> {
resumeCharging(context);
preference.setVisible(false);
return Unit.INSTANCE;
});
cardPreference.setSecondaryButtonVisible(mIsPluggedIn);
cardPreference.setSecondaryButtonVisibility(mIsPluggedIn);
cardPreference.buildContent();
}
private void resumeCharging(Context context) {

View File

@@ -16,11 +16,13 @@
package com.android.settings.fuelgauge.batterytip.tips;
import android.app.Activity;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.os.Parcel;
import android.util.Log;
import androidx.core.app.ActivityCompat;
import androidx.preference.Preference;
import com.android.settings.R;
@@ -28,6 +30,8 @@ import com.android.settings.widget.CardPreference;
import com.android.settingslib.HelpUtils;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import kotlin.Unit;
/** Tip to show incompatible charger state */
public final class IncompatibleChargerTip extends BatteryTip {
private static final String TAG = "IncompatibleChargerTip";
@@ -77,18 +81,27 @@ public final class IncompatibleChargerTip extends BatteryTip {
}
cardPreference.setSelectable(false);
cardPreference.setIconResId(getIconId());
cardPreference.setPrimaryButtonText(context.getString(R.string.learn_more));
cardPreference.setPrimaryButtonClickListener(
button ->
button.startActivityForResult(
HelpUtils.getHelpIntent(
context,
context.getString(R.string.help_url_incompatible_charging),
/* backupContext */ ""), /* requestCode */
0));
cardPreference.setPrimaryButtonVisible(true);
cardPreference.setPrimaryButtonAction(
() -> {
var helpIntent =
HelpUtils.getHelpIntent(
context,
context.getString(R.string.help_url_incompatible_charging),
/* backupContext */ "");
ActivityCompat.startActivityForResult(
(Activity) context,
helpIntent,
/* requestCode= */ 0,
/* options= */ null);
return Unit.INSTANCE;
});
cardPreference.setPrimaryButtonVisibility(true);
cardPreference.setPrimaryButtonContentDescription(
context.getString(R.string.battery_tip_incompatible_charging_content_description));
cardPreference.buildContent();
}
public static final Creator CREATOR =

View File

@@ -1,170 +0,0 @@
/*
* Copyright (C) 2019 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.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Button;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import com.android.settings.R;
import com.google.android.material.card.MaterialCardView;
import java.util.Optional;
/** Preference that wrapped by {@link MaterialCardView} */
public class CardPreference extends Preference {
private View.OnClickListener mPrimaryBtnClickListener = null;
private View.OnClickListener mSecondaryBtnClickListener = null;
private String mPrimaryButtonText = null;
private String mSecondaryButtonText = null;
private Optional<Button> mPrimaryButton = Optional.empty();
private Optional<Button> mSecondaryButton = Optional.empty();
private Optional<View> mButtonsGroup = Optional.empty();
private boolean mPrimaryButtonVisible = false;
private boolean mSecondaryButtonVisible = false;
public CardPreference(Context context) {
this(context, null /* attrs */);
}
public CardPreference(Context context, AttributeSet attrs) {
super(context, attrs, R.attr.cardPreferenceStyle);
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
initButtonsAndLayout(holder);
}
private void initButtonsAndLayout(PreferenceViewHolder holder) {
mPrimaryButton = Optional.ofNullable((Button) holder.findViewById(android.R.id.button1));
mSecondaryButton = Optional.ofNullable((Button) holder.findViewById(android.R.id.button2));
mButtonsGroup = Optional.ofNullable(holder.findViewById(R.id.card_preference_buttons));
setPrimaryButtonText(mPrimaryButtonText);
setPrimaryButtonClickListener(mPrimaryBtnClickListener);
setPrimaryButtonVisible(mPrimaryButtonVisible);
setSecondaryButtonText(mSecondaryButtonText);
setSecondaryButtonClickListener(mSecondaryBtnClickListener);
setSecondaryButtonVisible(mSecondaryButtonVisible);
}
/** Clear layout state if needed */
public void resetLayoutState() {
setPrimaryButtonVisible(false);
setSecondaryButtonVisible(false);
}
/**
* Register a callback to be invoked when the primary button is clicked.
*
* @param l the callback that will run
*/
public void setPrimaryButtonClickListener(View.OnClickListener l) {
mPrimaryButton.ifPresent(button -> button.setOnClickListener(l));
mPrimaryBtnClickListener = l;
}
/**
* Register a callback to be invoked when the secondary button is clicked.
*
* @param l the callback that will run
*/
public void setSecondaryButtonClickListener(View.OnClickListener l) {
mSecondaryButton.ifPresent(button -> button.setOnClickListener(l));
mSecondaryBtnClickListener = l;
}
/**
* Sets the text to be displayed on primary button.
*
* @param text text to be displayed
*/
public void setPrimaryButtonText(String text) {
mPrimaryButton.ifPresent(button -> button.setText(text));
mPrimaryButtonText = text;
}
/**
* Sets the text to be displayed on secondary button.
*
* @param text text to be displayed
*/
public void setSecondaryButtonText(String text) {
mSecondaryButton.ifPresent(button -> button.setText(text));
mSecondaryButtonText = text;
}
/**
* Set the visible on the primary button.
*
* @param visible {@code true} for visible
*/
public void setPrimaryButtonVisible(boolean visible) {
mPrimaryButton.ifPresent(
button -> button.setVisibility(visible ? View.VISIBLE : View.GONE));
mPrimaryButtonVisible = visible;
updateButtonGroupsVisibility();
}
/**
* Set the visible on the secondary button.
*
* @param visible {@code true} for visible
*/
public void setSecondaryButtonVisible(boolean visible) {
mSecondaryButton.ifPresent(
button -> button.setVisibility(visible ? View.VISIBLE : View.GONE));
mSecondaryButtonVisible = visible;
updateButtonGroupsVisibility();
}
/**
* Sets the text of content description on primary button.
*
* @param text text for the content description
*/
public void setPrimaryButtonContentDescription(String text) {
mPrimaryButton.ifPresent(button -> button.setContentDescription(text));
}
/**
* Sets the text of content description on secondary button.
*
* @param text text for the content description
*/
public void setSecondaryButtonContentDescription(String text) {
mSecondaryButton.ifPresent(button -> button.setContentDescription(text));
}
private void updateButtonGroupsVisibility() {
int visibility =
(mPrimaryButtonVisible || mSecondaryButtonVisible) ? View.VISIBLE : View.GONE;
mButtonsGroup.ifPresent(group -> group.setVisibility(visibility));
}
}

View File

@@ -0,0 +1,119 @@
/*
* Copyright (C) 2024 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.widget
import android.content.Context
import android.content.res.Resources
import android.util.AttributeSet
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.vectorResource
import com.android.settings.spa.preference.ComposePreference
import com.android.settingslib.spa.widget.card.CardButton
import com.android.settingslib.spa.widget.card.CardModel
import com.android.settingslib.spa.widget.card.SettingsCard
/** A preference for settings banner tips card. */
class CardPreference
@JvmOverloads
constructor(
context: Context,
attr: AttributeSet? = null,
) : ComposePreference(context, attr) {
/** A icon resource id for displaying icon on tips card. */
var iconResId: Int? = null
/** The primary button's text. */
var primaryButtonText: String = ""
/** The accessibility content description of the primary button. */
var primaryButtonContentDescription: String? = null
/** The action for click on primary button. */
var primaryButtonAction: () -> Unit = {}
/** The visibility of primary button on tips card. The default value is `false`. */
var primaryButtonVisibility: Boolean = false
/** The text on the second button of this [SettingsCard]. */
var secondaryButtonText: String = ""
/** The accessibility content description of the secondary button. */
var secondaryButtonContentDescription: String? = null
/** The action for click on secondary button. */
var secondaryButtonAction: () -> Unit = {}
/** The visibility of secondary button on tips card. The default value is `false`. */
var secondaryButtonVisibility: Boolean = false
private var onDismiss: (() -> Unit)? = null
/** Enable the dismiss button on tips card. */
fun enableDismiss(enable: Boolean) =
if (enable) onDismiss = { isVisible = false } else onDismiss = null
/** Clear layout state if needed. */
fun resetLayoutState() {
primaryButtonVisibility = false
secondaryButtonVisibility = false
notifyChanged()
}
/** Build the tips card content to apply any changes of this card's property. */
fun buildContent() {
setContent {
SettingsCard(
CardModel(
title = title?.toString() ?: "",
text = summary?.toString() ?: "",
buttons = listOfNotNull(configPrimaryButton(), configSecondaryButton()),
onDismiss = onDismiss,
imageVector =
iconResId
?.takeIf { it != Resources.ID_NULL }
?.let { ImageVector.vectorResource(it) },
)
)
}
}
private fun configPrimaryButton(): CardButton? {
return if (primaryButtonVisibility)
CardButton(
text = primaryButtonText,
contentDescription = primaryButtonContentDescription,
onClick = primaryButtonAction,
)
else null
}
private fun configSecondaryButton(): CardButton? {
return if (secondaryButtonVisibility)
CardButton(
text = secondaryButtonText,
contentDescription = secondaryButtonContentDescription,
onClick = secondaryButtonAction,
)
else null
}
override fun notifyChanged() {
buildContent()
super.notifyChanged()
}
}

View File

@@ -18,6 +18,8 @@ package com.android.settings.bluetooth;
import static android.bluetooth.BluetoothDevice.BOND_NONE;
import static com.android.settings.bluetooth.BluetoothDetailsHearingDeviceControlsController.KEY_DEVICE_CONTROLS_GENERAL_GROUP;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -29,8 +31,10 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.settings.SettingsEnums;
import android.companion.CompanionDeviceManager;
import android.content.Context;
import android.content.Intent;
import android.hardware.input.InputManager;
import android.os.Bundle;
import android.os.UserManager;
@@ -49,6 +53,8 @@ import com.android.settings.R;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.google.common.collect.ImmutableList;
@@ -65,6 +71,8 @@ import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.fakes.RoboMenu;
import java.util.List;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {
com.android.settings.testutils.shadow.ShadowUserManager.class,
@@ -216,6 +224,38 @@ public class BluetoothDeviceDetailsFragmentTest {
verify(mFragment).finish();
}
@Test
public void createPreferenceControllers_launchFromHAPage_deviceControllerNotExist() {
BluetoothDeviceDetailsFragment fragment = setupFragment();
Intent intent = fragment.getActivity().getIntent();
intent.putExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY,
SettingsEnums.ACCESSIBILITY_HEARING_AID_SETTINGS);
fragment.onAttach(mContext);
List<AbstractPreferenceController> controllerList = fragment.createPreferenceControllers(
mContext);
assertThat(controllerList.stream()
.anyMatch(controller -> controller.getPreferenceKey().equals(
KEY_DEVICE_CONTROLS_GENERAL_GROUP))).isFalse();
}
@Test
public void createPreferenceControllers_notLaunchFromHAPage_deviceControllerExist() {
BluetoothDeviceDetailsFragment fragment = setupFragment();
Intent intent = fragment.getActivity().getIntent();
intent.putExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY,
SettingsEnums.PAGE_UNKNOWN);
fragment.onAttach(mContext);
List<AbstractPreferenceController> controllerList = fragment.createPreferenceControllers(
mContext);
assertThat(controllerList.stream()
.anyMatch(controller -> controller.getPreferenceKey().equals(
KEY_DEVICE_CONTROLS_GENERAL_GROUP))).isTrue();
}
private InputDevice createInputDeviceWithMatchingBluetoothAddress() {
doReturn(new int[]{0}).when(mInputManager).getInputDeviceIds();
InputDevice device = mock(InputDevice.class);

View File

@@ -22,11 +22,17 @@ import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
import com.android.settings.fuelgauge.batterytip.tips.LowBatteryTip;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import java.util.ArrayList;
@RunWith(RobolectricTestRunner.class)
public class BatterySettingsFeatureProviderImplTest {
private BatterySettingsFeatureProviderImpl mImpl;
@@ -52,4 +58,15 @@ public class BatterySettingsFeatureProviderImplTest {
public void isBatteryInfoEnabled_returnFalse() {
assertThat(mImpl.isBatteryInfoEnabled(mContext)).isFalse();
}
@Test
public void addBatteryTipDetector_containsLowBatteryTip() {
var tips = new ArrayList<BatteryTip>();
mImpl.addBatteryTipDetector(
mContext, tips, new BatteryInfo(), new BatteryTipPolicy(mContext));
var expectedResult = tips.stream().anyMatch(tip -> tip instanceof LowBatteryTip);
assertThat(expectedResult).isTrue();
}
}

View File

@@ -19,20 +19,25 @@ package com.android.settings.fuelgauge.batterytip.detectors;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
import static org.robolectric.Shadows.shadowOf;
import android.content.Context;
import android.os.PowerManager;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.fuelgauge.BatteryInfo;
import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.util.ReflectionHelpers;
import java.util.concurrent.TimeUnit;
@@ -40,73 +45,79 @@ import java.util.concurrent.TimeUnit;
@RunWith(RobolectricTestRunner.class)
public class LowBatteryDetectorTest {
@Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
@Mock private BatteryInfo mBatteryInfo;
private BatteryTipPolicy mPolicy;
private BatteryTipPolicy mBatteryTipPolicy;
private LowBatteryDetector mLowBatteryDetector;
private Context mContext;
private PowerManager mPowerManager;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = ApplicationProvider.getApplicationContext();
mBatteryTipPolicy = spy(new BatteryTipPolicy(mContext));
mPolicy = spy(new BatteryTipPolicy(RuntimeEnvironment.application));
mContext = RuntimeEnvironment.application;
ReflectionHelpers.setField(mPolicy, "lowBatteryEnabled", true);
mPowerManager = mContext.getSystemService(PowerManager.class);
shadowOf(mPowerManager).setIsPowerSaveMode(false);
ReflectionHelpers.setField(mBatteryTipPolicy, "lowBatteryEnabled", true);
mBatteryInfo.discharging = true;
mLowBatteryDetector =
new LowBatteryDetector(
mContext, mPolicy, mBatteryInfo, false /* isPowerSaveMode */);
mLowBatteryDetector = new LowBatteryDetector(mContext, mBatteryTipPolicy, mBatteryInfo);
}
@Test
public void testDetect_disabledByPolicy_tipInvisible() {
ReflectionHelpers.setField(mPolicy, "lowBatteryEnabled", false);
mLowBatteryDetector =
new LowBatteryDetector(mContext, mPolicy, mBatteryInfo, true /* isPowerSaveMode */);
public void detect_disabledByPolicy_tipInvisible() {
ReflectionHelpers.setField(mBatteryTipPolicy, "lowBatteryEnabled", false);
shadowOf(mPowerManager).setIsPowerSaveMode(true);
mLowBatteryDetector = new LowBatteryDetector(mContext, mBatteryTipPolicy, mBatteryInfo);
assertThat(mLowBatteryDetector.detect().isVisible()).isFalse();
}
@Test
public void testDetect_enabledByTest_tipNew() {
ReflectionHelpers.setField(mPolicy, "testLowBatteryTip", true);
public void detect_enabledByTest_tipNew() {
ReflectionHelpers.setField(mBatteryTipPolicy, "testLowBatteryTip", true);
assertThat(mLowBatteryDetector.detect().getState()).isEqualTo(BatteryTip.StateType.NEW);
}
@Test
public void testDetect_lowBattery_tipNew() {
public void detect_lowBattery_tipNew() {
mBatteryInfo.batteryLevel = 20;
mBatteryInfo.remainingTimeUs = TimeUnit.DAYS.toMillis(1);
assertThat(mLowBatteryDetector.detect().getState()).isEqualTo(BatteryTip.StateType.NEW);
}
@Test
public void testDetect_batterySaverOn_tipInvisible() {
mLowBatteryDetector =
new LowBatteryDetector(mContext, mPolicy, mBatteryInfo, true /* isPowerSaveMode */);
public void detect_batterySaverOn_tipInvisible() {
shadowOf(mPowerManager).setIsPowerSaveMode(true);
mLowBatteryDetector = new LowBatteryDetector(mContext, mBatteryTipPolicy, mBatteryInfo);
assertThat(mLowBatteryDetector.detect().getState())
.isEqualTo(BatteryTip.StateType.INVISIBLE);
}
@Test
public void testDetect_charging_tipInvisible() {
public void detect_charging_tipInvisible() {
mBatteryInfo.discharging = false;
assertThat(mLowBatteryDetector.detect().isVisible()).isFalse();
}
@Test
public void testDetect_lowTimeEstimation_tipInvisible() {
public void detect_lowTimeEstimation_tipInvisible() {
mBatteryInfo.batteryLevel = 50;
mBatteryInfo.remainingTimeUs = TimeUnit.MINUTES.toMillis(1);
assertThat(mLowBatteryDetector.detect().isVisible()).isFalse();
}
@Test
public void testDetect_noEarlyWarning_tipInvisible() {
public void detect_noEarlyWarning_tipInvisible() {
mBatteryInfo.remainingTimeUs = TimeUnit.DAYS.toMicros(1);
mBatteryInfo.batteryLevel = 100;

View File

@@ -124,7 +124,7 @@ public class BatteryDefenderTipTest {
public void updatePreference_shouldSetPrimaryButtonVisible() {
mBatteryDefenderTip.updatePreference(mCardPreference);
verify(mCardPreference).setPrimaryButtonVisible(true);
verify(mCardPreference).setPrimaryButtonVisibility(true);
}
@Test
@@ -134,14 +134,14 @@ public class BatteryDefenderTipTest {
mBatteryDefenderTip.updatePreference(mCardPreference);
verify(mCardPreference).setPrimaryButtonVisible(true);
verify(mCardPreference).setPrimaryButtonVisibility(true);
}
@Test
public void updatePreference_whenNotCharging_setSecondaryButtonVisibleToBeFalse() {
mBatteryDefenderTip.updatePreference(mCardPreference);
verify(mCardPreference).setSecondaryButtonVisible(false);
verify(mCardPreference).setSecondaryButtonVisibility(false);
}
@Test
@@ -150,7 +150,7 @@ public class BatteryDefenderTipTest {
mBatteryDefenderTip.updatePreference(mCardPreference);
verify(mCardPreference).setSecondaryButtonVisible(false);
verify(mCardPreference).setSecondaryButtonVisibility(false);
}
private void fakeGetChargingStatusFailed() {

View File

@@ -91,7 +91,7 @@ public class BatteryTipTest {
mContext, R.layout.card_preference_layout, /* parent= */ null));
CardPreference cardPreference = new CardPreference(mContext);
cardPreference.onBindViewHolder(holder);
cardPreference.setPrimaryButtonVisible(true);
cardPreference.setPrimaryButtonVisibility(true);
mBatteryTip.updatePreference(cardPreference);

View File

@@ -113,7 +113,7 @@ public final class IncompatibleChargerTipTest {
@Test
public void updatePreference_shouldSetSecondaryButtonVisible() {
mIncompatibleChargerTip.updatePreference(mCardPreference);
verify(mCardPreference).setPrimaryButtonVisible(true);
verify(mCardPreference).setPrimaryButtonVisibility(true);
}
private String getLastErrorLog() {

View File

@@ -1,344 +0,0 @@
/*
* Copyright (C) 2019 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
*Visibility_setGoneForPrimaryButton_buttonGroupIsGone
* 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.widget;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import android.content.Context;
import android.view.View;
import android.widget.Button;
import androidx.preference.PreferenceViewHolder;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
@RunWith(RobolectricTestRunner.class)
public class CardPreferenceTest {
private CardPreference mCardPreference;
private PreferenceViewHolder mHolder;
@Before
public void setUp() {
Context context = ApplicationProvider.getApplicationContext();
context.setTheme(R.style.Theme_Settings);
mCardPreference = new CardPreference(context);
mHolder = PreferenceViewHolder.createInstanceForTests(
View.inflate(context, R.layout.card_preference_layout, /* parent= */ null));
}
@Test
public void newACardPreference_layoutResourceShouldBeCardPreferenceLayout() {
Context context = ApplicationProvider.getApplicationContext();
context.setTheme(R.style.SettingsPreferenceTheme);
CardPreference cardPreference = new CardPreference(context);
assertThat(cardPreference.getLayoutResource()).isEqualTo(R.layout.card_preference_layout);
}
@Test
public void onBindViewHolder_noButtonVisible_buttonsLayoutIsGone() {
mCardPreference.onBindViewHolder(mHolder);
assertThat(getCardPreferenceButtonsView().getVisibility()).isEqualTo(GONE);
}
@Test
public void onBindViewHolder_setPrimaryButtonVisibility_buttonsLayoutIsVisible() {
mCardPreference.setPrimaryButtonVisible(true);
mCardPreference.onBindViewHolder(mHolder);
assertThat(getCardPreferenceButtonsView().getVisibility()).isEqualTo(VISIBLE);
}
@Test
public void onBindViewHolder_setPrimaryButtonVisibilityToVisible() {
mCardPreference.setPrimaryButtonVisible(true);
mCardPreference.onBindViewHolder(mHolder);
assertThat(getPrimaryButton().getVisibility()).isEqualTo(VISIBLE);
}
@Test
public void onBindViewHolder_setSecondaryButtonVisibility_buttonsLayoutIsVisible() {
mCardPreference.setSecondaryButtonVisible(true);
mCardPreference.onBindViewHolder(mHolder);
assertThat(getCardPreferenceButtonsView().getVisibility()).isEqualTo(VISIBLE);
}
@Test
public void onBindViewHolder_setSecondaryButtonVisibilityToVisible() {
mCardPreference.setSecondaryButtonVisible(true);
mCardPreference.onBindViewHolder(mHolder);
assertThat(getSecondaryButton().getVisibility()).isEqualTo(VISIBLE);
}
@Test
public void onBindViewHolder_setPrimaryButtonTextToExpectedText() {
String expectedText = "primary-button";
mCardPreference.setPrimaryButtonText(expectedText);
mCardPreference.onBindViewHolder(mHolder);
assertThat(getPrimaryButton().getText().toString()).isEqualTo(expectedText);
}
@Test
public void onBindViewHolder_setSecondaryButtonTextToExpectedText() {
String expectedText = "secondary-button";
mCardPreference.setSecondaryButtonText(expectedText);
mCardPreference.onBindViewHolder(mHolder);
assertThat(getSecondaryButton().getText().toString()).isEqualTo(expectedText);
}
@Test
public void onBindViewHolder_initialTextForPrimaryButtonShouldBeEmpty() {
mCardPreference.onBindViewHolder(mHolder);
assertThat(getPrimaryButton().getText().toString()).isEqualTo("");
}
@Test
public void onBindViewHolder_initialTextForSecondaryButtonShouldBeEmpty() {
mCardPreference.onBindViewHolder(mHolder);
assertThat(getSecondaryButton().getText().toString()).isEqualTo("");
}
@Test
public void performClickOnPrimaryButton_callClickListener() {
final boolean[] hasCalled = {false};
View.OnClickListener clickListener = v -> hasCalled[0] = true;
mCardPreference.setPrimaryButtonClickListener(clickListener);
mCardPreference.onBindViewHolder(mHolder);
getPrimaryButton().performClick();
assertThat(hasCalled[0]).isTrue();
}
@Test
public void performClickOnSecondaryButton_callClickListener() {
final boolean[] hasCalled = {false};
View.OnClickListener clickListener = v -> hasCalled[0] = true;
mCardPreference.setSecondaryButtonClickListener(clickListener);
mCardPreference.onBindViewHolder(mHolder);
getSecondaryButton().performClick();
assertThat(hasCalled[0]).isTrue();
}
@Test
public void onBindViewHolder_primaryButtonDefaultIsGone() {
mCardPreference.onBindViewHolder(mHolder);
assertThat(getPrimaryButton().getVisibility()).isEqualTo(GONE);
}
@Test
public void onBindViewHolder_secondaryButtonDefaultIsGone() {
mCardPreference.onBindViewHolder(mHolder);
assertThat(getSecondaryButton().getVisibility()).isEqualTo(GONE);
}
@Test
public void setPrimaryButtonVisibility_setTrueAfterBindViewHolder_isVisible() {
mCardPreference.setPrimaryButtonVisible(false);
mCardPreference.onBindViewHolder(mHolder);
mCardPreference.setPrimaryButtonVisible(true);
assertThat(getPrimaryButton().getVisibility()).isEqualTo(VISIBLE);
}
@Test
public void setPrimaryButtonText_setAfterBindViewHolder_setOnUi() {
String expectedText = "123456";
mCardPreference.onBindViewHolder(mHolder);
mCardPreference.setPrimaryButtonText(expectedText);
assertThat(getPrimaryButton().getText().toString()).isEqualTo(expectedText);
}
@Test
public void setPrimaryButtonText_setNull_isEmptyText() {
final String emptyString = "";
mCardPreference.setPrimaryButtonText("1234");
mCardPreference.onBindViewHolder(mHolder);
mCardPreference.setPrimaryButtonText(null);
assertThat(getPrimaryButton().getText().toString()).isEqualTo(emptyString);
}
@Test
public void setPrimaryButtonClickListener_setAfterOnBindViewHolder() {
final String[] hasCalled = {""};
String expectedClickedResult = "was called";
View.OnClickListener clickListener = v -> hasCalled[0] = expectedClickedResult;
mCardPreference.onBindViewHolder(mHolder);
mCardPreference.setPrimaryButtonClickListener(clickListener);
getPrimaryButton().performClick();
assertThat(hasCalled[0]).isEqualTo(expectedClickedResult);
}
@Test
public void setPrimaryButtonClickListener_setNull_clearTheOnClickListener() {
final String[] hasCalled = {"not called"};
View.OnClickListener clickListener = v -> hasCalled[0] = "called once";
mCardPreference.setPrimaryButtonClickListener(clickListener);
mCardPreference.onBindViewHolder(mHolder);
mCardPreference.setPrimaryButtonClickListener(null);
getPrimaryButton().performClick();
assertThat(hasCalled[0]).isEqualTo("not called");
}
@Test
public void setSecondaryButtonVisibility_setTrueAfterBindViewHolder_isVisible() {
mCardPreference.setSecondaryButtonVisible(false);
mCardPreference.onBindViewHolder(mHolder);
mCardPreference.setSecondaryButtonVisible(true);
assertThat(getSecondaryButton().getVisibility()).isEqualTo(VISIBLE);
}
@Test
public void setSecondaryButtonText_setAfterBindViewHolder_setOnUi() {
String expectedText = "10101010";
mCardPreference.onBindViewHolder(mHolder);
mCardPreference.setSecondaryButtonText(expectedText);
assertThat(getSecondaryButton().getText().toString()).isEqualTo(expectedText);
}
@Test
public void setSecondaryButtonText_setNull_isEmptyText() {
String emptyString = "";
mCardPreference.setSecondaryButtonText("1234");
mCardPreference.onBindViewHolder(mHolder);
mCardPreference.setSecondaryButtonText(null);
assertThat(getSecondaryButton().getText().toString()).isEqualTo(emptyString);
}
@Test
public void setSecondaryButtonClickListener_setAfterOnBindViewHolder() {
final String[] hasCalled = {""};
String expectedClickedResult = "2nd was called";
View.OnClickListener clickListener = v -> hasCalled[0] = expectedClickedResult;
mCardPreference.onBindViewHolder(mHolder);
mCardPreference.setSecondaryButtonClickListener(clickListener);
getSecondaryButton().performClick();
assertThat(hasCalled[0]).isEqualTo(expectedClickedResult);
}
@Test
public void setSecondaryButtonClickListener_setNull_clearTheOnClickListener() {
final String[] hasCalled = {"not called"};
View.OnClickListener clickListener = v -> hasCalled[0] = "called once";
mCardPreference.setSecondaryButtonClickListener(clickListener);
mCardPreference.onBindViewHolder(mHolder);
mCardPreference.setSecondaryButtonClickListener(null);
getSecondaryButton().performClick();
assertThat(hasCalled[0]).isEqualTo("not called");
}
@Test
public void setPrimaryButtonVisibility_setGoneForSecondaryButton_buttonGroupIsGone() {
mCardPreference.setPrimaryButtonVisible(true);
mCardPreference.setSecondaryButtonVisible(false);
mCardPreference.onBindViewHolder(mHolder);
assertWithMessage("PreCondition: buttonsView should be Visible")
.that(getCardPreferenceButtonsView().getVisibility())
.isEqualTo(VISIBLE);
mCardPreference.setPrimaryButtonVisible(false);
assertThat(getCardPreferenceButtonsView().getVisibility()).isEqualTo(GONE);
}
@Test
public void setSecondaryButtonVisibility_setGoneForPrimaryButton_buttonGroupIsGone() {
mCardPreference.setPrimaryButtonVisible(false);
mCardPreference.setSecondaryButtonVisible(true);
mCardPreference.onBindViewHolder(mHolder);
assertWithMessage("PreCondition: buttonsView should be Visible")
.that(getCardPreferenceButtonsView().getVisibility())
.isEqualTo(VISIBLE);
mCardPreference.setSecondaryButtonVisible(false);
assertThat(getCardPreferenceButtonsView().getVisibility()).isEqualTo(GONE);
}
@Test
public void resetLayoutState_buttonGroupIsGone() {
mCardPreference.setPrimaryButtonVisible(true);
mCardPreference.setSecondaryButtonVisible(true);
mCardPreference.onBindViewHolder(mHolder);
mCardPreference.resetLayoutState();
assertThat(getCardPreferenceButtonsView().getVisibility()).isEqualTo(GONE);
}
private View getCardPreferenceButtonsView() {
return mHolder.findViewById(R.id.card_preference_buttons);
}
private Button getPrimaryButton() {
return (Button) mHolder.findViewById(android.R.id.button1);
}
private Button getSecondaryButton() {
return (Button) mHolder.findViewById(android.R.id.button2);
}
}

View File

@@ -0,0 +1,240 @@
/*
* Copyright (C) 2024 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.widget
import android.content.Context
import androidx.compose.runtime.Composable
import androidx.compose.ui.test.assertContentDescriptionEquals
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsNotDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.R
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class CardPreferenceTest {
@get:Rule val composeTestRule = createComposeRule()
private lateinit var context: Context
@Before
fun setUp() {
context = ApplicationProvider.getApplicationContext()
}
@Test
fun enableDismiss_whenEnable_shouldBeDisplayed() {
composeTestRule.setContent { buildCardPreference(enableDismiss = true) }
composeTestRule.onNodeWithContentDescription("Dismiss").assertIsDisplayed()
}
@Test
fun enableDismiss_whenDisable_shouldBeDisplayed() {
composeTestRule.setContent { buildCardPreference(enableDismiss = false) }
composeTestRule.onNodeWithContentDescription("Dismiss").assertIsNotDisplayed()
}
@Test
fun primaryButton_whenVisible_shouldBeDisplayed() {
val expectedPrimaryButtonText = "You can see me"
composeTestRule.setContent {
buildCardPreference(
primaryButtonText = expectedPrimaryButtonText,
primaryButtonVisibility = true,
)
}
composeTestRule.onNodeWithText(expectedPrimaryButtonText).assertIsDisplayed()
}
@Test
fun primaryButton_whenInvisible_shouldBeDisplayed() {
val expectedButtonText = "You cannot see me"
composeTestRule.setContent {
buildCardPreference(
primaryButtonText = expectedButtonText,
primaryButtonVisibility = false,
)
}
composeTestRule.onNodeWithText(expectedButtonText).assertIsNotDisplayed()
}
@Test
fun primaryButtonAction_whenClick_performAction() {
val buttonText = "click me"
var clicked = false
composeTestRule.setContent {
buildCardPreference(
primaryButtonText = buttonText,
primaryButtonVisibility = true,
primaryButtonAction = { clicked = true }
)
}
composeTestRule.onNodeWithText(buttonText).performClick()
assertThat(clicked).isTrue()
}
@Test
fun primaryButtonContentDescription_whenSet_shouldBeExists() {
val expectedText = "this is a content description"
val buttonText = "primary-button"
composeTestRule.setContent {
buildCardPreference(
primaryButtonText = buttonText,
primaryButtonContentDescription = expectedText,
primaryButtonVisibility = true,
)
}
composeTestRule.onNodeWithText(buttonText).assertContentDescriptionEquals(expectedText)
}
@Test
fun secondaryButton_whenVisible_shouldBeDisplayed() {
val expectedSecondaryButtonText = "You can see me"
composeTestRule.setContent {
buildCardPreference(
secondaryButtonText = expectedSecondaryButtonText,
secondaryButtonVisibility = true,
)
}
composeTestRule.onNodeWithText(expectedSecondaryButtonText).assertIsDisplayed()
}
@Test
fun secondaryButton_whenInvisible_shouldBeDisplayed() {
val expectedButtonText = "You cannot see me"
composeTestRule.setContent {
buildCardPreference(
secondaryButtonText = expectedButtonText,
secondaryButtonVisibility = false,
)
}
composeTestRule.onNodeWithText(expectedButtonText).assertIsNotDisplayed()
}
@Test
fun secondaryButtonAction_whenClick_performAction() {
val buttonText = "click me2"
var clicked = false
composeTestRule.setContent {
buildCardPreference(
secondaryButtonText = buttonText,
secondaryButtonVisibility = true,
secondaryButtonAction = { clicked = true }
)
}
composeTestRule.onNodeWithText(buttonText).performClick()
assertThat(clicked).isTrue()
}
@Test
fun secondaryButtonContentDescription_whenSet_shouldBeExists() {
val expectedText = "found bug yay"
val buttonText = "secondary-button"
composeTestRule.setContent {
buildCardPreference(
secondaryButtonText = buttonText,
secondaryButtonContentDescription = expectedText,
secondaryButtonVisibility = true,
)
}
composeTestRule.onNodeWithText(buttonText).assertContentDescriptionEquals(expectedText)
}
@Test
fun resetLayoutState_shouldRemoveThePrimaryButton() {
val buttonText = "9527"
val cardPreference =
CardPreference(context)
.apply {
primaryButtonText = buttonText
primaryButtonVisibility = true
}
.also { it.buildContent() }
cardPreference.resetLayoutState()
composeTestRule.setContent { cardPreference.Content() }
composeTestRule.onNodeWithText(buttonText).assertDoesNotExist()
}
@Test
fun resetLayoutState_shouldRemoveTheSecondaryButton() {
val buttonText = "4567"
val cardPreference =
CardPreference(context)
.apply {
secondaryButtonText = buttonText
secondaryButtonVisibility = true
}
.also { it.buildContent() }
cardPreference.resetLayoutState()
composeTestRule.setContent { cardPreference.Content() }
composeTestRule.onNodeWithText(buttonText).assertDoesNotExist()
}
@Composable
private fun buildCardPreference(
iconResId: Int? = R.drawable.ic_battery_status_protected_24dp,
primaryButtonText: String = "primary text",
primaryButtonContentDescription: String? = "primary description",
primaryButtonAction: () -> Unit = {},
primaryButtonVisibility: Boolean = false,
secondaryButtonText: String = "secondary button",
secondaryButtonContentDescription: String? = null,
secondaryButtonAction: () -> Unit = {},
secondaryButtonVisibility: Boolean = false,
enableDismiss: Boolean = true,
) =
CardPreference(context)
.apply {
this.iconResId = iconResId
this.primaryButtonText = primaryButtonText
this.primaryButtonContentDescription = primaryButtonContentDescription
this.primaryButtonAction = primaryButtonAction
this.primaryButtonVisibility = primaryButtonVisibility
this.secondaryButtonText = secondaryButtonText
this.secondaryButtonContentDescription = secondaryButtonContentDescription
this.secondaryButtonAction = secondaryButtonAction
this.secondaryButtonVisibility = secondaryButtonVisibility
this.enableDismiss(enableDismiss)
}
.also { it.buildContent() }
.Content()
}

View File

@@ -17,6 +17,7 @@
package com.android.settings.applications.credentials;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
import static com.google.common.truth.Truth.assertThat;
@@ -55,6 +56,7 @@ import org.junit.runner.RunWith;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
@RunWith(AndroidJUnit4.class)
@@ -121,17 +123,34 @@ public class CredentialManagerPreferenceControllerTest {
createControllerWithServices(Lists.newArrayList(createCredentialProviderInfo()));
controller.setSimulateConnectedForTests(true);
assertThat(controller.isConnected()).isTrue();
controller.setVisibility(true);
assertThat(controller.getVisibility()).isTrue();
controller.setSimulateHiddenForTests(Optional.of(false));
assertThat(controller.isHiddenDueToNoProviderSet()).isFalse();
assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
public void getAvailabilityStatus_isHidden_returnsConditionallyUnavailable() {
CredentialManagerPreferenceController controller =
createControllerWithServices(Lists.newArrayList(createCredentialProviderInfo()));
controller.setSimulateConnectedForTests(true);
assertThat(controller.isConnected()).isTrue();
controller.setSimulateHiddenForTests(Optional.of(true));
assertThat(controller.isHiddenDueToNoProviderSet()).isTrue();
assertThat(controller.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
@Test
public void displayPreference_withServices_preferencesAdded() {
CredentialManagerPreferenceController controller =
createControllerWithServices(Lists.newArrayList(createCredentialProviderInfo()));
controller.setSimulateConnectedForTests(true);
controller.setSimulateHiddenForTests(Optional.of(false));
assertThat(controller.isHiddenDueToNoProviderSet()).isFalse();
assertThat(controller.isConnected()).isTrue();
assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
controller.displayPreference(mScreen);
assertThat(controller.isConnected()).isFalse();
assertThat(mCredentialsPreferenceCategory.getPreferenceCount()).isEqualTo(1);
Preference pref = mCredentialsPreferenceCategory.getPreference(0);
@@ -150,8 +169,8 @@ public class CredentialManagerPreferenceControllerTest {
createControllerWithServices(Lists.newArrayList(providerInfo1, providerInfo2));
controller.setSimulateConnectedForTests(true);
assertThat(controller.isConnected()).isTrue();
controller.setVisibility(true);
assertThat(controller.getVisibility()).isTrue();
controller.setSimulateHiddenForTests(Optional.of(false));
assertThat(controller.isHiddenDueToNoProviderSet()).isFalse();
assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
// Test the data is correct.
@@ -194,8 +213,8 @@ public class CredentialManagerPreferenceControllerTest {
createCredentialProviderInfo("com.android.provider6", "ClassA")));
controller.setSimulateConnectedForTests(true);
assertThat(controller.isConnected()).isTrue();
controller.setVisibility(true);
assertThat(controller.getVisibility()).isTrue();
controller.setSimulateHiddenForTests(Optional.of(false));
assertThat(controller.isHiddenDueToNoProviderSet()).isFalse();
assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
// Ensure that we stay under 5 providers.
@@ -263,8 +282,8 @@ public class CredentialManagerPreferenceControllerTest {
createControllerWithServices(Lists.newArrayList(providerInfo1, providerInfo2));
controller.setSimulateConnectedForTests(true);
assertThat(controller.isConnected()).isTrue();
controller.setVisibility(true);
assertThat(controller.getVisibility()).isTrue();
controller.setSimulateHiddenForTests(Optional.of(false));
assertThat(controller.isHiddenDueToNoProviderSet()).isFalse();
assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
// Test the data is correct.
@@ -316,9 +335,14 @@ public class CredentialManagerPreferenceControllerTest {
CredentialManagerPreferenceController controller =
createControllerWithServices(
Lists.newArrayList(serviceA1, serviceB1, serviceC1, serviceC2, serviceC3));
controller.displayPreference(mScreen);
controller.setSimulateConnectedForTests(true);
controller.setSimulateHiddenForTests(Optional.of(false));
assertThat(controller.isConnected()).isFalse();
assertThat(controller.isHiddenDueToNoProviderSet()).isFalse();
assertThat(controller.isConnected()).isTrue();
assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
controller.displayPreference(mScreen);
assertThat(mCredentialsPreferenceCategory.getPreferenceCount()).isEqualTo(3);
Map<String, CredentialManagerPreferenceController.CombiPreference> prefs =