Snap for 11401641 from 2eba5be9b4ec334bdf000cf78ab7d58a1611e1b5 to 24Q2-release
Change-Id: I57bba30c0bbb7d7a02375e7b1d531e8259fdade3
diff --git a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
index 2f04b62..4fc0e16 100644
--- a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
+++ b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
@@ -46,6 +46,7 @@
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.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 @@
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 @@
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 @@
}
@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 @@
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 @@
// 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 @@
}
// Set the visibility if we have services.
- setVisibility(!output.isEmpty());
+ forceDelegateRefresh();
return output;
}
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControlsController.java b/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControlsController.java
index 18ad210..3d85ca2 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControlsController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControlsController.java
@@ -38,7 +38,8 @@
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";
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
index 5e41a20..9c68c9c 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
@@ -22,6 +22,7 @@
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.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 @@
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 @@
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)) {
diff --git a/src/com/android/settings/fuelgauge/BatterySettingsFeatureProvider.java b/src/com/android/settings/fuelgauge/BatterySettingsFeatureProvider.java
index cc333a5..62be5df 100644
--- a/src/com/android/settings/fuelgauge/BatterySettingsFeatureProvider.java
+++ b/src/com/android/settings/fuelgauge/BatterySettingsFeatureProvider.java
@@ -18,6 +18,7 @@
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 @@
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);
}
diff --git a/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImpl.java
index f974b9d..f398373 100644
--- a/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImpl.java
+++ b/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImpl.java
@@ -18,6 +18,8 @@
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 @@
@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());
+ }
}
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
index 5352105..d68bf39 100644
--- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
@@ -18,7 +18,6 @@
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.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 @@
@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;
}
diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetector.java
index 1ce5a8e..b1a1562 100644
--- a/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetector.java
+++ b/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetector.java
@@ -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 @@
/** 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);
}
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java
index 047bf13..319ba7a 100644
--- a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java
@@ -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.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 @@
}
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) {
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTip.java
index 882b755..c9ff864 100644
--- a/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTip.java
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTip.java
@@ -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.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 @@
}
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 =
diff --git a/src/com/android/settings/widget/CardPreference.java b/src/com/android/settings/widget/CardPreference.java
deleted file mode 100644
index 61114d9..0000000
--- a/src/com/android/settings/widget/CardPreference.java
+++ /dev/null
@@ -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));
- }
-}
diff --git a/src/com/android/settings/widget/CardPreference.kt b/src/com/android/settings/widget/CardPreference.kt
new file mode 100644
index 0000000..7122ac6
--- /dev/null
+++ b/src/com/android/settings/widget/CardPreference.kt
@@ -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()
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java
index cfd256f..fc72c41 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java
@@ -18,6 +18,8 @@
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.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.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.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 @@
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);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImplTest.java
index 554227e..14ba337 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImplTest.java
@@ -22,11 +22,17 @@
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 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();
+ }
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetectorTest.java
index 8e3de7c..c5897f2 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetectorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetectorTest.java
@@ -19,20 +19,25 @@
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 @@
@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;
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java
index 296306d..3f89f9b 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java
@@ -124,7 +124,7 @@
public void updatePreference_shouldSetPrimaryButtonVisible() {
mBatteryDefenderTip.updatePreference(mCardPreference);
- verify(mCardPreference).setPrimaryButtonVisible(true);
+ verify(mCardPreference).setPrimaryButtonVisibility(true);
}
@Test
@@ -134,14 +134,14 @@
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 @@
mBatteryDefenderTip.updatePreference(mCardPreference);
- verify(mCardPreference).setSecondaryButtonVisible(false);
+ verify(mCardPreference).setSecondaryButtonVisibility(false);
}
private void fakeGetChargingStatusFailed() {
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTipTest.java
index 45fdc1f..ea72ff6 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTipTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTipTest.java
@@ -91,7 +91,7 @@
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);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTipTest.java
index c1d039b..c66cf37 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTipTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTipTest.java
@@ -113,7 +113,7 @@
@Test
public void updatePreference_shouldSetSecondaryButtonVisible() {
mIncompatibleChargerTip.updatePreference(mCardPreference);
- verify(mCardPreference).setPrimaryButtonVisible(true);
+ verify(mCardPreference).setPrimaryButtonVisibility(true);
}
private String getLastErrorLog() {
diff --git a/tests/robotests/src/com/android/settings/widget/CardPreferenceTest.java b/tests/robotests/src/com/android/settings/widget/CardPreferenceTest.java
deleted file mode 100644
index e26643f..0000000
--- a/tests/robotests/src/com/android/settings/widget/CardPreferenceTest.java
+++ /dev/null
@@ -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);
- }
-}
diff --git a/tests/spa_unit/src/com/android/settings/widget/CardPreferenceTest.kt b/tests/spa_unit/src/com/android/settings/widget/CardPreferenceTest.kt
new file mode 100644
index 0000000..0483e36
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/widget/CardPreferenceTest.kt
@@ -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()
+}
diff --git a/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java b/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java
index acf590b..b5aeac7 100644
--- a/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java
@@ -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 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 @@
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 @@
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 @@
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 @@
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 @@
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 =