[BatteryTip] Implement new CardPreference to apply new style
- Implement a new CardPreference to apply SettingsCard
- Apply CardPreference on battery tips
Bug: 315748218
Test: atest SettingsSpaUnitTests:com.android.settings.widget.CardPreferenceTest
Test: atest SettingsRoboTest:com.android.settings.fuelgauge
Change-Id: I9a57e7739275854278b2c586793af718b0680d23
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/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()
+}