Snap for 12205827 from 1a888b6e8f to 24Q4-release

Change-Id: I88b150906cf68bc5133d1571c6957e4b969d9259
This commit is contained in:
Android Build Coastguard Worker
2024-08-09 01:21:07 +00:00
26 changed files with 368 additions and 772 deletions

View File

@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/settingslib_materialColorSurfaceBright" />
<corners android:radius="@dimen/battery_tips_card_corner_radius_normal" />
</shape>

View File

@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:attr/colorControlHighlight">
<item android:drawable="@drawable/battery_tips_all_rounded_bg"/>
</ripple>

View File

@@ -1,27 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/settingslib_dialog_background"/>
<corners
android:topLeftRadius="@dimen/battery_tips_card_corner_radius_small"
android:topRightRadius="@dimen/battery_tips_card_corner_radius_small"
android:bottomLeftRadius="@dimen/battery_tips_card_corner_radius_normal"
android:bottomRightRadius="@dimen/battery_tips_card_corner_radius_normal"
/>
</shape>

View File

@@ -1,27 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/settingslib_dialog_background"/>
<corners
android:topLeftRadius="@dimen/battery_tips_card_corner_radius_normal"
android:topRightRadius="@dimen/battery_tips_card_corner_radius_normal"
android:bottomLeftRadius="@dimen/battery_tips_card_corner_radius_small"
android:bottomRightRadius="@dimen/battery_tips_card_corner_radius_small"
/>
</shape>

View File

@@ -1,61 +0,0 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/battery_tips_card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="?android:attr/listPreferredItemPaddingStart"
android:layout_marginEnd="?android:attr/listPreferredItemPaddingEnd"
android:background="@drawable/battery_tips_all_rounded_bg_ripple"
android:orientation="vertical"
android:padding="20dp">
<ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
android:contentDescription="@string/battery_usage_anomaly_content_description"
android:src="@drawable/ic_battery_tips_lightbulb" />
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:textAlignment="viewStart"
android:textAppearance="@style/TextAppearance.Material3.TitleMedium"
android:textColor="@color/settingslib_materialColorOnSurface" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="end"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/dismiss_button"
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical"
android:layout_marginEnd="8dp"
android:paddingHorizontal="16dp"
android:text="@string/battery_tips_card_dismiss_button"
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle2"
android:textColor="@color/color_accent_selector" />
<com.google.android.material.button.MaterialButton
android:id="@+id/main_button"
style="@style/Widget.Material3.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical"
android:paddingHorizontal="16dp"
android:text="@string/battery_tips_card_action_button"
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle2"
android:textColor="@color/settingslib_materialColorOnPrimary"
app:backgroundTint="@color/color_accent_selector" />
</LinearLayout>
</LinearLayout>

View File

@@ -937,7 +937,7 @@
<!-- Message showing that multiple fingerprints, face, and the current watch is set up. Shown for a menu item that launches fingerprint, face, and active unlock settings or enrollment. [CHAR LIMIT=80]--> <!-- Message showing that multiple fingerprints, face, and the current watch is set up. Shown for a menu item that launches fingerprint, face, and active unlock settings or enrollment. [CHAR LIMIT=80]-->
<string name="security_settings_fingerprint_multiple_face_watch_preference_summary">Face, fingerprints, and <xliff:g id="watch" example="Dani's Watch">%s</xliff:g> added</string> <string name="security_settings_fingerprint_multiple_face_watch_preference_summary">Face, fingerprints, and <xliff:g id="watch" example="Dani's Watch">%s</xliff:g> added</string>
<!-- Description for mandatory biometrics prompt--> <!-- Description for mandatory biometrics prompt-->
<string name="mandatory_biometrics_prompt_description">This is needed since Identity Check is on</string> <string name="mandatory_biometrics_prompt_description">Identity Check is on</string>
<!-- RemoteAuth unlock enrollment and settings --><skip /> <!-- RemoteAuth unlock enrollment and settings --><skip />
<!-- Title shown for menu item that launches watch unlock settings. [CHAR LIMIT=40] --> <!-- Title shown for menu item that launches watch unlock settings. [CHAR LIMIT=40] -->
<string name ="security_settings_remoteauth_preference_title">Remote Authenticator Unlock</string> <string name ="security_settings_remoteauth_preference_title">Remote Authenticator Unlock</string>

View File

@@ -27,7 +27,7 @@
"com.android.settings.fuelgauge.batteryusage.BatteryTipsController" "com.android.settings.fuelgauge.batteryusage.BatteryTipsController"
settings:isPreferenceVisible="false"> settings:isPreferenceVisible="false">
<com.android.settings.fuelgauge.batteryusage.BatteryTipsCardPreference <com.android.settings.widget.TipCardPreference
android:key="battery_tips_card" android:key="battery_tips_card"
settings:isPreferenceVisible="false" /> settings:isPreferenceVisible="false" />

View File

@@ -20,6 +20,7 @@ import static android.app.Activity.RESULT_CANCELED;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS;
import static android.provider.Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED; import static android.provider.Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED;
import static android.provider.Settings.Secure.ACCESSIBILITY_GESTURE_TARGETS;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED; import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED;
import static android.provider.Settings.Secure.ACCESSIBILITY_QS_TARGETS; import static android.provider.Settings.Secure.ACCESSIBILITY_QS_TARGETS;
import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE; import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
@@ -93,7 +94,8 @@ public class EditShortcutsPreferenceFragment extends DashboardFragment {
Settings.Secure.getUriFor(ACCESSIBILITY_BUTTON_MODE); Settings.Secure.getUriFor(ACCESSIBILITY_BUTTON_MODE);
private static final Uri BUTTON_SHORTCUT_SETTING = private static final Uri BUTTON_SHORTCUT_SETTING =
Settings.Secure.getUriFor(ACCESSIBILITY_BUTTON_TARGETS); Settings.Secure.getUriFor(ACCESSIBILITY_BUTTON_TARGETS);
private static final Uri GESTURE_SHORTCUT_SETTING =
Settings.Secure.getUriFor(ACCESSIBILITY_GESTURE_TARGETS);
private static final Uri TRIPLE_TAP_SHORTCUT_SETTING = private static final Uri TRIPLE_TAP_SHORTCUT_SETTING =
Settings.Secure.getUriFor(ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED); Settings.Secure.getUriFor(ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED);
private static final Uri TWO_FINGERS_DOUBLE_TAP_SHORTCUT_SETTING = private static final Uri TWO_FINGERS_DOUBLE_TAP_SHORTCUT_SETTING =
@@ -107,6 +109,7 @@ public class EditShortcutsPreferenceFragment extends DashboardFragment {
VOLUME_KEYS_SHORTCUT_SETTING, VOLUME_KEYS_SHORTCUT_SETTING,
BUTTON_SHORTCUT_MODE_SETTING, BUTTON_SHORTCUT_MODE_SETTING,
BUTTON_SHORTCUT_SETTING, BUTTON_SHORTCUT_SETTING,
GESTURE_SHORTCUT_SETTING,
TRIPLE_TAP_SHORTCUT_SETTING, TRIPLE_TAP_SHORTCUT_SETTING,
TWO_FINGERS_DOUBLE_TAP_SHORTCUT_SETTING, TWO_FINGERS_DOUBLE_TAP_SHORTCUT_SETTING,
QUICK_SETTINGS_SHORTCUT_SETTING, QUICK_SETTINGS_SHORTCUT_SETTING,
@@ -173,6 +176,8 @@ public class EditShortcutsPreferenceFragment extends DashboardFragment {
} else if (BUTTON_SHORTCUT_MODE_SETTING.equals(uri) } else if (BUTTON_SHORTCUT_MODE_SETTING.equals(uri)
|| BUTTON_SHORTCUT_SETTING.equals(uri)) { || BUTTON_SHORTCUT_SETTING.equals(uri)) {
refreshSoftwareShortcutControllers(); refreshSoftwareShortcutControllers();
} else if (GESTURE_SHORTCUT_SETTING.equals(uri)) {
refreshPreferenceController(GestureShortcutOptionController.class);
} else if (TRIPLE_TAP_SHORTCUT_SETTING.equals(uri)) { } else if (TRIPLE_TAP_SHORTCUT_SETTING.equals(uri)) {
refreshPreferenceController(TripleTapShortcutOptionController.class); refreshPreferenceController(TripleTapShortcutOptionController.class);
} else if (TWO_FINGERS_DOUBLE_TAP_SHORTCUT_SETTING.equals(uri)) { } else if (TWO_FINGERS_DOUBLE_TAP_SHORTCUT_SETTING.equals(uri)) {

View File

@@ -50,7 +50,14 @@ public class FloatingButtonShortcutOptionController
@Override @Override
protected boolean isShortcutAvailable() { protected boolean isShortcutAvailable() {
return AccessibilityUtil.isFloatingMenuEnabled(mContext); if (android.provider.Flags.a11yStandaloneGestureEnabled()) {
// FAB should be available when in gesture navigation mode,
// or if we're in the FAB button mode while in navbar navigation mode.
return AccessibilityUtil.isGestureNavigateEnabled(mContext)
|| AccessibilityUtil.isFloatingMenuEnabled(mContext);
} else {
return AccessibilityUtil.isFloatingMenuEnabled(mContext);
}
} }
@Nullable @Nullable

View File

@@ -16,6 +16,8 @@
package com.android.settings.accessibility.shortcuts; package com.android.settings.accessibility.shortcuts;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE;
import android.content.Context; import android.content.Context;
import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder;
@@ -51,11 +53,22 @@ public class GestureShortcutOptionController extends SoftwareShortcutOptionPrefe
} }
} }
@Override
protected int getShortcutType() {
return android.provider.Flags.a11yStandaloneGestureEnabled()
? GESTURE : super.getShortcutType();
}
@Override @Override
protected boolean isShortcutAvailable() { protected boolean isShortcutAvailable() {
return !isInSetupWizard() if (android.provider.Flags.a11yStandaloneGestureEnabled()) {
&& !AccessibilityUtil.isFloatingMenuEnabled(mContext) return !isInSetupWizard()
&& AccessibilityUtil.isGestureNavigateEnabled(mContext); && AccessibilityUtil.isGestureNavigateEnabled(mContext);
} else {
return !isInSetupWizard()
&& AccessibilityUtil.isGestureNavigateEnabled(mContext)
&& !AccessibilityUtil.isFloatingMenuEnabled(mContext);
}
} }
@Override @Override
@@ -68,9 +81,8 @@ public class GestureShortcutOptionController extends SoftwareShortcutOptionPrefe
final SpannableStringBuilder sb = new SpannableStringBuilder(); final SpannableStringBuilder sb = new SpannableStringBuilder();
sb.append(instruction); sb.append(instruction);
if (!isInSetupWizard()) { if (!isInSetupWizard() && !android.provider.Flags.a11yStandaloneGestureEnabled()) {
sb.append("\n\n"); sb.append("\n\n").append(getCustomizeAccessibilityButtonLink());
sb.append(getCustomizeAccessibilityButtonLink());
} }
return sb; return sb;

View File

@@ -42,6 +42,8 @@ import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.UserManager; import android.os.UserManager;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.text.InputFilter; import android.text.InputFilter;
import android.text.Spanned; import android.text.Spanned;
import android.text.TextUtils; import android.text.TextUtils;
@@ -109,6 +111,9 @@ public class FingerprintSettings extends SubSettings {
private static final int RESULT_FINISHED = BiometricEnrollBase.RESULT_FINISHED; private static final int RESULT_FINISHED = BiometricEnrollBase.RESULT_FINISHED;
private static final int RESULT_SKIP = BiometricEnrollBase.RESULT_SKIP; private static final int RESULT_SKIP = BiometricEnrollBase.RESULT_SKIP;
private static final int RESULT_TIMEOUT = BiometricEnrollBase.RESULT_TIMEOUT; private static final int RESULT_TIMEOUT = BiometricEnrollBase.RESULT_TIMEOUT;
@VisibleForTesting
static final VibrationEffect SUCCESS_VIBRATION_EFFECT =
VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
@Override @Override
public Intent getIntent() { public Intent getIntent() {
@@ -285,6 +290,7 @@ public class FingerprintSettings extends SubSettings {
private FingerprintAuthenticateSidecar mAuthenticateSidecar; private FingerprintAuthenticateSidecar mAuthenticateSidecar;
private FingerprintRemoveSidecar mRemovalSidecar; private FingerprintRemoveSidecar mRemovalSidecar;
private HashMap<Integer, String> mFingerprintsRenaming; private HashMap<Integer, String> mFingerprintsRenaming;
private Vibrator mVibrator;
@Nullable @Nullable
private UdfpsEnrollCalibrator mCalibrator; private UdfpsEnrollCalibrator mCalibrator;
@@ -367,8 +373,8 @@ public class FingerprintSettings extends SubSettings {
break; break;
case MSG_FINGER_AUTH_HELP: { case MSG_FINGER_AUTH_HELP: {
// Not used // Not used
break;
} }
break;
} }
} }
}; };
@@ -511,6 +517,7 @@ public class FingerprintSettings extends SubSettings {
addFirstFingerprint(null); addFirstFingerprint(null);
} }
} }
mVibrator = getContext().getSystemService(Vibrator.class);
final PreferenceScreen root = getPreferenceScreen(); final PreferenceScreen root = getPreferenceScreen();
root.removeAll(); root.removeAll();
addPreferencesFromResource(getPreferenceScreenResId()); addPreferencesFromResource(getPreferenceScreenResId());
@@ -1095,6 +1102,7 @@ public class FingerprintSettings extends SubSettings {
} }
private void highlightFingerprintItem(int fpId) { private void highlightFingerprintItem(int fpId) {
mVibrator.vibrate(SUCCESS_VIBRATION_EFFECT);
String prefName = genKey(fpId); String prefName = genKey(fpId);
FingerprintPreference fpref = (FingerprintPreference) findPreference(prefName); FingerprintPreference fpref = (FingerprintPreference) findPreference(prefName);
final Drawable highlight = getHighlightDrawable(); final Drawable highlight = getHighlightDrawable();

View File

@@ -28,10 +28,11 @@ import androidx.annotation.Nullable;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.SettingsActivity; import com.android.settings.SettingsActivity;
import com.android.settings.core.SubSettingLauncher; import com.android.settings.core.SubSettingLauncher;
import com.android.settings.widget.TipCardPreference;
import java.util.function.Function; import java.util.function.Function;
final class AnomalyEventWrapper { class AnomalyEventWrapper {
private static final String TAG = "AnomalyEventWrapper"; private static final String TAG = "AnomalyEventWrapper";
private final Context mContext; private final Context mContext;
@@ -235,16 +236,16 @@ final class AnomalyEventWrapper {
return mHighlightSlotPair; return mHighlightSlotPair;
} }
boolean updateTipsCardPreference(BatteryTipsCardPreference preference) { boolean updateTipsCardPreference(TipCardPreference preference) {
final String titleString = getTitleString(); final String titleString = getTitleString();
if (TextUtils.isEmpty(titleString)) { if (TextUtils.isEmpty(titleString)) {
return false; return false;
} }
preference.setTitle(titleString); preference.setTitle(titleString);
preference.setIconResourceId(getIconResId()); preference.setIconResId(getIconResId());
preference.setButtonColorResourceId(getColorResId()); preference.setTintColorResId(getColorResId());
preference.setMainButtonLabel(getMainBtnString()); preference.setPrimaryButtonText(getDismissBtnString());
preference.setDismissButtonLabel(getDismissBtnString()); preference.setSecondaryButtonText(getMainBtnString());
return true; return true;
} }

View File

@@ -1,150 +0,0 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.fuelgauge.batteryusage;
import android.content.Context;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import com.android.settings.R;
import com.google.android.material.button.MaterialButton;
/** A preference for displaying the battery tips card view. */
public class BatteryTipsCardPreference extends Preference implements View.OnClickListener {
private static final String TAG = "BatteryTipsCardPreference";
interface OnConfirmListener {
void onConfirm();
}
interface OnRejectListener {
void onReject();
}
private OnConfirmListener mOnConfirmListener;
private OnRejectListener mOnRejectListener;
private int mIconResourceId = 0;
private int mButtonColorResourceId = 0;
@VisibleForTesting CharSequence mMainButtonLabel;
@VisibleForTesting CharSequence mDismissButtonLabel;
public BatteryTipsCardPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setLayoutResource(R.layout.battery_tips_card);
setViewId(R.id.battery_tips_card);
setSelectable(false);
}
public void setOnConfirmListener(OnConfirmListener listener) {
mOnConfirmListener = listener;
}
public void setOnRejectListener(OnRejectListener listener) {
mOnRejectListener = listener;
}
/**
* Sets the icon in tips card.
*/
public void setIconResourceId(int resourceId) {
if (mIconResourceId != resourceId) {
mIconResourceId = resourceId;
notifyChanged();
}
}
/**
* Sets the background color for main button and the text color for dismiss button.
*/
public void setButtonColorResourceId(int resourceId) {
if (mButtonColorResourceId != resourceId) {
mButtonColorResourceId = resourceId;
notifyChanged();
}
}
/**
* Sets the label of main button in tips card.
*/
public void setMainButtonLabel(CharSequence label) {
if (!TextUtils.equals(mMainButtonLabel, label)) {
mMainButtonLabel = label;
notifyChanged();
}
}
/**
* Sets the label of dismiss button in tips card.
*/
public void setDismissButtonLabel(CharSequence label) {
if (!TextUtils.equals(mDismissButtonLabel, label)) {
mDismissButtonLabel = label;
notifyChanged();
}
}
@Override
public void onClick(View view) {
final int viewId = view.getId();
if (viewId == R.id.main_button || viewId == R.id.battery_tips_card) {
if (mOnConfirmListener != null) {
mOnConfirmListener.onConfirm();
}
} else if (viewId == R.id.dismiss_button) {
if (mOnRejectListener != null) {
mOnRejectListener.onReject();
}
}
}
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
super.onBindViewHolder(view);
((TextView) view.findViewById(R.id.title)).setText(getTitle());
final LinearLayout tipsCard = (LinearLayout) view.findViewById(R.id.battery_tips_card);
tipsCard.setOnClickListener(this);
final MaterialButton mainButton = (MaterialButton) view.findViewById(R.id.main_button);
mainButton.setOnClickListener(this);
mainButton.setText(mMainButtonLabel);
final MaterialButton dismissButton =
(MaterialButton) view.findViewById(R.id.dismiss_button);
dismissButton.setOnClickListener(this);
dismissButton.setText(mDismissButtonLabel);
if (mButtonColorResourceId != 0) {
final int colorInt = getContext().getColor(mButtonColorResourceId);
mainButton.setBackgroundColor(colorInt);
dismissButton.setTextColor(colorInt);
}
if (mIconResourceId != 0) {
((ImageView) view.findViewById(R.id.icon)).setImageResource(mIconResourceId);
}
}
}

View File

@@ -25,6 +25,7 @@ import androidx.preference.PreferenceScreen;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.core.BasePreferenceController; import com.android.settings.core.BasePreferenceController;
import com.android.settings.overlay.FeatureFactory; import com.android.settings.overlay.FeatureFactory;
import com.android.settings.widget.TipCardPreference;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
/** Controls the update for battery tips card */ /** Controls the update for battery tips card */
@@ -50,10 +51,9 @@ public class BatteryTipsController extends BasePreferenceController {
void onAnomalyReject(); void onAnomalyReject();
} }
private OnAnomalyConfirmListener mOnAnomalyConfirmListener; @VisibleForTesting OnAnomalyConfirmListener mOnAnomalyConfirmListener;
private OnAnomalyRejectListener mOnAnomalyRejectListener; @VisibleForTesting OnAnomalyRejectListener mOnAnomalyRejectListener;
@VisibleForTesting TipCardPreference mCardPreference;
@VisibleForTesting BatteryTipsCardPreference mCardPreference;
@VisibleForTesting AnomalyEventWrapper mAnomalyEventWrapper = null; @VisibleForTesting AnomalyEventWrapper mAnomalyEventWrapper = null;
@VisibleForTesting Boolean mIsAcceptable = false; @VisibleForTesting Boolean mIsAcceptable = false;
@@ -117,42 +117,20 @@ public class BatteryTipsController extends BasePreferenceController {
return; return;
} }
// Set battery tips card listener mCardPreference.setPrimaryButtonAction(
mCardPreference.setOnConfirmListener(
() -> { () -> {
mCardPreference.setVisible(false); onBatteryTipsCardDismiss(anomalyKeyNumber);
if (mOnAnomalyConfirmListener != null) { return null;
mOnAnomalyConfirmListener.onAnomalyConfirm();
} else if (mAnomalyEventWrapper.updateSystemSettingsIfAvailable()
|| mAnomalyEventWrapper.launchSubSetting()) {
mMetricsFeatureProvider.action(
/* attribution= */ SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
/* action= */ SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT,
/* pageId= */ SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
/* key= */ ANOMALY_KEY,
/* value= */ anomalyKeyNumber);
}
}); });
mCardPreference.setOnRejectListener( mCardPreference.setSecondaryButtonAction(
() -> { () -> {
mCardPreference.setVisible(false); onBatteryTipsCardAccept(anomalyKeyNumber);
if (mOnAnomalyRejectListener != null) { return null;
mOnAnomalyRejectListener.onAnomalyReject();
}
// For anomaly events with same record key, dismissed until next time full
// charged.
final String dismissRecordKey = mAnomalyEventWrapper.getDismissRecordKey();
if (!TextUtils.isEmpty(dismissRecordKey)) {
DatabaseUtils.setDismissedPowerAnomalyKeys(mContext, dismissRecordKey);
}
mMetricsFeatureProvider.action(
/* attribution= */ SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
/* action= */ SettingsEnums.ACTION_BATTERY_TIPS_CARD_DISMISS,
/* pageId= */ SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
/* key= */ ANOMALY_KEY,
/* value= */ anomalyKeyNumber);
}); });
mCardPreference.setPrimaryButtonVisibility(true);
mCardPreference.setSecondaryButtonVisibility(true);
mCardPreference.buildContent();
mCardPreference.setVisible(true); mCardPreference.setVisible(true);
mMetricsFeatureProvider.action( mMetricsFeatureProvider.action(
/* attribution= */ SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL, /* attribution= */ SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
@@ -161,4 +139,37 @@ public class BatteryTipsController extends BasePreferenceController {
/* key= */ ANOMALY_KEY, /* key= */ ANOMALY_KEY,
/* value= */ anomalyKeyNumber); /* value= */ anomalyKeyNumber);
} }
private void onBatteryTipsCardDismiss(final int anomalyKeyNumber) {
mCardPreference.setVisible(false);
if (mOnAnomalyRejectListener != null) {
mOnAnomalyRejectListener.onAnomalyReject();
}
// For anomaly events with same record key, dismissed until next time full charged.
final String dismissRecordKey = mAnomalyEventWrapper.getDismissRecordKey();
if (!TextUtils.isEmpty(dismissRecordKey)) {
DatabaseUtils.setDismissedPowerAnomalyKeys(mContext, dismissRecordKey);
}
mMetricsFeatureProvider.action(
/* attribution= */ SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
/* action= */ SettingsEnums.ACTION_BATTERY_TIPS_CARD_DISMISS,
/* pageId= */ SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
/* key= */ ANOMALY_KEY,
/* value= */ anomalyKeyNumber);
}
private void onBatteryTipsCardAccept(final int anomalyKeyNumber) {
mCardPreference.setVisible(false);
if (mOnAnomalyConfirmListener != null) {
mOnAnomalyConfirmListener.onAnomalyConfirm();
} else if (mAnomalyEventWrapper.updateSystemSettingsIfAvailable()
|| mAnomalyEventWrapper.launchSubSetting()) {
mMetricsFeatureProvider.action(
/* attribution= */ SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
/* action= */ SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT,
/* pageId= */ SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
/* key= */ ANOMALY_KEY,
/* value= */ anomalyKeyNumber);
}
}
} }

View File

@@ -19,6 +19,7 @@ package com.android.settings.network.ims;
import static android.telephony.ims.ProvisioningManager.KEY_VOIMS_OPT_IN_STATUS; import static android.telephony.ims.ProvisioningManager.KEY_VOIMS_OPT_IN_STATUS;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager;
import android.telecom.TelecomManager; import android.telecom.TelecomManager;
import android.telephony.AccessNetworkConstants; import android.telephony.AccessNetworkConstants;
import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager;
@@ -143,6 +144,11 @@ public class VolteQueryImsState extends ImsQueryController {
* @return true when VoIMS opt-in has been enabled, otherwise false * @return true when VoIMS opt-in has been enabled, otherwise false
*/ */
public boolean isVoImsOptInEnabled() { public boolean isVoImsOptInEnabled() {
if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS)) {
// If the device does not have PackageManager.FEATURE_TELEPHONY_IMS,
// ProvisioningManager.getProvisioningIntValue() could not be called.
return false;
}
int voImsOptInStatus = ProvisioningManager.createForSubscriptionId(mSubId) int voImsOptInStatus = ProvisioningManager.createForSubscriptionId(mSubId)
.getProvisioningIntValue(KEY_VOIMS_OPT_IN_STATUS); .getProvisioningIntValue(KEY_VOIMS_OPT_IN_STATUS);
return voImsOptInStatus == ProvisioningManager.PROVISIONING_VALUE_ENABLED; return voImsOptInStatus == ProvisioningManager.PROVISIONING_VALUE_ENABLED;

View File

@@ -104,6 +104,7 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity {
private boolean mForceVerifyPath = false; private boolean mForceVerifyPath = false;
private boolean mGoingToBackground; private boolean mGoingToBackground;
private boolean mWaitingForBiometricCallback; private boolean mWaitingForBiometricCallback;
private int mBiometricsAuthenticators;
private Executor mExecutor = (runnable -> { private Executor mExecutor = (runnable -> {
mHandler.post(runnable); mHandler.post(runnable);
@@ -122,8 +123,14 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity {
Log.i(TAG, "Finishing, user no longer valid: " + mUserId); Log.i(TAG, "Finishing, user no longer valid: " + mUserId);
finish(); finish();
} else { } else {
// All other errors go to some version of CC if ((mBiometricsAuthenticators
showConfirmCredentials(); & BiometricManager.Authenticators.DEVICE_CREDENTIAL) != 0) {
// All other errors go to some version of CC
showConfirmCredentials();
} else {
Log.i(TAG, "Finishing, device credential not requested");
finish();
}
} }
} else if (mWaitingForBiometricCallback) { // mGoingToBackground is true } else if (mWaitingForBiometricCallback) { // mGoingToBackground is true
mWaitingForBiometricCallback = false; mWaitingForBiometricCallback = false;
@@ -188,7 +195,7 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity {
mDetails = intent.getCharSequenceExtra(KeyguardManager.EXTRA_DESCRIPTION); mDetails = intent.getCharSequenceExtra(KeyguardManager.EXTRA_DESCRIPTION);
String alternateButton = intent.getStringExtra( String alternateButton = intent.getStringExtra(
KeyguardManager.EXTRA_ALTERNATE_BUTTON_LABEL); KeyguardManager.EXTRA_ALTERNATE_BUTTON_LABEL);
final int authenticators = intent.getIntExtra(BIOMETRIC_PROMPT_AUTHENTICATORS, mBiometricsAuthenticators = intent.getIntExtra(BIOMETRIC_PROMPT_AUTHENTICATORS,
BiometricManager.Authenticators.DEVICE_CREDENTIAL BiometricManager.Authenticators.DEVICE_CREDENTIAL
| BiometricManager.Authenticators.BIOMETRIC_WEAK); | BiometricManager.Authenticators.BIOMETRIC_WEAK);
final String negativeButtonText = intent.getStringExtra( final String negativeButtonText = intent.getStringExtra(
@@ -229,7 +236,7 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity {
promptInfo.setTitle(mTitle); promptInfo.setTitle(mTitle);
promptInfo.setDescription(mDetails); promptInfo.setDescription(mDetails);
promptInfo.setDisallowBiometricsIfPolicyExists(mCheckDevicePolicyManager); promptInfo.setDisallowBiometricsIfPolicyExists(mCheckDevicePolicyManager);
promptInfo.setAuthenticators(authenticators); promptInfo.setAuthenticators(mBiometricsAuthenticators);
promptInfo.setNegativeButtonText(negativeButtonText); promptInfo.setNegativeButtonText(negativeButtonText);
if (android.multiuser.Flags.enablePrivateSpaceFeatures() if (android.multiuser.Flags.enablePrivateSpaceFeatures()

View File

@@ -120,6 +120,16 @@ public class SettingsSliceProvider extends SliceProvider {
* permission can use them. * permission can use them.
*/ */
private static final List<Uri> PUBLICLY_SUPPORTED_CUSTOM_SLICE_URIS = private static final List<Uri> PUBLICLY_SUPPORTED_CUSTOM_SLICE_URIS =
android.app.Flags.modesUi()
?
Arrays.asList(
CustomSliceRegistry.BLUETOOTH_URI,
CustomSliceRegistry.FLASHLIGHT_SLICE_URI,
CustomSliceRegistry.LOCATION_SLICE_URI,
CustomSliceRegistry.MOBILE_DATA_SLICE_URI,
CustomSliceRegistry.WIFI_CALLING_URI,
CustomSliceRegistry.WIFI_SLICE_URI
) :
Arrays.asList( Arrays.asList(
CustomSliceRegistry.BLUETOOTH_URI, CustomSliceRegistry.BLUETOOTH_URI,
CustomSliceRegistry.FLASHLIGHT_SLICE_URI, CustomSliceRegistry.FLASHLIGHT_SLICE_URI,
@@ -184,7 +194,9 @@ public class SettingsSliceProvider extends SliceProvider {
} }
if (CustomSliceRegistry.ZEN_MODE_SLICE_URI.equals(sliceUri)) { if (CustomSliceRegistry.ZEN_MODE_SLICE_URI.equals(sliceUri)) {
registerIntentToUri(ZenModeSliceBuilder.INTENT_FILTER, sliceUri); if (!android.app.Flags.modesUi()) {
registerIntentToUri(ZenModeSliceBuilder.INTENT_FILTER, sliceUri);
}
return; return;
} else if (CustomSliceRegistry.BLUETOOTH_URI.equals(sliceUri)) { } else if (CustomSliceRegistry.BLUETOOTH_URI.equals(sliceUri)) {
registerIntentToUri(BluetoothSliceBuilder.INTENT_FILTER, sliceUri); registerIntentToUri(BluetoothSliceBuilder.INTENT_FILTER, sliceUri);
@@ -256,7 +268,8 @@ public class SettingsSliceProvider extends SliceProvider {
.getSlicesFeatureProvider() .getSlicesFeatureProvider()
.getNewWifiCallingSliceHelper(getContext()) .getNewWifiCallingSliceHelper(getContext())
.createWifiCallingSlice(sliceUri); .createWifiCallingSlice(sliceUri);
} else if (CustomSliceRegistry.ZEN_MODE_SLICE_URI.equals(sliceUri)) { } else if (!android.app.Flags.modesUi()
&& CustomSliceRegistry.ZEN_MODE_SLICE_URI.equals(sliceUri)) {
return ZenModeSliceBuilder.getSlice(getContext()); return ZenModeSliceBuilder.getSlice(getContext());
} else if (CustomSliceRegistry.BLUETOOTH_URI.equals(sliceUri)) { } else if (CustomSliceRegistry.BLUETOOTH_URI.equals(sliceUri)) {
return BluetoothSliceBuilder.getSlice(getContext()); return BluetoothSliceBuilder.getSlice(getContext());

View File

@@ -19,6 +19,7 @@ package com.android.settings.widget
import android.content.Context import android.content.Context
import android.content.res.Resources import android.content.res.Resources
import android.util.AttributeSet import android.util.AttributeSet
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.vectorResource import androidx.compose.ui.res.vectorResource
import com.android.settings.spa.preference.ComposePreference import com.android.settings.spa.preference.ComposePreference
@@ -37,6 +38,9 @@ constructor(
/** A icon resource id for displaying icon on tips card. */ /** A icon resource id for displaying icon on tips card. */
var iconResId: Int? = null var iconResId: Int? = null
/** A color resource id for displaying icon and button text on tips card. */
var tintColorResId: Int? = null
/** The primary button's text. */ /** The primary button's text. */
var primaryButtonText: String = "" var primaryButtonText: String = ""
@@ -85,6 +89,8 @@ constructor(
title = title?.toString() ?: "", title = title?.toString() ?: "",
text = summary?.toString() ?: "", text = summary?.toString() ?: "",
buttons = listOfNotNull(configPrimaryButton(), configSecondaryButton()), buttons = listOfNotNull(configPrimaryButton(), configSecondaryButton()),
tintColor = tintColorResId?.let { Color(context.getColor(it)) }
?: Color.Unspecified,
onDismiss = onDismiss, onDismiss = onDismiss,
imageVector = imageVector =
iconResId iconResId

View File

@@ -16,37 +16,46 @@
package com.android.settings.accessibility.shortcuts; package com.android.settings.accessibility.shortcuts;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.provider.Settings; import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Flags;
import androidx.preference.PreferenceManager; import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen; import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.testutils.AccessibilityTestUtils;
import com.android.settings.testutils.shadow.SettingsShadowResources;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import java.util.Set; import java.util.Set;
/** /**
* Tests for {@link FloatingButtonShortcutOptionController} * Tests for {@link FloatingButtonShortcutOptionController}
*/ */
@Config(shadows = SettingsShadowResources.class)
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
public class FloatingButtonShortcutOptionControllerTest { public class FloatingButtonShortcutOptionControllerTest {
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private static final String PREF_KEY = "prefKey"; private static final String PREF_KEY = "prefKey";
private static final String TARGET = private static final String TARGET =
new ComponentName("FakePackage", "FakeClass").flattenToString(); new ComponentName("FakePackage", "FakeClass").flattenToString();
private final Context mContext = ApplicationProvider.getApplicationContext(); private final Context mContext = spy(ApplicationProvider.getApplicationContext());
private FloatingButtonShortcutOptionController mController; private FloatingButtonShortcutOptionController mController;
private ShortcutOptionPreference mShortcutOptionPreference; private ShortcutOptionPreference mShortcutOptionPreference;
@@ -61,7 +70,6 @@ public class FloatingButtonShortcutOptionControllerTest {
mShortcutOptionPreference.setKey(PREF_KEY); mShortcutOptionPreference.setKey(PREF_KEY);
mPreferenceScreen = new PreferenceManager(mContext).createPreferenceScreen(mContext); mPreferenceScreen = new PreferenceManager(mContext).createPreferenceScreen(mContext);
mPreferenceScreen.addPreference(mShortcutOptionPreference); mPreferenceScreen.addPreference(mShortcutOptionPreference);
setFloatingButtonEnabled(true);
} }
@Test @Test
@@ -95,23 +103,26 @@ public class FloatingButtonShortcutOptionControllerTest {
@Test @Test
public void isShortcutAvailable_floatingMenuEnabled_returnTrue() { public void isShortcutAvailable_floatingMenuEnabled_returnTrue() {
setFloatingButtonEnabled(true); AccessibilityTestUtils.setSoftwareShortcutMode(
mContext, /* gestureNavEnabled= */ false, /* floatingButtonEnabled= */ true);
assertThat(mController.isShortcutAvailable()).isTrue(); assertThat(mController.isShortcutAvailable()).isTrue();
} }
@Test @Test
public void isShortcutAvailable_floatingMenuDisabled_returnFalse() { public void isShortcutAvailable_floatingMenuDisabled_returnFalse() {
setFloatingButtonEnabled(false); AccessibilityTestUtils.setSoftwareShortcutMode(
mContext, /* gestureNavEnabled= */ false, /* floatingButtonEnabled= */ false);
assertThat(mController.isShortcutAvailable()).isFalse(); assertThat(mController.isShortcutAvailable()).isFalse();
} }
private void setFloatingButtonEnabled(boolean enable) { @Test
int mode = enable @EnableFlags(Flags.FLAG_A11Y_STANDALONE_GESTURE_ENABLED)
? ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU : ACCESSIBILITY_BUTTON_MODE_GESTURE; public void isShortcutAvailable_gestureNavigationMode_returnsTrue() {
AccessibilityTestUtils.setSoftwareShortcutMode(
mContext, /* gestureNavEnabled= */ true, /* floatingButtonEnabled= */ false);
Settings.Secure.putInt(mContext.getContentResolver(), assertThat(mController.isShortcutAvailable()).isTrue();
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, mode);
} }
} }

View File

@@ -16,6 +16,8 @@
package com.android.settings.accessibility.shortcuts; package com.android.settings.accessibility.shortcuts;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE;
import static com.android.settings.testutils.AccessibilityTestUtils.setupMockAccessibilityManager; import static com.android.settings.testutils.AccessibilityTestUtils.setupMockAccessibilityManager;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
@@ -25,6 +27,10 @@ import static org.mockito.Mockito.when;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Flags;
import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityManager;
import androidx.preference.PreferenceManager; import androidx.preference.PreferenceManager;
@@ -37,6 +43,7 @@ import com.android.settings.testutils.shadow.SettingsShadowResources;
import com.android.settingslib.utils.StringUtil; import com.android.settingslib.utils.StringUtil;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
@@ -50,6 +57,8 @@ import java.util.Set;
@Config(shadows = SettingsShadowResources.class) @Config(shadows = SettingsShadowResources.class)
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
public class GestureShortcutOptionControllerTest { public class GestureShortcutOptionControllerTest {
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private static final String PREF_KEY = "prefKey"; private static final String PREF_KEY = "prefKey";
private static final String TARGET = private static final String TARGET =
new ComponentName("FakePackage", "FakeClass").flattenToString(); new ComponentName("FakePackage", "FakeClass").flattenToString();
@@ -136,6 +145,18 @@ public class GestureShortcutOptionControllerTest {
assertThat(mController.getSummary().toString()).isEqualTo(expected); assertThat(mController.getSummary().toString()).isEqualTo(expected);
} }
@Test
@EnableFlags(Flags.FLAG_A11Y_STANDALONE_GESTURE_ENABLED)
public void getSummary_standaloneGestureFlagOn_verifyNoCustomizeA11yButtonTest() {
enableTouchExploration(true);
String expected = StringUtil.getIcuPluralsString(
mContext,
/* count= */ 3,
R.string.accessibility_shortcut_edit_dialog_summary_gesture);
assertThat(mController.getSummary().toString()).isEqualTo(expected);
}
@Test @Test
public void isShortcutAvailable_inSuw_returnFalse() { public void isShortcutAvailable_inSuw_returnFalse() {
mController.setInSetupWizard(true); mController.setInSetupWizard(true);
@@ -144,6 +165,7 @@ public class GestureShortcutOptionControllerTest {
} }
@Test @Test
@DisableFlags(Flags.FLAG_A11Y_STANDALONE_GESTURE_ENABLED)
public void isShortcutAvailable_notInSuwUseGestureNavSystemUseFab_returnFalse() { public void isShortcutAvailable_notInSuwUseGestureNavSystemUseFab_returnFalse() {
mController.setInSetupWizard(false); mController.setInSetupWizard(false);
AccessibilityTestUtils.setSoftwareShortcutMode( AccessibilityTestUtils.setSoftwareShortcutMode(
@@ -179,6 +201,28 @@ public class GestureShortcutOptionControllerTest {
assertThat(mController.isShortcutAvailable()).isFalse(); assertThat(mController.isShortcutAvailable()).isFalse();
} }
@EnableFlags(Flags.FLAG_A11Y_STANDALONE_GESTURE_ENABLED)
@Test
public void isShortcutAvailable_floatingMenuEnabled_gestureNavEnabled_returnsTrue() {
mController.setInSetupWizard(false);
AccessibilityTestUtils.setSoftwareShortcutMode(
mContext, /* gestureNavEnabled= */ true, /* floatingButtonEnabled= */ true);
assertThat(mController.isShortcutAvailable()).isTrue();
}
@EnableFlags(Flags.FLAG_A11Y_STANDALONE_GESTURE_ENABLED)
@Test
public void getShortcutType_gesture() {
assertThat(mController.getShortcutType()).isEqualTo(GESTURE);
}
@DisableFlags(Flags.FLAG_A11Y_STANDALONE_GESTURE_ENABLED)
@Test
public void getShortcutType_software() {
assertThat(mController.getShortcutType()).isEqualTo(SOFTWARE);
}
private void enableTouchExploration(boolean enable) { private void enableTouchExploration(boolean enable) {
AccessibilityManager am = setupMockAccessibilityManager(mContext); AccessibilityManager am = setupMockAccessibilityManager(mContext);
when(am.isTouchExplorationEnabled()).thenReturn(enable); when(am.isTouchExplorationEnabled()).thenReturn(enable);

View File

@@ -54,6 +54,7 @@ import android.os.Bundle;
import android.os.CancellationSignal; import android.os.CancellationSignal;
import android.os.Looper; import android.os.Looper;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.Vibrator;
import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule; import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings; import android.provider.Settings;
@@ -128,6 +129,9 @@ public class FingerprintSettingsFragmentTest {
mAuthenticationCallbackArgumentCaptor = ArgumentCaptor.forClass( mAuthenticationCallbackArgumentCaptor = ArgumentCaptor.forClass(
FingerprintManager.AuthenticationCallback.class); FingerprintManager.AuthenticationCallback.class);
@Mock
private Vibrator mVibrator;
private FingerprintAuthenticateSidecar mFingerprintAuthenticateSidecar; private FingerprintAuthenticateSidecar mFingerprintAuthenticateSidecar;
private FingerprintRemoveSidecar mFingerprintRemoveSidecar; private FingerprintRemoveSidecar mFingerprintRemoveSidecar;
@@ -141,6 +145,7 @@ public class FingerprintSettingsFragmentTest {
doReturn(mContext).when(mFragment).getContext(); doReturn(mContext).when(mFragment).getContext();
doReturn(mBiometricManager).when(mContext).getSystemService(BiometricManager.class); doReturn(mBiometricManager).when(mContext).getSystemService(BiometricManager.class);
doReturn(true).when(mFingerprintManager).isHardwareDetected(); doReturn(true).when(mFingerprintManager).isHardwareDetected();
doReturn(mVibrator).when(mContext).getSystemService(Vibrator.class);
when(mBiometricManager.canAuthenticate( when(mBiometricManager.canAuthenticate(
BiometricManager.Authenticators.MANDATORY_BIOMETRICS)) BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
.thenReturn(BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE); .thenReturn(BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE);
@@ -287,6 +292,28 @@ public class FingerprintSettingsFragmentTest {
assertThat(mFragment.isVisible()).isTrue(); assertThat(mFragment.isVisible()).isTrue();
} }
@Test
@Ignore("b/353726774")
public void fingerprintVibratesOnAuthSuccess() {
setUpFragment(false);
doNothing().when(mFingerprintManager).authenticate(any(),
mCancellationSignalArgumentCaptor.capture(),
mAuthenticationCallbackArgumentCaptor.capture(), any(), anyInt());
mFingerprintAuthenticateSidecar.startAuthentication(1);
assertThat(mAuthenticationCallbackArgumentCaptor.getValue()).isNotNull();
assertThat(mCancellationSignalArgumentCaptor.getValue()).isNotNull();
mAuthenticationCallbackArgumentCaptor.getValue()
.onAuthenticationSucceeded(new FingerprintManager.AuthenticationResult(null,
new Fingerprint("finger 1", 1, 1), 0 /* userId */, false));
shadowOf(Looper.getMainLooper()).idle();
verify(mVibrator).vibrate(FingerprintSettings.SUCCESS_VIBRATION_EFFECT);
}
@Test @Test
public void testNotIndexable_whenDisabled() { public void testNotIndexable_whenDisabled() {
doReturn(mPackageManager).when(mContext).getPackageManager(); doReturn(mPackageManager).when(mContext).getPackageManager();

View File

@@ -1,293 +0,0 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.fuelgauge.batteryusage;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.Intent;
import android.provider.Settings;
import android.util.Pair;
import android.view.View;
import com.android.settings.DisplaySettings;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.testutils.BatteryTestUtils;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import java.util.Map;
import java.util.Optional;
import java.util.TimeZone;
@RunWith(RobolectricTestRunner.class)
public final class BatteryTipsCardPreferenceTest {
private Context mContext;
private FakeFeatureFactory mFeatureFactory;
private BatteryTipsCardPreference mBatteryTipsCardPreference;
private PowerUsageAdvanced mPowerUsageAdvanced;
private BatteryTipsController mBatteryTipsController;
private BatteryChartPreferenceController mBatteryChartPreferenceController;
@Mock private View mFakeView;
@Mock private BatteryUsageBreakdownController mBatteryUsageBreakdownController;
@Mock private BatteryDiffEntry mFakeEntry;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
mContext = spy(RuntimeEnvironment.application);
mFeatureFactory = FakeFeatureFactory.setupForTest();
mBatteryTipsCardPreference = new BatteryTipsCardPreference(mContext, /* attrs= */ null);
mBatteryTipsController = new BatteryTipsController(mContext);
mBatteryChartPreferenceController =
spy(new BatteryChartPreferenceController(mContext, null, null));
mBatteryChartPreferenceController.mPrefContext = mContext;
mBatteryTipsController.mCardPreference = mBatteryTipsCardPreference;
mPowerUsageAdvanced = spy(new PowerUsageAdvanced());
doReturn(mContext).when(mPowerUsageAdvanced).getContext();
mPowerUsageAdvanced.mBatteryTipsController = mBatteryTipsController;
mPowerUsageAdvanced.mBatteryChartPreferenceController = mBatteryChartPreferenceController;
mPowerUsageAdvanced.mBatteryUsageBreakdownController = mBatteryUsageBreakdownController;
mPowerUsageAdvanced.mBatteryLevelData =
Optional.of(
new BatteryLevelData(
Map.of(
1694354400000L, 1, // 2023-09-10 22:00:00
1694361600000L, 2, // 2023-09-11 00:00:00
1694368800000L, 3))); // 2023-09-11 02:00:00
doReturn("TestEntriesKey").when(mFakeEntry).getKey();
}
@Test
public void constructor_returnExpectedResult() {
assertThat(mBatteryTipsCardPreference.getLayoutResource())
.isEqualTo(R.layout.battery_tips_card);
}
@Test
public void onClick_mainBtnOfSettingsAnomalyLaunchPage_getAdaptiveBrightnessLauncher() {
final ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
PowerAnomalyEvent adaptiveBrightnessAnomaly =
BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent(/* changeSettings= */ false);
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
when(mFakeView.getId()).thenReturn(R.id.main_button);
doNothing().when(mContext).startActivity(captor.capture());
mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(
adaptiveBrightnessAnomaly, adaptiveBrightnessAnomaly);
mBatteryTipsCardPreference.onClick(mFakeView);
assertThat(mBatteryTipsCardPreference.isVisible()).isFalse();
verify(mContext).startActivity(any(Intent.class));
final Intent intent = captor.getValue();
assertThat(intent.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT))
.isEqualTo(DisplaySettings.class.getName());
assertThat(intent.getIntExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY, -1))
.isEqualTo(SettingsEnums.DISPLAY);
verify(mFeatureFactory.metricsFeatureProvider)
.action(
SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW,
SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
BatteryTipsController.ANOMALY_KEY,
PowerAnomalyKey.KEY_BRIGHTNESS.getNumber());
verify(mFeatureFactory.metricsFeatureProvider)
.action(
SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT,
SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
BatteryTipsController.ANOMALY_KEY,
PowerAnomalyKey.KEY_BRIGHTNESS.getNumber());
}
@Test
public void onClick_mainBtnOfSettingsAnomalyChangeSettings_settingsChanged()
throws Settings.SettingNotFoundException {
Settings.System.putInt(
mContext.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS_MODE,
Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
final ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
PowerAnomalyEvent adaptiveBrightnessAnomaly =
BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent(/* changeSettings= */ true);
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
when(mFakeView.getId()).thenReturn(R.id.main_button);
doNothing().when(mContext).startActivity(captor.capture());
mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(
adaptiveBrightnessAnomaly, adaptiveBrightnessAnomaly);
mBatteryTipsCardPreference.onClick(mFakeView);
assertThat(mBatteryTipsCardPreference.isVisible()).isFalse();
assertThat(
Settings.System.getInt(
mContext.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS_MODE))
.isEqualTo(Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
verify(mContext, never()).startActivity(any(Intent.class));
verify(mFeatureFactory.metricsFeatureProvider)
.action(
SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW,
SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
BatteryTipsController.ANOMALY_KEY,
PowerAnomalyKey.KEY_BRIGHTNESS.getNumber());
verify(mFeatureFactory.metricsFeatureProvider)
.action(
SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT,
SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
BatteryTipsController.ANOMALY_KEY,
PowerAnomalyKey.KEY_BRIGHTNESS.getNumber());
}
@Test
public void onClick_dismissBtnOfSettingsAnomaly_cardDismissAndLogged() {
final PowerAnomalyEvent screenTimeoutAnomaly =
BatteryTestUtils.createScreenTimeoutAnomalyEvent();
DatabaseUtils.removeDismissedPowerAnomalyKeys(mContext);
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
when(mFakeView.getId()).thenReturn(R.id.dismiss_button);
mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(
screenTimeoutAnomaly, screenTimeoutAnomaly);
mBatteryTipsCardPreference.onClick(mFakeView);
assertThat(mBatteryTipsCardPreference.isVisible()).isFalse();
assertThat(DatabaseUtils.getDismissedPowerAnomalyKeys(mContext)).hasSize(1);
assertThat(DatabaseUtils.getDismissedPowerAnomalyKeys(mContext))
.contains(PowerAnomalyKey.KEY_SCREEN_TIMEOUT.name());
verify(mFeatureFactory.metricsFeatureProvider)
.action(
SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW,
SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
BatteryTipsController.ANOMALY_KEY,
PowerAnomalyKey.KEY_SCREEN_TIMEOUT.getNumber());
verify(mFeatureFactory.metricsFeatureProvider)
.action(
SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
SettingsEnums.ACTION_BATTERY_TIPS_CARD_DISMISS,
SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
BatteryTipsController.ANOMALY_KEY,
PowerAnomalyKey.KEY_SCREEN_TIMEOUT.getNumber());
}
@Test
public void onClick_mainBtnOfAppsAnomaly_selectHighlightSlot() {
final PowerAnomalyEvent appsAnomaly = BatteryTestUtils.createAppAnomalyEvent();
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
when(mFakeView.getId()).thenReturn(R.id.main_button);
doNothing().when(mBatteryChartPreferenceController).selectHighlightSlotIndex();
when(mPowerUsageAdvanced.findRelatedBatteryDiffEntry(any())).thenReturn(mFakeEntry);
mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(appsAnomaly, appsAnomaly);
assertHighlightSlotIndexPair(1, 0);
mBatteryTipsCardPreference.onClick(mFakeView);
assertThat(mBatteryTipsCardPreference.isVisible()).isFalse();
verify(mContext, never()).startActivity(any(Intent.class));
verify(mBatteryChartPreferenceController).onHighlightSlotIndexUpdate(eq(1), eq(0));
verify(mBatteryChartPreferenceController).selectHighlightSlotIndex();
verify(mFeatureFactory.metricsFeatureProvider)
.action(
SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW,
SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
BatteryTipsController.ANOMALY_KEY,
PowerAnomalyKey.KEY_APP_TOTAL_HIGHER_THAN_USUAL.getNumber());
verify(mFeatureFactory.metricsFeatureProvider)
.action(
SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT,
SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
BatteryTipsController.ANOMALY_KEY,
PowerAnomalyKey.KEY_APP_TOTAL_HIGHER_THAN_USUAL.getNumber());
}
@Test
public void onClick_dismissBtnOfAppsAnomaly_keepHighlightSlotIndex() {
final PowerAnomalyEvent appsAnomaly = BatteryTestUtils.createAppAnomalyEvent();
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
when(mFakeView.getId()).thenReturn(R.id.dismiss_button);
when(mPowerUsageAdvanced.findRelatedBatteryDiffEntry(any())).thenReturn(mFakeEntry);
mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(appsAnomaly, appsAnomaly);
assertHighlightSlotIndexPair(1, 0);
mBatteryTipsCardPreference.onClick(mFakeView);
assertThat(mBatteryTipsCardPreference.isVisible()).isFalse();
verify(mContext, never()).startActivity(any(Intent.class));
verify(mBatteryChartPreferenceController).onHighlightSlotIndexUpdate(eq(1), eq(0));
verify(mBatteryChartPreferenceController, never()).selectHighlightSlotIndex();
verify(mFeatureFactory.metricsFeatureProvider)
.action(
SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW,
SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
BatteryTipsController.ANOMALY_KEY,
PowerAnomalyKey.KEY_APP_TOTAL_HIGHER_THAN_USUAL.getNumber());
verify(mFeatureFactory.metricsFeatureProvider)
.action(
SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
SettingsEnums.ACTION_BATTERY_TIPS_CARD_DISMISS,
SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
BatteryTipsController.ANOMALY_KEY,
PowerAnomalyKey.KEY_APP_TOTAL_HIGHER_THAN_USUAL.getNumber());
}
private void assertHighlightSlotIndexPair(
int dailyHighlightSlotIndex, int hourlyHighlightSlotIndex) {
assertThat(mPowerUsageAdvanced.mBatteryLevelData.isPresent()).isTrue();
assertThat(mPowerUsageAdvanced.mHighlightEventWrapper.isPresent()).isTrue();
Pair<Integer, Integer> slotIndexPair =
mPowerUsageAdvanced
.mHighlightEventWrapper
.get()
.getHighlightSlotPair(mPowerUsageAdvanced.mBatteryLevelData.get());
assertThat(slotIndexPair)
.isEqualTo(Pair.create(dailyHighlightSlotIndex, hourlyHighlightSlotIndex));
assertThat(mPowerUsageAdvanced.mBatteryChartPreferenceController.mDailyHighlightSlotIndex)
.isEqualTo(dailyHighlightSlotIndex);
assertThat(mPowerUsageAdvanced.mBatteryChartPreferenceController.mHourlyHighlightSlotIndex)
.isEqualTo(hourlyHighlightSlotIndex);
}
}

View File

@@ -16,8 +16,13 @@
package com.android.settings.fuelgauge.batteryusage; package com.android.settings.fuelgauge.batteryusage;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@@ -29,11 +34,11 @@ import android.os.LocaleList;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.testutils.BatteryTestUtils; import com.android.settings.testutils.BatteryTestUtils;
import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.widget.TipCardPreference;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
@@ -47,134 +52,156 @@ public final class BatteryTipsControllerTest {
private Context mContext; private Context mContext;
private FakeFeatureFactory mFeatureFactory; private FakeFeatureFactory mFeatureFactory;
private BatteryTipsController mBatteryTipsController; private BatteryTipsController mBatteryTipsController;
private TipCardPreference mCardPreference;
@Mock private BatteryTipsCardPreference mBatteryTipsCardPreference;
@Before @Before
public void setUp() { public void setUp() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
Locale.setDefault(new Locale("en_US")); Locale.setDefault(new Locale("en_US"));
org.robolectric.shadows.ShadowSettings.set24HourTimeFormat(false);
TimeZone.setDefault(TimeZone.getTimeZone("UTC")); TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
mContext = spy(RuntimeEnvironment.application); mContext = spy(RuntimeEnvironment.application);
final Resources resources = spy(mContext.getResources()); final Resources resources = spy(mContext.getResources());
resources.getConfiguration().setLocales(new LocaleList(new Locale("en_US"))); resources.getConfiguration().setLocales(new LocaleList(new Locale("en_US")));
doReturn(resources).when(mContext).getResources(); doReturn(resources).when(mContext).getResources();
mFeatureFactory = FakeFeatureFactory.setupForTest(); mFeatureFactory = FakeFeatureFactory.setupForTest();
mBatteryTipsController = new BatteryTipsController(mContext); mBatteryTipsController = spy(new BatteryTipsController(mContext));
mBatteryTipsController.mCardPreference = mBatteryTipsCardPreference; mCardPreference = new TipCardPreference(mContext);
mBatteryTipsController.mCardPreference = mCardPreference;
} }
@Test @Test
public void handleBatteryTipsCardUpdated_null_hidePreference() { public void handleBatteryTipsCardUpdated_null_hidePreference() {
mBatteryTipsController.handleBatteryTipsCardUpdated(/* powerAnomalyEvents= */ null, false); mBatteryTipsController.handleBatteryTipsCardUpdated(/* powerAnomalyEvents= */ null, false);
verify(mBatteryTipsCardPreference).setVisible(false); assertThat(mCardPreference.isVisible()).isFalse();
} }
@Test @Test
public void handleBatteryTipsCardUpdated_adaptiveBrightnessAnomaly_showAnomaly() { public void handleBatteryTipsCardUpdated_adaptiveBrightnessAnomaly_showAnomaly() {
PowerAnomalyEvent event = BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent(); AnomalyEventWrapper anomalyEventWrapper =
spy(
new AnomalyEventWrapper(
mContext,
BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent(true)));
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true); when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
mBatteryTipsController.handleBatteryTipsCardUpdated( mBatteryTipsController.handleBatteryTipsCardUpdated(anomalyEventWrapper, false);
new AnomalyEventWrapper(mContext, event), false);
// Check pre-defined string assertThat(mCardPreference.getTitle())
verify(mBatteryTipsCardPreference) .isEqualTo("Turn on adaptive brightness to extend battery life");
.setTitle("Turn on adaptive brightness to extend battery life"); assertThat(mCardPreference.getPrimaryButtonText()).isEqualTo("Got it");
verify(mBatteryTipsCardPreference).setIconResourceId(R.drawable.ic_battery_tips_lightbulb); assertThat(mCardPreference.getSecondaryButtonText()).isEqualTo("View Settings");
verify(mBatteryTipsCardPreference).setButtonColorResourceId(R.color.color_accent_selector); assertThat(mCardPreference.getIconResId()).isEqualTo(R.drawable.ic_battery_tips_lightbulb);
verify(mBatteryTipsCardPreference).setMainButtonLabel("View Settings"); assertThat(mCardPreference.getTintColorResId()).isEqualTo(R.color.color_accent_selector);
verify(mBatteryTipsCardPreference).setDismissButtonLabel("Got it"); assertThat(mCardPreference.getPrimaryButtonVisibility()).isTrue();
// Check proto info assertThat(mCardPreference.getSecondaryButtonVisibility()).isTrue();
verify(mBatteryTipsCardPreference).setVisible(true); assertCardButtonActionAndMetrics(anomalyEventWrapper);
verify(mFeatureFactory.metricsFeatureProvider)
.action(
SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW,
SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
BatteryTipsController.ANOMALY_KEY,
PowerAnomalyKey.KEY_BRIGHTNESS.getNumber());
} }
@Test @Test
public void handleBatteryTipsCardUpdated_screenTimeoutAnomaly_showAnomaly() { public void handleBatteryTipsCardUpdated_screenTimeoutAnomaly_showAnomaly() {
PowerAnomalyEvent event = BatteryTestUtils.createScreenTimeoutAnomalyEvent(); AnomalyEventWrapper anomalyEventWrapper =
spy(
new AnomalyEventWrapper(
mContext, BatteryTestUtils.createScreenTimeoutAnomalyEvent(true)));
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true); when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
mBatteryTipsController.handleBatteryTipsCardUpdated( mBatteryTipsController.handleBatteryTipsCardUpdated(anomalyEventWrapper, false);
new AnomalyEventWrapper(mContext, event), false);
verify(mBatteryTipsCardPreference).setTitle("Reduce screen timeout to extend battery life"); assertThat(mCardPreference.getTitle())
verify(mBatteryTipsCardPreference).setIconResourceId(R.drawable.ic_battery_tips_lightbulb); .isEqualTo("Reduce screen timeout to extend battery life");
verify(mBatteryTipsCardPreference).setButtonColorResourceId(R.color.color_accent_selector); assertThat(mCardPreference.getPrimaryButtonText()).isEqualTo("Got it");
verify(mBatteryTipsCardPreference).setMainButtonLabel("View Settings"); assertThat(mCardPreference.getSecondaryButtonText()).isEqualTo("View Settings");
verify(mBatteryTipsCardPreference).setDismissButtonLabel("Got it"); assertThat(mCardPreference.getIconResId()).isEqualTo(R.drawable.ic_battery_tips_lightbulb);
verify(mBatteryTipsCardPreference).setVisible(true); assertThat(mCardPreference.getTintColorResId()).isEqualTo(R.color.color_accent_selector);
verify(mFeatureFactory.metricsFeatureProvider) assertThat(mCardPreference.getPrimaryButtonVisibility()).isTrue();
.action( assertThat(mCardPreference.getSecondaryButtonVisibility()).isTrue();
SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL, assertCardButtonActionAndMetrics(anomalyEventWrapper);
SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW,
SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
BatteryTipsController.ANOMALY_KEY,
PowerAnomalyKey.KEY_SCREEN_TIMEOUT.getNumber());
} }
@Test @Test
public void handleBatteryTipsCardUpdated_screenTimeoutAnomalyHasTitle_showAnomaly() { public void handleBatteryTipsCardUpdated_screenTimeoutAnomalyHasTitle_showAnomaly() {
PowerAnomalyEvent event = BatteryTestUtils.createScreenTimeoutAnomalyEvent(); PowerAnomalyEvent anomalyEvent = BatteryTestUtils.createScreenTimeoutAnomalyEvent(true);
String testTitle = "TestTitle"; String testTitle = "TestTitle";
event = anomalyEvent =
event.toBuilder() anomalyEvent.toBuilder()
.setWarningBannerInfo( .setWarningBannerInfo(
event.getWarningBannerInfo().toBuilder() anomalyEvent.getWarningBannerInfo().toBuilder()
.setTitleString(testTitle) .setTitleString(testTitle)
.build()) .build())
.build(); .build();
AnomalyEventWrapper anomalyEventWrapper =
spy(new AnomalyEventWrapper(mContext, anomalyEvent));
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true); when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
mBatteryTipsController.handleBatteryTipsCardUpdated( mBatteryTipsController.handleBatteryTipsCardUpdated(anomalyEventWrapper, false);
new AnomalyEventWrapper(mContext, event), false);
verify(mBatteryTipsCardPreference).setTitle(testTitle); assertThat(mCardPreference.getTitle()).isEqualTo(testTitle);
verify(mBatteryTipsCardPreference).setIconResourceId(R.drawable.ic_battery_tips_lightbulb); assertThat(mCardPreference.getPrimaryButtonText()).isEqualTo("Got it");
verify(mBatteryTipsCardPreference).setButtonColorResourceId(R.color.color_accent_selector); assertThat(mCardPreference.getSecondaryButtonText()).isEqualTo("View Settings");
verify(mBatteryTipsCardPreference).setMainButtonLabel("View Settings"); assertThat(mCardPreference.getIconResId()).isEqualTo(R.drawable.ic_battery_tips_lightbulb);
verify(mBatteryTipsCardPreference).setDismissButtonLabel("Got it"); assertThat(mCardPreference.getTintColorResId()).isEqualTo(R.color.color_accent_selector);
verify(mBatteryTipsCardPreference).setVisible(true); assertThat(mCardPreference.getPrimaryButtonVisibility()).isTrue();
verify(mFeatureFactory.metricsFeatureProvider) assertThat(mCardPreference.getSecondaryButtonVisibility()).isTrue();
.action( assertCardButtonActionAndMetrics(anomalyEventWrapper);
SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW,
SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
BatteryTipsController.ANOMALY_KEY,
PowerAnomalyKey.KEY_SCREEN_TIMEOUT.getNumber());
} }
@Test @Test
public void handleBatteryTipsCardUpdated_appAnomaly_showAnomaly() { public void handleBatteryTipsCardUpdated_appAnomaly_showAnomaly() {
PowerAnomalyEvent event = BatteryTestUtils.createAppAnomalyEvent(); AnomalyEventWrapper anomalyEventWrapper =
spy(new AnomalyEventWrapper(mContext, BatteryTestUtils.createAppAnomalyEvent()));
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true); when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
AnomalyEventWrapper eventWrapper = new AnomalyEventWrapper(mContext, event); anomalyEventWrapper.setRelatedBatteryDiffEntry(
eventWrapper.setRelatedBatteryDiffEntry(new BatteryDiffEntry(mContext, "", "Chrome", 0)); new BatteryDiffEntry(mContext, "", "Chrome", 0));
mBatteryTipsController.handleBatteryTipsCardUpdated(eventWrapper, false); mBatteryTipsController.setOnAnomalyConfirmListener(
() -> mBatteryTipsController.acceptTipsCard());
mBatteryTipsController.handleBatteryTipsCardUpdated(anomalyEventWrapper, true);
verify(mBatteryTipsCardPreference).setTitle("Chrome used more battery than usual"); assertThat(mCardPreference.getTitle()).isEqualTo("Chrome used more battery than usual");
verify(mBatteryTipsCardPreference) assertThat(mCardPreference.getPrimaryButtonText()).isEqualTo("Got it");
.setIconResourceId(R.drawable.ic_battery_tips_warning_icon); assertThat(mCardPreference.getSecondaryButtonText()).isEqualTo("Check");
verify(mBatteryTipsCardPreference) assertThat(mCardPreference.getIconResId())
.setButtonColorResourceId(R.color.color_battery_anomaly_app_warning_selector); .isEqualTo(R.drawable.ic_battery_tips_warning_icon);
verify(mBatteryTipsCardPreference).setMainButtonLabel("Check"); assertThat(mCardPreference.getTintColorResId())
verify(mBatteryTipsCardPreference).setDismissButtonLabel("Got it"); .isEqualTo(R.color.color_battery_anomaly_app_warning_selector);
verify(mBatteryTipsCardPreference).setVisible(true); assertThat(mCardPreference.getPrimaryButtonVisibility()).isTrue();
assertThat(mCardPreference.getSecondaryButtonVisibility()).isTrue();
assertThat(mCardPreference.isVisible()).isTrue();
assertCardButtonActionAndMetrics(anomalyEventWrapper);
}
private void assertCardButtonActionAndMetrics(final AnomalyEventWrapper anomalyEventWrapper) {
when(anomalyEventWrapper.updateSystemSettingsIfAvailable()).thenReturn(true);
final int powerAnomalyKeyNumber = anomalyEventWrapper.getAnomalyKeyNumber();
assertCardMetrics(SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW, powerAnomalyKeyNumber);
assertThat(mCardPreference.isVisible()).isTrue();
// Check accept button action
mCardPreference.setVisible(true);
mCardPreference.getSecondaryButtonAction().invoke();
assertCardMetrics(SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT, powerAnomalyKeyNumber);
assertThat(mCardPreference.isVisible()).isFalse();
final boolean isAppAnomalyCard = powerAnomalyKeyNumber > 1;
verify(anomalyEventWrapper, isAppAnomalyCard ? never() : times(1))
.updateSystemSettingsIfAvailable();
// Check reject button action
mCardPreference.setVisible(true);
mCardPreference.getPrimaryButtonAction().invoke();
assertCardMetrics(SettingsEnums.ACTION_BATTERY_TIPS_CARD_DISMISS, powerAnomalyKeyNumber);
assertThat(mCardPreference.isVisible()).isFalse();
}
private void assertCardMetrics(final int action, final int powerAnomalyKeyNumber) {
verify(mFeatureFactory.metricsFeatureProvider) verify(mFeatureFactory.metricsFeatureProvider)
.action( .action(
SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL, SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW, action,
SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL, SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
BatteryTipsController.ANOMALY_KEY, BatteryTipsController.ANOMALY_KEY,
PowerAnomalyKey.KEY_APP_TOTAL_HIGHER_THAN_USUAL.getNumber()); powerAnomalyKeyNumber);
} }
} }

View File

@@ -30,7 +30,6 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@@ -131,12 +130,18 @@ public class SettingsSliceProviderTest {
CustomSliceRegistry.LOCATION_SLICE_URI CustomSliceRegistry.LOCATION_SLICE_URI
); );
private static final List<Uri> SPECIAL_CASE_OEM_URIS = Arrays.asList( private static final List<Uri> SPECIAL_CASE_OEM_URIS = android.app.Flags.modesUi()
CustomSliceRegistry.ZEN_MODE_SLICE_URI, ? Arrays.asList(
CustomSliceRegistry.FLASHLIGHT_SLICE_URI, CustomSliceRegistry.FLASHLIGHT_SLICE_URI,
CustomSliceRegistry.MOBILE_DATA_SLICE_URI, CustomSliceRegistry.MOBILE_DATA_SLICE_URI,
CustomSliceRegistry.WIFI_CALLING_URI CustomSliceRegistry.WIFI_CALLING_URI
); ) :
Arrays.asList(
CustomSliceRegistry.ZEN_MODE_SLICE_URI,
CustomSliceRegistry.FLASHLIGHT_SLICE_URI,
CustomSliceRegistry.MOBILE_DATA_SLICE_URI,
CustomSliceRegistry.WIFI_CALLING_URI
);
@Before @Before
public void setUp() { public void setUp() {

View File

@@ -20,6 +20,8 @@ import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATIN
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@@ -46,20 +48,15 @@ public class AccessibilityTestUtils {
public static void setSoftwareShortcutMode( public static void setSoftwareShortcutMode(
Context context, boolean gestureNavEnabled, boolean floatingButtonEnabled) { Context context, boolean gestureNavEnabled, boolean floatingButtonEnabled) {
int mode = floatingButtonEnabled ? ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU : -1; int buttonMode = floatingButtonEnabled ? ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU : -1;
int navMode = gestureNavEnabled ? NAV_BAR_MODE_GESTURAL : NAV_BAR_MODE_3BUTTON;
Settings.Secure.putInt(context.getContentResolver(), Settings.Secure.putInt(context.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, mode); Settings.Secure.ACCESSIBILITY_BUTTON_MODE, buttonMode);
SettingsShadowResources.overrideResource(
if (gestureNavEnabled) { com.android.internal.R.integer.config_navBarInteractionMode, navMode);
SettingsShadowResources.overrideResource( assertThat(context.getResources().getInteger(
com.android.internal.R.integer.config_navBarInteractionMode, com.android.internal.R.integer.config_navBarInteractionMode)).isEqualTo(navMode);
NAV_BAR_MODE_GESTURAL);
} else {
SettingsShadowResources.overrideResource(
com.android.internal.R.integer.config_navBarInteractionMode,
NAV_BAR_MODE_3BUTTON);
}
} }
/** /**

View File

@@ -264,18 +264,28 @@ public class BatteryTestUtils {
/** Create a power anomaly event proto of screen timeout. */ /** Create a power anomaly event proto of screen timeout. */
public static PowerAnomalyEvent createScreenTimeoutAnomalyEvent() { public static PowerAnomalyEvent createScreenTimeoutAnomalyEvent() {
return createScreenTimeoutAnomalyEvent(false);
}
/** Create a power anomaly event proto of screen timeout. */
public static PowerAnomalyEvent createScreenTimeoutAnomalyEvent(boolean changeSettings) {
WarningBannerInfo.Builder warningBannerInfoBuilder =
WarningBannerInfo.newBuilder()
.setMainButtonDestination(ScreenTimeoutSettings.class.getName())
.setMainButtonSourceMetricsCategory(SettingsEnums.SCREEN_TIMEOUT)
.setMainButtonSourceHighlightKey("60000");
if (changeSettings) {
warningBannerInfoBuilder
.setMainButtonConfigSettingsName(Settings.System.SCREEN_OFF_TIMEOUT)
.setMainButtonConfigSettingsValue(60000);
}
return PowerAnomalyEvent.newBuilder() return PowerAnomalyEvent.newBuilder()
.setEventId("ScreenTimeoutAnomaly") .setEventId("ScreenTimeoutAnomaly")
.setType(PowerAnomalyType.TYPE_SETTINGS_BANNER) .setType(PowerAnomalyType.TYPE_SETTINGS_BANNER)
.setKey(PowerAnomalyKey.KEY_SCREEN_TIMEOUT) .setKey(PowerAnomalyKey.KEY_SCREEN_TIMEOUT)
.setDismissRecordKey(PowerAnomalyKey.KEY_SCREEN_TIMEOUT.name()) .setDismissRecordKey(PowerAnomalyKey.KEY_SCREEN_TIMEOUT.name())
.setScore(1.1f) .setScore(1.1f)
.setWarningBannerInfo( .setWarningBannerInfo(warningBannerInfoBuilder.build())
WarningBannerInfo.newBuilder()
.setMainButtonDestination(ScreenTimeoutSettings.class.getName())
.setMainButtonSourceMetricsCategory(SettingsEnums.SCREEN_TIMEOUT)
.setMainButtonSourceHighlightKey("60000")
.build())
.build(); .build();
} }