Snap for 10832001 from 7c1b1fc934 to udc-qpr1-release
Change-Id: Ic61c84245a98aed84c1462f819c5634fdd6b1c39
This commit is contained in:
@@ -659,6 +659,7 @@
|
||||
<activity android:name="Settings$FaceSettingsActivity"
|
||||
android:label="@string/security_settings_face_preference_title"
|
||||
android:exported="true"
|
||||
android:theme="@style/Theme.Settings.NoActionBar"
|
||||
android:icon="@drawable/ic_face_header">
|
||||
<intent-filter>
|
||||
<action android:name="android.settings.FACE_SETTINGS" />
|
||||
@@ -673,6 +674,7 @@
|
||||
<activity android:name="Settings$FaceSettingsInternalActivity"
|
||||
android:label="@string/security_settings_face_preference_title"
|
||||
android:exported="false"
|
||||
android:theme="@style/Theme.Settings.NoActionBar"
|
||||
android:icon="@drawable/ic_face_header"
|
||||
android:taskAffinity="com.android.settings.root">
|
||||
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
|
||||
|
||||
22
res/drawable/battery_hints_chip_bg.xml
Normal file
22
res/drawable/battery_hints_chip_bg.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?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:radius="@dimen/battery_hints_chip_corner_radius" />
|
||||
</shape>
|
||||
21
res/drawable/battery_hints_chip_bg_ripple.xml
Normal file
21
res/drawable/battery_hints_chip_bg_ripple.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?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_hints_chip_bg"/>
|
||||
</ripple>
|
||||
67
res/layout/anomaly_app_item_preference.xml
Normal file
67
res/layout/anomaly_app_item_preference.xml
Normal file
@@ -0,0 +1,67 @@
|
||||
<?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.
|
||||
-->
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include layout="@layout/preference_app"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/warning_chip"
|
||||
android:visibility="gone"
|
||||
android:clickable="false"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
|
||||
|
||||
<Space
|
||||
android:layout_width="@dimen/secondary_app_icon_size"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="8dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:background="@drawable/battery_hints_chip_bg_ripple">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_gravity="center_vertical|start"
|
||||
android:contentDescription="@string/battery_hints_warning_icon_a11y"
|
||||
android:src="@drawable/ic_battery_tips_warning_icon" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/warning_info"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="8dp"
|
||||
android:layout_gravity="center_vertical|start"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="?android:attr/textColorPrimary"/>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -1420,20 +1420,49 @@
|
||||
<item>color_battery_anomaly_yellow_selector</item>
|
||||
</string-array>
|
||||
|
||||
<!-- The following 3 arrays are for power anomaly tips card. Please keep them the same size. -->
|
||||
<string-array name="power_anomaly_titles">
|
||||
<item>Turn on adaptive brightness to extend battery life</item>
|
||||
<item>Reduce screen timeout to extend battery life</item>
|
||||
<!-- The following 4 arrays are for power anomaly tips card. Please keep them the same size. -->
|
||||
<string-array name="power_anomaly_title_ids" translatable="false">
|
||||
<item>battery_tips_settings_summary_brightness</item>
|
||||
<item>battery_tips_settings_summary_screen_timeout</item>
|
||||
<item>battery_tips_apps_summary_always_high</item>
|
||||
<item>battery_tips_apps_summary_higher_than_usual</item>
|
||||
<item>battery_tips_apps_summary_always_high_in_background</item>
|
||||
<item>battery_tips_apps_summary_higher_than_usual_in_background</item>
|
||||
<item>battery_tips_apps_summary_always_high_in_foreground</item>
|
||||
<item>battery_tips_apps_summary_higher_than_usual_in_foreground</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="power_anomaly_main_btn_strings" translatable="false">
|
||||
<item>@string/battery_tips_card_action_button</item>
|
||||
<item>@string/battery_tips_card_action_button</item>
|
||||
<item>@string/battery_tips_card_action_button_check</item>
|
||||
<item>@string/battery_tips_card_action_button_check</item>
|
||||
<item>@string/battery_tips_card_action_button_check</item>
|
||||
<item>@string/battery_tips_card_action_button_check</item>
|
||||
<item>@string/battery_tips_card_action_button_check</item>
|
||||
<item>@string/battery_tips_card_action_button_check</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="power_anomaly_dismiss_btn_strings" translatable="false">
|
||||
<item>@string/battery_tips_card_dismiss_button</item>
|
||||
<item>@string/battery_tips_card_dismiss_button</item>
|
||||
<item>@string/battery_tips_card_dismiss_button</item>
|
||||
<item>@string/battery_tips_card_dismiss_button</item>
|
||||
<item>@string/battery_tips_card_dismiss_button</item>
|
||||
<item>@string/battery_tips_card_dismiss_button</item>
|
||||
<item>@string/battery_tips_card_dismiss_button</item>
|
||||
<item>@string/battery_tips_card_dismiss_button</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="power_anomaly_hint_messages" translatable="false">
|
||||
<item></item>
|
||||
<item></item>
|
||||
<item>@string/battery_app_item_hint</item>
|
||||
<item>@string/battery_app_item_hint</item>
|
||||
<item>@string/battery_app_item_hint_in_bg</item>
|
||||
<item>@string/battery_app_item_hint_in_bg</item>
|
||||
<item>@string/battery_app_item_hint_in_fg</item>
|
||||
<item>@string/battery_app_item_hint_in_fg</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -382,6 +382,7 @@
|
||||
<!-- Battery tips card view component -->
|
||||
<dimen name="battery_tips_card_corner_radius_small">4dp</dimen>
|
||||
<dimen name="battery_tips_card_corner_radius_normal">24dp</dimen>
|
||||
<dimen name="battery_hints_chip_corner_radius">8dp</dimen>
|
||||
|
||||
<!-- Dimensions for Dream settings cards -->
|
||||
<dimen name="dream_item_min_column_width">174dp</dimen>
|
||||
|
||||
@@ -7252,7 +7252,7 @@
|
||||
<string name="vibrate_when_ringing_option_ramping_ringer">Vibrate first then ring gradually</string>
|
||||
|
||||
<!-- Sound: Title for the option enabling spatializer effect. [CHAR LIMIT=30] -->
|
||||
<string name="spatial_audio_title">Spatial audio</string>
|
||||
<string name="spatial_audio_title">Spatial Audio</string>
|
||||
|
||||
<!-- Sound: Other sounds: Title for the option enabling touch sounds for dial pad tones. [CHAR LIMIT=30] -->
|
||||
<string name="dial_pad_tones_title">Dial pad tones</string>
|
||||
@@ -7300,7 +7300,11 @@
|
||||
<string name="live_caption_summary">Automatically caption media</string>
|
||||
|
||||
<!-- Output device type for the phone speaker that is available for spatializer effect. [CHAR LIMIT=NONE]-->
|
||||
<string name="spatial_audio_speaker">Phone speaker</string>
|
||||
<string name="spatial_audio_speaker" product="default">Phone speakers</string>
|
||||
<!-- Output device type for the phone speaker that is available for spatializer effect. [CHAR LIMIT=NONE]-->
|
||||
<string name="spatial_audio_speaker" product="tablet">Tablet speakers</string>
|
||||
<!-- Output device type for the phone speaker that is available for spatializer effect. [CHAR LIMIT=NONE]-->
|
||||
<string name="spatial_audio_speaker" product="device">Device speakers</string>
|
||||
|
||||
<!-- Output device type for the wired headphones that is available for spatializer effect. [CHAR LIMIT=NONE]-->
|
||||
<string name="spatial_audio_wired_headphones">Wired headphones</string>
|
||||
@@ -9688,12 +9692,51 @@
|
||||
<!-- Label of action button in battery tips card [CHAR LIMIT=50] -->
|
||||
<string name="battery_tips_card_action_button">View Settings</string>
|
||||
|
||||
<!-- Label of action button in battery tips card [CHAR LIMIT=50] -->
|
||||
<string name="battery_tips_card_action_button_check">Check</string>
|
||||
|
||||
<!-- Label of dismiss button in battery tips card [CHAR LIMIT=50] -->
|
||||
<string name="battery_tips_card_dismiss_button">Got it</string>
|
||||
|
||||
<!-- Feedback card message in battery tips card [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_tips_card_feedback_info">Is this message helpful?</string>
|
||||
|
||||
<!-- Content description for battery hints warning icon of app anomaly [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_hints_warning_icon_a11y">Battery tips warning icon</string>
|
||||
|
||||
<!-- Summary of settings anomaly for adaptive brightness [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_tips_settings_summary_brightness">Turn on adaptive brightness to extend battery life</string>
|
||||
|
||||
<!-- Summary of settings anomaly for screen timeout [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_tips_settings_summary_screen_timeout">Reduce screen timeout to extend battery life</string>
|
||||
|
||||
<!-- Summary of apps anomaly for always high [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_tips_apps_summary_always_high"><xliff:g id="app_label" example="Pokemon Go">%1$s</xliff:g> used more battery</string>
|
||||
|
||||
<!-- Summary of apps anomaly for higher than usual [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_tips_apps_summary_higher_than_usual"><xliff:g id="app_label" example="Pokemon Go">%1$s</xliff:g> used more battery than usual</string>
|
||||
|
||||
<!-- Summary of apps anomaly for always high in background [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_tips_apps_summary_always_high_in_background"><xliff:g id="app_label" example="Pokemon Go">%1$s</xliff:g> used more battery while in the background</string>
|
||||
|
||||
<!-- Summary of apps anomaly for higher than usual in background [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_tips_apps_summary_higher_than_usual_in_background"><xliff:g id="app_label" example="Pokemon Go">%1$s</xliff:g> used more battery than usual while in the background</string>
|
||||
|
||||
<!-- Summary of apps anomaly for always high in foreground [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_tips_apps_summary_always_high_in_foreground"><xliff:g id="app_label" example="Pokemon Go">%1$s</xliff:g> used more battery while in the foreground</string>
|
||||
|
||||
<!-- Summary of apps anomaly for higher than usual in foreground [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_tips_apps_summary_higher_than_usual_in_foreground"><xliff:g id="app_label" example="Pokemon Go">%1$s</xliff:g> used more battery than usual while in the foreground</string>
|
||||
|
||||
<!-- Label of hint for apps anomaly in battery usage [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_app_item_hint">High battery usage</string>
|
||||
|
||||
<!-- Label of hint for apps background anomaly in battery usage [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_app_item_hint_in_bg">High battery usage in the background</string>
|
||||
|
||||
<!-- Label of hint for apps foreground anomaly in battery usage [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_app_item_hint_in_fg">High battery usage in the foreground</string>
|
||||
|
||||
<!-- Filter title for battery unrestricted[CHAR_LIMIT=50]-->
|
||||
<string name="filter_battery_unrestricted_title">Unrestricted</string>
|
||||
|
||||
|
||||
@@ -69,7 +69,9 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
|
||||
private static final String ENABLE_DUAL_MODE_AUDIO =
|
||||
"persist.bluetooth.enable_dual_mode_audio";
|
||||
private static final String CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT = "le_audio_enabled_by_default";
|
||||
private static final boolean LE_AUDIO_DEVICE_DETAIL_DEFAULT_VALUE = true;
|
||||
private static final boolean LE_AUDIO_TOGGLE_VISIBLE_DEFAULT_VALUE = true;
|
||||
private static final String LE_AUDIO_TOGGLE_VISIBLE_PROPERTY =
|
||||
"persist.bluetooth.leaudio.toggle_visible";
|
||||
|
||||
private LocalBluetoothManager mManager;
|
||||
private LocalBluetoothProfileManager mProfileManager;
|
||||
@@ -464,15 +466,13 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
|
||||
private void updateLeAudioConfig() {
|
||||
mIsLeContactSharingEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SETTINGS_UI,
|
||||
SettingsUIDeviceConfig.BT_LE_AUDIO_CONTACT_SHARING_ENABLED, true);
|
||||
boolean isLeDeviceDetailEnabled = DeviceConfig.getBoolean(
|
||||
DeviceConfig.NAMESPACE_SETTINGS_UI,
|
||||
SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED,
|
||||
LE_AUDIO_DEVICE_DETAIL_DEFAULT_VALUE);
|
||||
boolean isLeAudioToggleVisible = SystemProperties.getBoolean(
|
||||
LE_AUDIO_TOGGLE_VISIBLE_PROPERTY, LE_AUDIO_TOGGLE_VISIBLE_DEFAULT_VALUE);
|
||||
boolean isLeEnabledByDefault = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_BLUETOOTH,
|
||||
CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT, false);
|
||||
mIsLeAudioToggleEnabled = isLeDeviceDetailEnabled || isLeEnabledByDefault;
|
||||
mIsLeAudioToggleEnabled = isLeAudioToggleVisible || isLeEnabledByDefault;
|
||||
Log.d(TAG, "BT_LE_AUDIO_CONTACT_SHARING_ENABLED:" + mIsLeContactSharingEnabled
|
||||
+ ", BT_LE_AUDIO_DEVICE_DETAIL_ENABLED:" + isLeDeviceDetailEnabled
|
||||
+ ", LE_AUDIO_TOGGLE_VISIBLE_PROPERTY:" + isLeAudioToggleVisible
|
||||
+ ", CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT:" + isLeEnabledByDefault);
|
||||
}
|
||||
|
||||
|
||||
@@ -42,9 +42,4 @@ public class SettingsUIDeviceConfig {
|
||||
* {@code true} whether or not event_log for generic actions is enabled. Default is true.
|
||||
*/
|
||||
public static final String GENERIC_EVENT_LOGGING_ENABLED = "event_logging_enabled";
|
||||
/**
|
||||
* {@code true} whether to show LE Audio toggle in device detail page. Default is false.
|
||||
*/
|
||||
public static final String BT_LE_AUDIO_DEVICE_DETAIL_ENABLED =
|
||||
"bt_le_audio_device_detail_enabled";
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothManager;
|
||||
import android.bluetooth.BluetoothStatusCodes;
|
||||
import android.content.Context;
|
||||
import android.os.SystemProperties;
|
||||
import android.provider.DeviceConfig;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
@@ -27,7 +28,6 @@ import androidx.preference.Preference;
|
||||
import androidx.preference.SwitchPreference;
|
||||
|
||||
import com.android.settings.core.PreferenceControllerMixin;
|
||||
import com.android.settings.core.SettingsUIDeviceConfig;
|
||||
import com.android.settingslib.development.DeveloperOptionsPreferenceController;
|
||||
|
||||
/**
|
||||
@@ -40,9 +40,12 @@ public class BluetoothLeAudioDeviceDetailsPreferenceController
|
||||
|
||||
private static final String PREFERENCE_KEY = "bluetooth_show_leaudio_device_details";
|
||||
private static final String CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT = "le_audio_enabled_by_default";
|
||||
private static final boolean LE_AUDIO_DEVICE_DETAIL_DEFAULT_VALUE = true;
|
||||
private static final boolean LE_AUDIO_TOGGLE_VISIBLE_DEFAULT_VALUE = true;
|
||||
static int sLeAudioSupportedStateCache = BluetoothStatusCodes.ERROR_UNKNOWN;
|
||||
|
||||
static final String LE_AUDIO_TOGGLE_VISIBLE_PROPERTY =
|
||||
"persist.bluetooth.leaudio.toggle_visible";
|
||||
|
||||
@VisibleForTesting
|
||||
BluetoothAdapter mBluetoothAdapter;
|
||||
|
||||
@@ -73,10 +76,7 @@ public class BluetoothLeAudioDeviceDetailsPreferenceController
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
final boolean isEnabled = (Boolean) newValue;
|
||||
DeviceConfig.setProperty(
|
||||
DeviceConfig.NAMESPACE_SETTINGS_UI,
|
||||
SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED,
|
||||
isEnabled ? "true" : "false", LE_AUDIO_DEVICE_DETAIL_DEFAULT_VALUE);
|
||||
SystemProperties.set(LE_AUDIO_TOGGLE_VISIBLE_PROPERTY, Boolean.toString(isEnabled));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -86,25 +86,13 @@ public class BluetoothLeAudioDeviceDetailsPreferenceController
|
||||
return;
|
||||
}
|
||||
|
||||
final boolean leAudioDeviceDetailEnabled = DeviceConfig.getBoolean(
|
||||
DeviceConfig.NAMESPACE_SETTINGS_UI,
|
||||
SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED,
|
||||
LE_AUDIO_DEVICE_DETAIL_DEFAULT_VALUE);
|
||||
final boolean isLeAudioToggleVisible = SystemProperties.getBoolean(
|
||||
LE_AUDIO_TOGGLE_VISIBLE_PROPERTY, LE_AUDIO_TOGGLE_VISIBLE_DEFAULT_VALUE);
|
||||
final boolean leAudioEnabledByDefault = DeviceConfig.getBoolean(
|
||||
DeviceConfig.NAMESPACE_BLUETOOTH, CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT, false);
|
||||
|
||||
mPreference.setEnabled(!leAudioEnabledByDefault);
|
||||
((SwitchPreference) mPreference).setChecked(leAudioDeviceDetailEnabled
|
||||
((SwitchPreference) mPreference).setChecked(isLeAudioToggleVisible
|
||||
|| leAudioEnabledByDefault);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDeveloperOptionsSwitchDisabled() {
|
||||
super.onDeveloperOptionsSwitchDisabled();
|
||||
// Reset the toggle to null when the developer option is disabled
|
||||
DeviceConfig.setProperty(
|
||||
DeviceConfig.NAMESPACE_SETTINGS_UI,
|
||||
SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, "null",
|
||||
LE_AUDIO_DEVICE_DETAIL_DEFAULT_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.preference.PreferenceViewHolder;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
class AnomalyAppItemPreference extends PowerGaugePreference {
|
||||
|
||||
private static final String TAG = "AnomalyAppItemPreference";
|
||||
|
||||
private CharSequence mAnomalyHintText;
|
||||
|
||||
AnomalyAppItemPreference(Context context) {
|
||||
super(context, /* attrs */ null);
|
||||
setLayoutResource(R.layout.anomaly_app_item_preference);
|
||||
}
|
||||
|
||||
void setAnomalyHint(CharSequence anomalyHintText) {
|
||||
if (!TextUtils.equals(mAnomalyHintText, anomalyHintText)) {
|
||||
mAnomalyHintText = anomalyHintText;
|
||||
notifyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(PreferenceViewHolder viewHolder) {
|
||||
super.onBindViewHolder(viewHolder);
|
||||
final LinearLayout warningChipView =
|
||||
(LinearLayout) viewHolder.findViewById(R.id.warning_chip);
|
||||
|
||||
if (!TextUtils.isEmpty(mAnomalyHintText)) {
|
||||
((TextView) warningChipView.findViewById(R.id.warning_info)).setText(mAnomalyHintText);
|
||||
warningChipView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
warningChipView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* 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.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
final class AnomalyEventWrapper {
|
||||
private static final String TAG = "AnomalyEventWrapper";
|
||||
|
||||
private final Context mContext;
|
||||
private final PowerAnomalyEvent mPowerAnomalyEvent;
|
||||
|
||||
private final int mCardStyleId;
|
||||
private final int mResourceIndex;
|
||||
|
||||
private SubSettingLauncher mSubSettingLauncher = null;
|
||||
private Pair<Integer, Integer> mHighlightSlotPair = null;
|
||||
private BatteryDiffEntry mRelatedBatteryDiffEntry = null;
|
||||
|
||||
AnomalyEventWrapper(Context context, PowerAnomalyEvent powerAnomalyEvent) {
|
||||
mContext = context;
|
||||
mPowerAnomalyEvent = powerAnomalyEvent;
|
||||
// Set basic battery tips card info
|
||||
mCardStyleId = mPowerAnomalyEvent.getType().getNumber();
|
||||
mResourceIndex = mPowerAnomalyEvent.getKey().getNumber();
|
||||
}
|
||||
|
||||
private <T> T getInfo(Function<WarningBannerInfo, T> warningBannerInfoSupplier,
|
||||
Function<WarningItemInfo, T> warningItemInfoSupplier) {
|
||||
if (warningBannerInfoSupplier != null && mPowerAnomalyEvent.hasWarningBannerInfo()) {
|
||||
return warningBannerInfoSupplier.apply(mPowerAnomalyEvent.getWarningBannerInfo());
|
||||
} else if (warningItemInfoSupplier != null && mPowerAnomalyEvent.hasWarningItemInfo()) {
|
||||
return warningItemInfoSupplier.apply(mPowerAnomalyEvent.getWarningItemInfo());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private int getResourceId(int resourceId, int resourceIndex, String defType) {
|
||||
final String key = getStringFromArrayResource(resourceId, resourceIndex);
|
||||
return TextUtils.isEmpty(key) ? 0
|
||||
: mContext.getResources().getIdentifier(key, defType, mContext.getPackageName());
|
||||
}
|
||||
|
||||
private String getString(Function<WarningBannerInfo, String> warningBannerInfoSupplier,
|
||||
Function<WarningItemInfo, String> warningItemInfoSupplier,
|
||||
int resourceId, int resourceIndex) {
|
||||
final String string = getInfo(warningBannerInfoSupplier, warningItemInfoSupplier);
|
||||
return (!TextUtils.isEmpty(string) || resourceId <= 0) ? string
|
||||
: getStringFromArrayResource(resourceId, resourceIndex);
|
||||
}
|
||||
|
||||
private String getStringFromArrayResource(int resourceId, int resourceIndex) {
|
||||
if (resourceId <= 0 || resourceIndex < 0) {
|
||||
return null;
|
||||
}
|
||||
final String[] stringArray = mContext.getResources().getStringArray(resourceId);
|
||||
return (resourceIndex >= 0 && resourceIndex < stringArray.length)
|
||||
? stringArray[resourceIndex] : null;
|
||||
}
|
||||
|
||||
void setRelatedBatteryDiffEntry(BatteryDiffEntry batteryDiffEntry) {
|
||||
mRelatedBatteryDiffEntry = batteryDiffEntry;
|
||||
}
|
||||
|
||||
String getEventId() {
|
||||
return mPowerAnomalyEvent.hasEventId() ? mPowerAnomalyEvent.getEventId() : null;
|
||||
}
|
||||
|
||||
int getIconResId() {
|
||||
return getResourceId(R.array.battery_tips_card_icons, mCardStyleId, "drawable");
|
||||
}
|
||||
|
||||
int getColorResId() {
|
||||
return getResourceId(R.array.battery_tips_card_colors, mCardStyleId, "color");
|
||||
}
|
||||
|
||||
String getTitleString() {
|
||||
final String protoTitleString = getInfo(WarningBannerInfo::getTitleString,
|
||||
WarningItemInfo::getTitleString);
|
||||
if (!TextUtils.isEmpty(protoTitleString)) {
|
||||
return protoTitleString;
|
||||
}
|
||||
final int titleFormatResId = getResourceId(R.array.power_anomaly_title_ids,
|
||||
mResourceIndex, "string");
|
||||
if (mPowerAnomalyEvent.hasWarningBannerInfo()) {
|
||||
return mContext.getString(titleFormatResId);
|
||||
} else if (mPowerAnomalyEvent.hasWarningItemInfo() && mRelatedBatteryDiffEntry != null) {
|
||||
final String appLabel = mRelatedBatteryDiffEntry.getAppLabel();
|
||||
return mContext.getString(titleFormatResId, appLabel);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
String getMainBtnString() {
|
||||
return getString(WarningBannerInfo::getMainButtonString,
|
||||
WarningItemInfo::getMainButtonString,
|
||||
R.array.power_anomaly_main_btn_strings, mResourceIndex);
|
||||
}
|
||||
|
||||
String getDismissBtnString() {
|
||||
return getString(WarningBannerInfo::getCancelButtonString,
|
||||
WarningItemInfo::getCancelButtonString,
|
||||
R.array.power_anomaly_dismiss_btn_strings, mResourceIndex);
|
||||
}
|
||||
|
||||
String getAnomalyHintString() {
|
||||
return getStringFromArrayResource(R.array.power_anomaly_hint_messages, mResourceIndex);
|
||||
}
|
||||
|
||||
String getDismissRecordKey() {
|
||||
return mPowerAnomalyEvent.getDismissRecordKey();
|
||||
}
|
||||
|
||||
boolean hasAnomalyEntryKey() {
|
||||
return getAnomalyEntryKey() != null;
|
||||
}
|
||||
|
||||
String getAnomalyEntryKey() {
|
||||
return mPowerAnomalyEvent.hasWarningItemInfo()
|
||||
&& mPowerAnomalyEvent.getWarningItemInfo().hasItemKey()
|
||||
? mPowerAnomalyEvent.getWarningItemInfo().getItemKey() : null;
|
||||
}
|
||||
|
||||
boolean hasSubSettingLauncher() {
|
||||
if (mSubSettingLauncher == null) {
|
||||
mSubSettingLauncher = getSubSettingLauncher();
|
||||
}
|
||||
return mSubSettingLauncher != null;
|
||||
}
|
||||
|
||||
SubSettingLauncher getSubSettingLauncher() {
|
||||
if (mSubSettingLauncher != null) {
|
||||
return mSubSettingLauncher;
|
||||
}
|
||||
final String destinationClassName = getInfo(
|
||||
WarningBannerInfo::getMainButtonDestination, null);
|
||||
if (!TextUtils.isEmpty(destinationClassName)) {
|
||||
final Integer sourceMetricsCategory = getInfo(
|
||||
WarningBannerInfo::getMainButtonSourceMetricsCategory, null);
|
||||
final String preferenceHighlightKey = getInfo(
|
||||
WarningBannerInfo::getMainButtonSourceHighlightKey, null);
|
||||
Bundle arguments = Bundle.EMPTY;
|
||||
if (!TextUtils.isEmpty(preferenceHighlightKey)) {
|
||||
arguments = new Bundle(1);
|
||||
arguments.putString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY,
|
||||
preferenceHighlightKey);
|
||||
}
|
||||
mSubSettingLauncher = new SubSettingLauncher(mContext)
|
||||
.setDestination(destinationClassName)
|
||||
.setSourceMetricsCategory(sourceMetricsCategory)
|
||||
.setArguments(arguments);
|
||||
}
|
||||
return mSubSettingLauncher;
|
||||
}
|
||||
|
||||
boolean hasHighlightSlotPair(BatteryLevelData batteryLevelData) {
|
||||
if (mHighlightSlotPair == null) {
|
||||
mHighlightSlotPair = getHighlightSlotPair(batteryLevelData);
|
||||
}
|
||||
return mHighlightSlotPair != null;
|
||||
}
|
||||
|
||||
Pair<Integer, Integer> getHighlightSlotPair(BatteryLevelData batteryLevelData) {
|
||||
if (mHighlightSlotPair != null) {
|
||||
return mHighlightSlotPair;
|
||||
}
|
||||
if (!mPowerAnomalyEvent.hasWarningItemInfo()) {
|
||||
return null;
|
||||
}
|
||||
final WarningItemInfo warningItemInfo = mPowerAnomalyEvent.getWarningItemInfo();
|
||||
final Long startTimestamp = warningItemInfo.hasStartTimestamp()
|
||||
? warningItemInfo.getStartTimestamp() : null;
|
||||
final Long endTimestamp = warningItemInfo.hasEndTimestamp()
|
||||
? warningItemInfo.getEndTimestamp() : null;
|
||||
if (startTimestamp != null && endTimestamp != null) {
|
||||
mHighlightSlotPair = batteryLevelData
|
||||
.getIndexByTimestamps(startTimestamp, endTimestamp);
|
||||
if (mHighlightSlotPair.first == BatteryChartViewModel.SELECTED_INDEX_INVALID
|
||||
|| mHighlightSlotPair.second == BatteryChartViewModel.SELECTED_INDEX_INVALID) {
|
||||
// Drop invalid mHighlightSlotPair index
|
||||
mHighlightSlotPair = null;
|
||||
}
|
||||
}
|
||||
return mHighlightSlotPair;
|
||||
}
|
||||
|
||||
boolean updateTipsCardPreference(BatteryTipsCardPreference preference) {
|
||||
final String titleString = getTitleString();
|
||||
if (TextUtils.isEmpty(titleString)) {
|
||||
return false;
|
||||
}
|
||||
preference.setTitle(titleString);
|
||||
preference.setIconResourceId(getIconResId());
|
||||
preference.setMainButtonStrokeColorResourceId(getColorResId());
|
||||
preference.setMainButtonLabel(getMainBtnString());
|
||||
preference.setDismissButtonLabel(getDismissBtnString());
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean launchSubSetting() {
|
||||
if (!hasSubSettingLauncher()) {
|
||||
return false;
|
||||
}
|
||||
// Navigate to sub setting page
|
||||
mSubSettingLauncher.launch();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -221,14 +221,20 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
|
||||
refreshUi();
|
||||
}
|
||||
|
||||
boolean isHighlightSlotFocused() {
|
||||
return (mDailyHighlightSlotIndex != BatteryChartViewModel.SELECTED_INDEX_INVALID
|
||||
&& mDailyHighlightSlotIndex == mDailyChartIndex
|
||||
&& mHourlyHighlightSlotIndex != BatteryChartViewModel.SELECTED_INDEX_INVALID
|
||||
&& mHourlyHighlightSlotIndex == mHourlyChartIndex);
|
||||
}
|
||||
|
||||
void onHighlightSlotIndexUpdate(int dailyHighlightSlotIndex, int hourlyHighlightSlotIndex) {
|
||||
if (mDailyHighlightSlotIndex == dailyHighlightSlotIndex
|
||||
&& mHourlyHighlightSlotIndex == hourlyHighlightSlotIndex) {
|
||||
return;
|
||||
}
|
||||
mDailyHighlightSlotIndex = dailyHighlightSlotIndex;
|
||||
mHourlyHighlightSlotIndex = hourlyHighlightSlotIndex;
|
||||
refreshUi();
|
||||
if (mOnSelectedIndexUpdatedListener != null) {
|
||||
mOnSelectedIndexUpdatedListener.onSelectedIndexUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
void selectHighlightSlotIndex() {
|
||||
@@ -405,7 +411,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
|
||||
final String slotInformation = getSlotInformation();
|
||||
return slotInformation == null
|
||||
? mPrefContext.getString(
|
||||
R.string.battery_usage_breakdown_title_since_last_full_charge)
|
||||
R.string.battery_usage_breakdown_title_since_last_full_charge)
|
||||
: mPrefContext.getString(
|
||||
R.string.battery_usage_breakdown_title_for_slot, slotInformation);
|
||||
}
|
||||
|
||||
@@ -120,12 +120,10 @@ public class BatteryTipsCardPreference extends Preference implements View.OnClic
|
||||
public void onClick(View view) {
|
||||
final int viewId = view.getId();
|
||||
if (viewId == R.id.main_button || viewId == R.id.tips_card) {
|
||||
setVisible(false);
|
||||
if (mOnConfirmListener != null) {
|
||||
mOnConfirmListener.onConfirm();
|
||||
}
|
||||
} else if (viewId == R.id.dismiss_button) {
|
||||
setVisible(false);
|
||||
if (mOnRejectListener != null) {
|
||||
mOnRejectListener.onReject();
|
||||
}
|
||||
|
||||
@@ -18,21 +18,15 @@ package com.android.settings.fuelgauge.batteryusage;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
/** Controls the update for battery tips card */
|
||||
public class BatteryTipsController extends BasePreferenceController {
|
||||
|
||||
@@ -59,6 +53,10 @@ public class BatteryTipsController extends BasePreferenceController {
|
||||
|
||||
@VisibleForTesting
|
||||
BatteryTipsCardPreference mCardPreference;
|
||||
@VisibleForTesting
|
||||
AnomalyEventWrapper mAnomalyEventWrapper = null;
|
||||
@VisibleForTesting
|
||||
Boolean mIsAcceptable = false;
|
||||
|
||||
public BatteryTipsController(Context context) {
|
||||
super(context, ROOT_PREFERENCE_KEY);
|
||||
@@ -85,132 +83,56 @@ public class BatteryTipsController extends BasePreferenceController {
|
||||
mOnAnomalyRejectListener = listener;
|
||||
}
|
||||
|
||||
private <T> T getInfo(PowerAnomalyEvent powerAnomalyEvent,
|
||||
Function<WarningBannerInfo, T> warningBannerInfoSupplier,
|
||||
Function<WarningItemInfo, T> warningItemInfoSupplier) {
|
||||
if (warningBannerInfoSupplier != null && powerAnomalyEvent.hasWarningBannerInfo()) {
|
||||
return warningBannerInfoSupplier.apply(powerAnomalyEvent.getWarningBannerInfo());
|
||||
} else if (warningItemInfoSupplier != null && powerAnomalyEvent.hasWarningItemInfo()) {
|
||||
return warningItemInfoSupplier.apply(powerAnomalyEvent.getWarningItemInfo());
|
||||
void acceptTipsCard() {
|
||||
if (mAnomalyEventWrapper == null || !mIsAcceptable) {
|
||||
return;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getStringFromResource(int resourceId, int resourceIndex) {
|
||||
if (resourceId < 0) {
|
||||
return null;
|
||||
// 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);
|
||||
}
|
||||
final String[] stringArray = mContext.getResources().getStringArray(resourceId);
|
||||
return (resourceIndex >= 0 && resourceIndex < stringArray.length)
|
||||
? stringArray[resourceIndex] : null;
|
||||
mCardPreference.setVisible(false);
|
||||
mMetricsFeatureProvider.action(
|
||||
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT,
|
||||
mAnomalyEventWrapper.getEventId());
|
||||
}
|
||||
|
||||
private int getResourceId(int resourceId, int resourceIndex, String defType) {
|
||||
final String key = getStringFromResource(resourceId, resourceIndex);
|
||||
return TextUtils.isEmpty(key) ? 0
|
||||
: mContext.getResources().getIdentifier(key, defType, mContext.getPackageName());
|
||||
}
|
||||
|
||||
private String getString(PowerAnomalyEvent powerAnomalyEvent,
|
||||
Function<WarningBannerInfo, String> warningBannerInfoSupplier,
|
||||
Function<WarningItemInfo, String> warningItemInfoSupplier,
|
||||
int resourceId, int resourceIndex) {
|
||||
String string =
|
||||
getInfo(powerAnomalyEvent, warningBannerInfoSupplier, warningItemInfoSupplier);
|
||||
return (!TextUtils.isEmpty(string) || resourceId < 0) ? string
|
||||
: getStringFromResource(resourceId, resourceIndex);
|
||||
}
|
||||
|
||||
/** Generate a key string of current anomaly to record as dismissed in sharedPreferences. */
|
||||
public static String getDismissRecordKey(PowerAnomalyEvent event) {
|
||||
if (!event.hasKey()) {
|
||||
return null;
|
||||
}
|
||||
switch (event.getKey()){
|
||||
case KEY_APP:
|
||||
return event.hasWarningItemInfo()
|
||||
&& event.getWarningItemInfo().hasDismissRecordKey()
|
||||
? event.getWarningItemInfo().getDismissRecordKey() : null;
|
||||
default:
|
||||
return event.getKey().name();
|
||||
}
|
||||
}
|
||||
|
||||
void handleBatteryTipsCardUpdated(PowerAnomalyEvent powerAnomalyEvent) {
|
||||
if (powerAnomalyEvent == null) {
|
||||
void handleBatteryTipsCardUpdated(
|
||||
AnomalyEventWrapper anomalyEventWrapper, boolean isAcceptable) {
|
||||
mAnomalyEventWrapper = anomalyEventWrapper;
|
||||
mIsAcceptable = isAcceptable;
|
||||
if (mAnomalyEventWrapper == null) {
|
||||
mCardPreference.setVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get card icon and color styles
|
||||
final int cardStyleId = powerAnomalyEvent.getType().getNumber();
|
||||
final int iconResId = getResourceId(
|
||||
R.array.battery_tips_card_icons, cardStyleId, "drawable");
|
||||
final int colorResId = getResourceId(
|
||||
R.array.battery_tips_card_colors, cardStyleId, "color");
|
||||
|
||||
// Get card preference strings and navigate fragment info
|
||||
final String eventId = powerAnomalyEvent.hasEventId()
|
||||
? powerAnomalyEvent.getEventId() : null;
|
||||
final PowerAnomalyKey powerAnomalyKey = powerAnomalyEvent.hasKey()
|
||||
? powerAnomalyEvent.getKey() : null;
|
||||
final int resourceIndex = powerAnomalyKey != null ? powerAnomalyKey.getNumber() : -1;
|
||||
final String eventId = mAnomalyEventWrapper.getEventId();
|
||||
|
||||
final String titleString = getString(powerAnomalyEvent, WarningBannerInfo::getTitleString,
|
||||
WarningItemInfo::getTitleString, R.array.power_anomaly_titles, resourceIndex);
|
||||
if (titleString.isEmpty()) {
|
||||
// Update card & buttons preference
|
||||
if (!mAnomalyEventWrapper.updateTipsCardPreference(mCardPreference)) {
|
||||
mCardPreference.setVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
final String mainBtnString = getString(powerAnomalyEvent,
|
||||
WarningBannerInfo::getMainButtonString, WarningItemInfo::getMainButtonString,
|
||||
R.array.power_anomaly_main_btn_strings, resourceIndex);
|
||||
final String dismissBtnString = getString(powerAnomalyEvent,
|
||||
WarningBannerInfo::getCancelButtonString, WarningItemInfo::getCancelButtonString,
|
||||
R.array.power_anomaly_dismiss_btn_strings, resourceIndex);
|
||||
|
||||
final String destinationClassName = getInfo(powerAnomalyEvent,
|
||||
WarningBannerInfo::getMainButtonDestination, null);
|
||||
final Integer sourceMetricsCategory = getInfo(powerAnomalyEvent,
|
||||
WarningBannerInfo::getMainButtonSourceMetricsCategory, null);
|
||||
final String preferenceHighlightKey = getInfo(powerAnomalyEvent,
|
||||
WarningBannerInfo::getMainButtonSourceHighlightKey, null);
|
||||
|
||||
// Update card preference and main button fragment launcher
|
||||
mCardPreference.setTitle(titleString);
|
||||
mCardPreference.setIconResourceId(iconResId);
|
||||
mCardPreference.setMainButtonStrokeColorResourceId(colorResId);
|
||||
mCardPreference.setMainButtonLabel(mainBtnString);
|
||||
mCardPreference.setDismissButtonLabel(dismissBtnString);
|
||||
|
||||
// Set battery tips card listener
|
||||
mCardPreference.setOnConfirmListener(() -> {
|
||||
mCardPreference.setVisible(false);
|
||||
if (mOnAnomalyConfirmListener != null) {
|
||||
mOnAnomalyConfirmListener.onAnomalyConfirm();
|
||||
} else if (!TextUtils.isEmpty(destinationClassName)) {
|
||||
// Navigate to sub setting page
|
||||
Bundle arguments = Bundle.EMPTY;
|
||||
if (!TextUtils.isEmpty(preferenceHighlightKey)) {
|
||||
arguments = new Bundle(1);
|
||||
arguments.putString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY,
|
||||
preferenceHighlightKey);
|
||||
}
|
||||
new SubSettingLauncher(mContext)
|
||||
.setDestination(destinationClassName)
|
||||
.setSourceMetricsCategory(sourceMetricsCategory)
|
||||
.setArguments(arguments)
|
||||
.launch();
|
||||
} else if (mAnomalyEventWrapper.launchSubSetting()) {
|
||||
mMetricsFeatureProvider.action(
|
||||
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT, eventId);
|
||||
}
|
||||
mMetricsFeatureProvider.action(
|
||||
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT, eventId);
|
||||
});
|
||||
mCardPreference.setOnRejectListener(() -> {
|
||||
mCardPreference.setVisible(false);
|
||||
if (mOnAnomalyRejectListener != null) {
|
||||
mOnAnomalyRejectListener.onAnomalyReject();
|
||||
}
|
||||
// For anomaly events with same record key, dismissed until next time full charged.
|
||||
final String dismissRecordKey = getDismissRecordKey(powerAnomalyEvent);
|
||||
final String dismissRecordKey = mAnomalyEventWrapper.getDismissRecordKey();
|
||||
if (!TextUtils.isEmpty(dismissRecordKey)) {
|
||||
DatabaseUtils.setDismissedPowerAnomalyKeys(mContext, dismissRecordKey);
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
/** Controller for battery usage breakdown preference group. */
|
||||
@@ -93,6 +94,14 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
|
||||
BatteryDiffData mBatteryDiffData;
|
||||
@VisibleForTesting
|
||||
String mPercentLessThanThresholdText;
|
||||
@VisibleForTesting
|
||||
boolean mIsHighlightSlot;
|
||||
@VisibleForTesting
|
||||
String mAnomalyEventId;
|
||||
@VisibleForTesting
|
||||
String mAnomalyEntryKey;
|
||||
@VisibleForTesting
|
||||
String mAnomalyHintString;
|
||||
|
||||
public BatteryUsageBreakdownController(
|
||||
Context context, Lifecycle lifecycle, SettingsActivity activity,
|
||||
@@ -137,6 +146,12 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
|
||||
return false;
|
||||
}
|
||||
|
||||
private String getActionKey(String packageName) {
|
||||
final String actionKey = TextUtils.isEmpty(packageName)
|
||||
? PACKAGE_NAME_NONE : packageName;
|
||||
return mAnomalyEventId == null ? actionKey : actionKey + "|" + mAnomalyEventId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handlePreferenceTreeClick(Preference preference) {
|
||||
if (!(preference instanceof PowerGaugePreference)) {
|
||||
@@ -151,7 +166,7 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
|
||||
? SettingsEnums.ACTION_BATTERY_USAGE_SYSTEM_ITEM
|
||||
: SettingsEnums.ACTION_BATTERY_USAGE_APP_ITEM,
|
||||
/* pageId */ SettingsEnums.OPEN_BATTERY_USAGE,
|
||||
TextUtils.isEmpty(packageName) ? PACKAGE_NAME_NONE : packageName,
|
||||
getActionKey(packageName),
|
||||
(int) Math.round(diffEntry.getPercentage()));
|
||||
Log.d(TAG, String.format("handleClick() label=%s key=%s package=%s",
|
||||
diffEntry.getAppLabel(), diffEntry.getKey(), packageName));
|
||||
@@ -211,9 +226,23 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
|
||||
* used when showing the footer.
|
||||
*/
|
||||
void handleBatteryUsageUpdated(
|
||||
BatteryDiffData slotUsageData, String slotTimestamp, boolean isAllUsageDataEmpty) {
|
||||
BatteryDiffData slotUsageData, String slotTimestamp,
|
||||
boolean isAllUsageDataEmpty, boolean isHighlightSlot,
|
||||
Optional<AnomalyEventWrapper> optionalAnomalyEventWrapper) {
|
||||
mBatteryDiffData = slotUsageData;
|
||||
mSlotTimestamp = slotTimestamp;
|
||||
mIsHighlightSlot = isHighlightSlot;
|
||||
|
||||
if (optionalAnomalyEventWrapper != null) {
|
||||
final AnomalyEventWrapper anomalyEventWrapper =
|
||||
optionalAnomalyEventWrapper.orElse(null);
|
||||
mAnomalyEventId = anomalyEventWrapper != null
|
||||
? anomalyEventWrapper.getEventId() : null;
|
||||
mAnomalyEntryKey = anomalyEventWrapper != null
|
||||
? anomalyEventWrapper.getAnomalyEntryKey() : null;
|
||||
mAnomalyHintString = anomalyEventWrapper != null
|
||||
? anomalyEventWrapper.getAnomalyHintString() : null;
|
||||
}
|
||||
|
||||
showCategoryTitle(slotTimestamp);
|
||||
showSpinnerAndAppList();
|
||||
@@ -278,15 +307,15 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
|
||||
continue;
|
||||
}
|
||||
final String prefKey = entry.getKey();
|
||||
PowerGaugePreference pref = mAppListPreferenceGroup.findPreference(prefKey);
|
||||
AnomalyAppItemPreference pref = mAppListPreferenceGroup.findPreference(prefKey);
|
||||
if (pref != null) {
|
||||
isAdded = true;
|
||||
} else {
|
||||
pref = (PowerGaugePreference) mPreferenceCache.get(prefKey);
|
||||
pref = (AnomalyAppItemPreference) mPreferenceCache.get(prefKey);
|
||||
}
|
||||
// Creates new innstance if cached preference is not found.
|
||||
// Creates new instance if cached preference is not found.
|
||||
if (pref == null) {
|
||||
pref = new PowerGaugePreference(mPrefContext);
|
||||
pref = new AnomalyAppItemPreference(mPrefContext);
|
||||
pref.setKey(prefKey);
|
||||
mPreferenceCache.put(prefKey, pref);
|
||||
}
|
||||
@@ -294,6 +323,10 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
|
||||
pref.setTitle(appLabel);
|
||||
pref.setOrder(prefIndex);
|
||||
pref.setSingleLineTitle(true);
|
||||
// Updates App item preference style
|
||||
pref.setAnomalyHint(mIsHighlightSlot && mAnomalyEntryKey != null
|
||||
&& mAnomalyEntryKey.equals(entry.getKey())
|
||||
? mAnomalyHintString : null);
|
||||
// Sets the BatteryDiffEntry to preference for launching detailed page.
|
||||
pref.setBatteryDiffEntry(entry);
|
||||
pref.setSelectable(entry.validForRestriction());
|
||||
|
||||
@@ -28,6 +28,7 @@ import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.settings.fuelgauge.BatteryUsageHistoricalLogEntry.Action;
|
||||
import com.android.settings.fuelgauge.batteryusage.bugreport.BatteryUsageLogUtils;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -138,6 +139,8 @@ public final class BatteryUsageDataLoader {
|
||||
// No app usage data or battery diff data at this time.
|
||||
loadAppUsageData(context);
|
||||
preprocessBatteryUsageSlots(context);
|
||||
FeatureFactory.getFactory(context).getPowerUsageFeatureProvider(context)
|
||||
.detectSettingsAnomaly(context, /* displayDrain= */ 0);
|
||||
}
|
||||
Log.d(TAG, String.format(
|
||||
"loadUsageDataSafely() in %d/ms", System.currentTimeMillis() - start));
|
||||
|
||||
@@ -52,6 +52,7 @@ import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/** Advanced power usage. */
|
||||
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
|
||||
@@ -92,9 +93,9 @@ public class PowerUsageAdvanced extends PowerUsageBase {
|
||||
@VisibleForTesting
|
||||
BatteryUsageBreakdownController mBatteryUsageBreakdownController;
|
||||
@VisibleForTesting
|
||||
PowerAnomalyEvent mPowerAnomalyEvent;
|
||||
@VisibleForTesting
|
||||
Optional<BatteryLevelData> mBatteryLevelData;
|
||||
@VisibleForTesting
|
||||
Optional<AnomalyEventWrapper> mHighlightEventWrapper;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
@@ -188,7 +189,7 @@ public class PowerUsageAdvanced extends PowerUsageBase {
|
||||
mIsChartDataLoaded = true;
|
||||
mBatteryLevelData = null;
|
||||
mBatteryUsageMap = null;
|
||||
mPowerAnomalyEvent = null;
|
||||
mHighlightEventWrapper = null;
|
||||
restartLoader(LoaderIndex.BATTERY_LEVEL_DATA_LOADER, bundle,
|
||||
mBatteryLevelDataLoaderCallbacks);
|
||||
}
|
||||
@@ -239,8 +240,13 @@ public class PowerUsageAdvanced extends PowerUsageBase {
|
||||
mScreenOnTimeController.handleSceenOnTimeUpdated(
|
||||
slotUsageData.getScreenOnTime(), slotInformation);
|
||||
}
|
||||
// Hide card tips if the related highlight slot was clicked.
|
||||
if (isAppsAnomalyEventFocused()) {
|
||||
mBatteryTipsController.acceptTipsCard();
|
||||
}
|
||||
mBatteryUsageBreakdownController.handleBatteryUsageUpdated(
|
||||
slotUsageData, slotInformation, isBatteryUsageMapNullOrEmpty());
|
||||
slotUsageData, slotInformation, isBatteryUsageMapNullOrEmpty(),
|
||||
isAppsAnomalyEventFocused(), mHighlightEventWrapper);
|
||||
Log.d(TAG, String.format("Battery usage list shows in %d millis",
|
||||
System.currentTimeMillis() - mResumeTimestamp));
|
||||
}
|
||||
@@ -262,49 +268,95 @@ public class PowerUsageAdvanced extends PowerUsageBase {
|
||||
return;
|
||||
}
|
||||
Log.d(TAG, "anomalyEventList = " + anomalyEventList);
|
||||
final PowerAnomalyEvent displayEvent =
|
||||
getHighestScoreAnomalyEvent(getContext(), anomalyEventList);
|
||||
onDisplayAnomalyEventUpdated(displayEvent);
|
||||
|
||||
final Set<String> dismissedPowerAnomalyKeys =
|
||||
DatabaseUtils.getDismissedPowerAnomalyKeys(getContext());
|
||||
Log.d(TAG, "dismissedPowerAnomalyKeys = " + dismissedPowerAnomalyKeys);
|
||||
|
||||
// Choose an app anomaly event with highest score to show highlight slot
|
||||
final PowerAnomalyEvent highlightEvent =
|
||||
getAnomalyEvent(anomalyEventList, PowerAnomalyEvent::hasWarningItemInfo);
|
||||
// Choose an event never dismissed to show as card.
|
||||
// If the slot is already highlighted, the tips card should be the corresponding app
|
||||
// or settings anomaly event.
|
||||
final PowerAnomalyEvent tipsCardEvent =
|
||||
getAnomalyEvent(anomalyEventList,
|
||||
event -> !dismissedPowerAnomalyKeys.contains(event.getDismissRecordKey())
|
||||
&& (event.equals(highlightEvent) || !event.hasWarningItemInfo()));
|
||||
onDisplayAnomalyEventUpdated(tipsCardEvent, highlightEvent);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void onDisplayAnomalyEventUpdated(PowerAnomalyEvent event) {
|
||||
mPowerAnomalyEvent = event;
|
||||
void onDisplayAnomalyEventUpdated(
|
||||
PowerAnomalyEvent tipsCardEvent, PowerAnomalyEvent highlightEvent) {
|
||||
if (mBatteryTipsController == null
|
||||
|| mBatteryChartPreferenceController == null
|
||||
|| mBatteryUsageBreakdownController == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final boolean isSameAnomalyEvent = (tipsCardEvent == highlightEvent);
|
||||
// Update battery tips card preference & behaviour
|
||||
mBatteryTipsController.setOnAnomalyConfirmListener(null);
|
||||
mBatteryTipsController.setOnAnomalyRejectListener(null);
|
||||
mBatteryTipsController.handleBatteryTipsCardUpdated(mPowerAnomalyEvent);
|
||||
final AnomalyEventWrapper tipsCardEventWrapper = (tipsCardEvent == null) ? null :
|
||||
new AnomalyEventWrapper(getContext(), tipsCardEvent);
|
||||
if (tipsCardEventWrapper != null) {
|
||||
tipsCardEventWrapper.setRelatedBatteryDiffEntry(
|
||||
findRelatedBatteryDiffEntry(tipsCardEventWrapper));
|
||||
}
|
||||
mBatteryTipsController.handleBatteryTipsCardUpdated(
|
||||
tipsCardEventWrapper, isSameAnomalyEvent);
|
||||
|
||||
// Update highlight slot effect in battery chart view
|
||||
Pair<Integer, Integer> highlightSlotIndexPair = Pair.create(
|
||||
BatteryChartViewModel.SELECTED_INDEX_INVALID,
|
||||
BatteryChartViewModel.SELECTED_INDEX_INVALID);
|
||||
if (mPowerAnomalyEvent != null && mPowerAnomalyEvent.hasWarningItemInfo()) {
|
||||
final WarningItemInfo warningItemInfo = mPowerAnomalyEvent.getWarningItemInfo();
|
||||
final Long startTimestamp = warningItemInfo.hasStartTimestamp()
|
||||
? warningItemInfo.getStartTimestamp() : null;
|
||||
final Long endTimestamp = warningItemInfo.hasEndTimestamp()
|
||||
? warningItemInfo.getEndTimestamp() : null;
|
||||
if (startTimestamp != null && endTimestamp != null) {
|
||||
highlightSlotIndexPair = mBatteryLevelData.map(levelData ->
|
||||
levelData.getIndexByTimestamps(startTimestamp, endTimestamp))
|
||||
.orElse(highlightSlotIndexPair);
|
||||
mBatteryTipsController.setOnAnomalyConfirmListener(
|
||||
mBatteryChartPreferenceController::selectHighlightSlotIndex);
|
||||
mBatteryTipsController.setOnAnomalyRejectListener(
|
||||
() -> onDisplayAnomalyEventUpdated(null));
|
||||
mHighlightEventWrapper = Optional.ofNullable(isSameAnomalyEvent ? tipsCardEventWrapper :
|
||||
((highlightEvent != null)
|
||||
? new AnomalyEventWrapper(getContext(), highlightEvent) : null));
|
||||
if (mBatteryLevelData != null && mBatteryLevelData.isPresent()
|
||||
&& mHighlightEventWrapper.isPresent()
|
||||
&& mHighlightEventWrapper.get().hasHighlightSlotPair(mBatteryLevelData.get())) {
|
||||
highlightSlotIndexPair = mHighlightEventWrapper.get()
|
||||
.getHighlightSlotPair(mBatteryLevelData.get());
|
||||
if (isSameAnomalyEvent) {
|
||||
// For main button, focus on highlight slot when clicked
|
||||
mBatteryTipsController.setOnAnomalyConfirmListener(() -> {
|
||||
mBatteryChartPreferenceController.selectHighlightSlotIndex();
|
||||
mBatteryTipsController.acceptTipsCard();
|
||||
});
|
||||
}
|
||||
}
|
||||
mBatteryChartPreferenceController.onHighlightSlotIndexUpdate(
|
||||
highlightSlotIndexPair.first, highlightSlotIndexPair.second);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
BatteryDiffEntry findRelatedBatteryDiffEntry(AnomalyEventWrapper eventWrapper) {
|
||||
if (eventWrapper == null
|
||||
|| mBatteryLevelData == null || mBatteryLevelData.isEmpty()
|
||||
|| !eventWrapper.hasHighlightSlotPair(mBatteryLevelData.get())
|
||||
|| !eventWrapper.hasAnomalyEntryKey()
|
||||
|| mBatteryUsageMap == null) {
|
||||
return null;
|
||||
}
|
||||
final Pair<Integer, Integer> highlightSlotIndexPair =
|
||||
eventWrapper.getHighlightSlotPair(mBatteryLevelData.get());
|
||||
final BatteryDiffData relatedDiffData = mBatteryUsageMap
|
||||
.get(highlightSlotIndexPair.first).get(highlightSlotIndexPair.second);
|
||||
final String anomalyEntryKey = eventWrapper.getAnomalyEntryKey();
|
||||
if (relatedDiffData == null || anomalyEntryKey == null) {
|
||||
return null;
|
||||
}
|
||||
for (BatteryDiffEntry entry : relatedDiffData.getAppDiffEntryList()) {
|
||||
if (anomalyEntryKey.equals(entry.getKey())) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void setBatteryChartPreferenceController() {
|
||||
if (mHistPref != null && mBatteryChartPreferenceController != null) {
|
||||
mHistPref.setChartPreferenceController(mBatteryChartPreferenceController);
|
||||
@@ -319,6 +371,11 @@ public class PowerUsageAdvanced extends PowerUsageBase {
|
||||
&& allBatteryDiffData.getSystemDiffEntryList().isEmpty());
|
||||
}
|
||||
|
||||
private boolean isAppsAnomalyEventFocused() {
|
||||
return mBatteryChartPreferenceController != null
|
||||
&& mBatteryChartPreferenceController.isHighlightSlotFocused();
|
||||
}
|
||||
|
||||
private void logScreenUsageTime() {
|
||||
final BatteryDiffData allBatteryDiffData = getAllBatteryDiffData(mBatteryUsageMap);
|
||||
if (allBatteryDiffData == null) {
|
||||
@@ -339,25 +396,22 @@ public class PowerUsageAdvanced extends PowerUsageBase {
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static PowerAnomalyEvent getHighestScoreAnomalyEvent(
|
||||
Context context, PowerAnomalyEventList anomalyEventList) {
|
||||
static PowerAnomalyEvent getAnomalyEvent(
|
||||
PowerAnomalyEventList anomalyEventList, Predicate<PowerAnomalyEvent> predicate) {
|
||||
if (anomalyEventList == null || anomalyEventList.getPowerAnomalyEventsCount() == 0) {
|
||||
return null;
|
||||
}
|
||||
final Set<String> dismissedPowerAnomalyKeys =
|
||||
DatabaseUtils.getDismissedPowerAnomalyKeys(context);
|
||||
Log.d(TAG, "dismissedPowerAnomalyKeys = " + dismissedPowerAnomalyKeys);
|
||||
|
||||
final PowerAnomalyEvent highestScoreEvent = anomalyEventList.getPowerAnomalyEventsList()
|
||||
final PowerAnomalyEvent filterAnomalyEvent = anomalyEventList.getPowerAnomalyEventsList()
|
||||
.stream()
|
||||
.filter(event -> !dismissedPowerAnomalyKeys.contains(
|
||||
BatteryTipsController.getDismissRecordKey(event)))
|
||||
.filter(predicate)
|
||||
.max(Comparator.comparing(PowerAnomalyEvent::getScore))
|
||||
.orElse(null);
|
||||
Log.d(TAG, "highestScoreAnomalyEvent = " + highestScoreEvent);
|
||||
return highestScoreEvent;
|
||||
Log.d(TAG, "filterAnomalyEvent = " + filterAnomalyEvent);
|
||||
return filterAnomalyEvent;
|
||||
}
|
||||
|
||||
|
||||
private static BatteryDiffData getAllBatteryDiffData(
|
||||
Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap) {
|
||||
return batteryUsageMap == null ? null : batteryUsageMap
|
||||
|
||||
@@ -18,6 +18,7 @@ message PowerAnomalyEvent {
|
||||
WarningBannerInfo warning_banner_info = 6;
|
||||
WarningItemInfo warning_item_info = 7;
|
||||
}
|
||||
optional string dismiss_record_key = 8;
|
||||
}
|
||||
|
||||
// NOTE: Please DO NOT delete enum items or change enum values. Use [deprecated = true] instead.
|
||||
@@ -32,11 +33,16 @@ enum PowerAnomalyType{
|
||||
// NOTE: Please DO NOT delete enum items or change enum values. Use [deprecated = true] instead.
|
||||
// The enum value will be used to decide pre-defined title and button labels.
|
||||
//
|
||||
// Next id: 3
|
||||
// Next id: 8
|
||||
enum PowerAnomalyKey{
|
||||
KEY_BRIGHTNESS = 0;
|
||||
KEY_SCREEN_TIMEOUT = 1;
|
||||
KEY_APP = 2;
|
||||
KEY_APP_TOTAL_ALWAYS_HIGH = 2;
|
||||
KEY_APP_TOTAL_HIGHER_THAN_USUAL = 3;
|
||||
KEY_APP_BACKGROUND_ALWAYS_HIGH = 4;
|
||||
KEY_APP_BACKGROUND_HIGHER_THAN_USUAL = 5;
|
||||
KEY_APP_FOREGROUND_ALWAYS_HIGH = 6;
|
||||
KEY_APP_FOREGROUND_HIGHER_THAN_USUAL = 7;
|
||||
}
|
||||
|
||||
message WarningBannerInfo {
|
||||
@@ -60,6 +66,5 @@ message WarningItemInfo {
|
||||
optional string description_string = 5;
|
||||
optional string main_button_string = 6;
|
||||
optional string cancel_button_string = 7;
|
||||
optional string dismiss_record_key = 8;
|
||||
optional string item_key = 9;
|
||||
optional string item_key = 8;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ package com.android.settings.network;
|
||||
|
||||
import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX;
|
||||
import static android.telephony.UiccSlotInfo.CARD_STATE_INFO_PRESENT;
|
||||
|
||||
import static com.android.internal.util.CollectionUtils.emptyIfNull;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
@@ -56,6 +55,8 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@@ -66,6 +67,9 @@ public class SubscriptionUtil {
|
||||
static final String SUB_ID = "sub_id";
|
||||
@VisibleForTesting
|
||||
static final String KEY_UNIQUE_SUBSCRIPTION_DISPLAYNAME = "unique_subscription_displayName";
|
||||
private static final String REGEX_DISPLAY_NAME_PREFIXES = "^";
|
||||
private static final String REGEX_DISPLAY_NAME_SUFFIXES = "\\s[0-9]+";
|
||||
|
||||
private static List<SubscriptionInfo> sAvailableResultsForTesting;
|
||||
private static List<SubscriptionInfo> sActiveResultsForTesting;
|
||||
|
||||
@@ -281,8 +285,8 @@ public class SubscriptionUtil {
|
||||
String displayName = i.getDisplayName().toString();
|
||||
info.originalName =
|
||||
TextUtils.equals(displayName, PROFILE_GENERIC_DISPLAY_NAME)
|
||||
? context.getResources().getString(R.string.sim_card)
|
||||
: displayName.trim();
|
||||
? context.getResources().getString(R.string.sim_card)
|
||||
: displayName.trim();
|
||||
return info;
|
||||
});
|
||||
|
||||
@@ -298,12 +302,17 @@ public class SubscriptionUtil {
|
||||
// If a display name is duplicate, append the final 4 digits of the phone number.
|
||||
// Creates a mapping of Subscription id to original display name + phone number display name
|
||||
final Supplier<Stream<DisplayInfo>> uniqueInfos = () -> originalInfos.get().map(info -> {
|
||||
int infoSubId = info.subscriptionInfo.getSubscriptionId();
|
||||
String cachedDisplayName = getDisplayNameFromSharedPreference(
|
||||
context, info.subscriptionInfo.getSubscriptionId());
|
||||
if (!TextUtils.isEmpty(cachedDisplayName)) {
|
||||
Log.d(TAG, "use cached display name : " + cachedDisplayName);
|
||||
context, infoSubId);
|
||||
if (isValidCachedDisplayName(cachedDisplayName, info.originalName.toString())) {
|
||||
Log.d(TAG, "use cached display name : for subId : " + infoSubId
|
||||
+ "cached display name : " + cachedDisplayName);
|
||||
info.uniqueName = cachedDisplayName;
|
||||
return info;
|
||||
} else {
|
||||
Log.d(TAG, "remove cached display name : " + infoSubId);
|
||||
removeItemFromDisplayNameSharedPreference(context, infoSubId);
|
||||
}
|
||||
|
||||
if (duplicateOriginalNames.contains(info.originalName)) {
|
||||
@@ -320,9 +329,8 @@ public class SubscriptionUtil {
|
||||
} else {
|
||||
info.uniqueName = info.originalName + " " + lastFourDigits;
|
||||
Log.d(TAG, "Cache display name [" + info.uniqueName + "] for sub id "
|
||||
+ info.subscriptionInfo.getSubscriptionId());
|
||||
saveDisplayNameToSharedPreference(
|
||||
context, info.subscriptionInfo.getSubscriptionId(), info.uniqueName);
|
||||
+ infoSubId);
|
||||
saveDisplayNameToSharedPreference(context, infoSubId, info.uniqueName);
|
||||
}
|
||||
} else {
|
||||
info.uniqueName = info.originalName;
|
||||
@@ -404,10 +412,27 @@ public class SubscriptionUtil {
|
||||
.apply();
|
||||
}
|
||||
|
||||
private static void removeItemFromDisplayNameSharedPreference(Context context, int subId) {
|
||||
getDisplayNameSharedPreferenceEditor(context)
|
||||
.remove(SUB_ID + subId)
|
||||
.commit();
|
||||
}
|
||||
|
||||
private static String getDisplayNameFromSharedPreference(Context context, int subid) {
|
||||
return getDisplayNameSharedPreferences(context).getString(SUB_ID + subid, "");
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static boolean isValidCachedDisplayName(String cachedDisplayName, String originalName) {
|
||||
if (TextUtils.isEmpty(cachedDisplayName) || TextUtils.isEmpty(originalName)) {
|
||||
return false;
|
||||
}
|
||||
String regex = REGEX_DISPLAY_NAME_PREFIXES + originalName + REGEX_DISPLAY_NAME_SUFFIXES;
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
Matcher matcher = pattern.matcher(cachedDisplayName);
|
||||
return matcher.matches();
|
||||
}
|
||||
|
||||
public static String getDisplayName(SubscriptionInfo info) {
|
||||
final CharSequence name = info.getDisplayName();
|
||||
if (name != null) {
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package com.android.settings.development;
|
||||
|
||||
import static com.android.settings.development.BluetoothLeAudioDeviceDetailsPreferenceController
|
||||
.LE_AUDIO_TOGGLE_VISIBLE_PROPERTY;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.spy;
|
||||
@@ -25,12 +28,11 @@ import static org.mockito.Mockito.when;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothStatusCodes;
|
||||
import android.content.Context;
|
||||
import android.provider.DeviceConfig;
|
||||
import android.os.SystemProperties;
|
||||
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.preference.SwitchPreference;
|
||||
|
||||
import com.android.settings.core.SettingsUIDeviceConfig;
|
||||
import com.android.settings.testutils.shadow.ShadowDeviceConfig;
|
||||
|
||||
import org.junit.After;
|
||||
@@ -77,9 +79,8 @@ public class BluetoothLeAudioDeviceDetailsPreferenceControllerTest {
|
||||
public void onPreferenceChanged_settingEnabled_shouldTurnOnLeAudioDeviceDetailSetting() {
|
||||
mController.sLeAudioSupportedStateCache = BluetoothStatusCodes.FEATURE_SUPPORTED;
|
||||
mController.onPreferenceChange(mPreference, true /* new value */);
|
||||
final boolean isEnabled = DeviceConfig.getBoolean(
|
||||
DeviceConfig.NAMESPACE_SETTINGS_UI,
|
||||
SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, false);
|
||||
final boolean isEnabled = SystemProperties.getBoolean(
|
||||
LE_AUDIO_TOGGLE_VISIBLE_PROPERTY, false);
|
||||
|
||||
assertThat(isEnabled).isTrue();
|
||||
}
|
||||
@@ -88,9 +89,8 @@ public class BluetoothLeAudioDeviceDetailsPreferenceControllerTest {
|
||||
public void onPreferenceChanged_settingDisabled_shouldTurnOffLeAudioDeviceDetailSetting() {
|
||||
mController.sLeAudioSupportedStateCache = BluetoothStatusCodes.FEATURE_SUPPORTED;
|
||||
mController.onPreferenceChange(mPreference, false /* new value */);
|
||||
final boolean isEnabled = DeviceConfig.getBoolean(
|
||||
DeviceConfig.NAMESPACE_SETTINGS_UI,
|
||||
SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, false);
|
||||
final boolean isEnabled = SystemProperties.getBoolean(
|
||||
LE_AUDIO_TOGGLE_VISIBLE_PROPERTY, true);
|
||||
|
||||
assertThat(isEnabled).isFalse();
|
||||
}
|
||||
@@ -98,18 +98,15 @@ public class BluetoothLeAudioDeviceDetailsPreferenceControllerTest {
|
||||
@Test
|
||||
public void updateState_settingEnabled_preferenceShouldBeChecked() {
|
||||
mController.sLeAudioSupportedStateCache = BluetoothStatusCodes.FEATURE_SUPPORTED;
|
||||
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_UI,
|
||||
SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, "true", false);
|
||||
SystemProperties.set(LE_AUDIO_TOGGLE_VISIBLE_PROPERTY, "true");
|
||||
mController.updateState(mPreference);
|
||||
|
||||
verify(mPreference).setChecked(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateState_settingDisabled_preferenceShouldNotBeChecked() {
|
||||
mController.sLeAudioSupportedStateCache = BluetoothStatusCodes.FEATURE_SUPPORTED;
|
||||
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_UI,
|
||||
SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, "false", false);
|
||||
SystemProperties.set(LE_AUDIO_TOGGLE_VISIBLE_PROPERTY, "false");
|
||||
mController.updateState(mPreference);
|
||||
|
||||
verify(mPreference).setChecked(false);
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.Mockito.spy;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.settings.testutils.BatteryTestUtils;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import java.util.TimeZone;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class AnomalyEventWrapperTest {
|
||||
private AnomalyEventWrapper mAnomalyEventWrapper;
|
||||
private Context mContext;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDismissRecordKey_returnExpectedResult() {
|
||||
mAnomalyEventWrapper = new AnomalyEventWrapper(mContext,
|
||||
BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent());
|
||||
assertThat(mAnomalyEventWrapper.getDismissRecordKey())
|
||||
.isEqualTo("KEY_BRIGHTNESS");
|
||||
|
||||
mAnomalyEventWrapper = new AnomalyEventWrapper(mContext,
|
||||
BatteryTestUtils.createScreenTimeoutAnomalyEvent());
|
||||
assertThat(mAnomalyEventWrapper.getDismissRecordKey())
|
||||
.isEqualTo("KEY_SCREEN_TIMEOUT");
|
||||
|
||||
mAnomalyEventWrapper = new AnomalyEventWrapper(mContext,
|
||||
BatteryTestUtils.createAppAnomalyEvent());
|
||||
assertThat(mAnomalyEventWrapper.getDismissRecordKey())
|
||||
.isEqualTo("KEY_APP_1");
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ 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;
|
||||
@@ -58,13 +59,14 @@ public final class BatteryTipsCardPreferenceTest {
|
||||
private BatteryTipsCardPreference mBatteryTipsCardPreference;
|
||||
private PowerUsageAdvanced mPowerUsageAdvanced;
|
||||
private BatteryTipsController mBatteryTipsController;
|
||||
private BatteryChartPreferenceController mBatteryChartPreferenceController;
|
||||
|
||||
@Mock
|
||||
private View mFakeView;
|
||||
@Mock
|
||||
private BatteryChartPreferenceController mBatteryChartPreferenceController;
|
||||
@Mock
|
||||
private BatteryUsageBreakdownController mBatteryUsageBreakdownController;
|
||||
@Mock
|
||||
private BatteryDiffEntry mFakeEntry;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@@ -73,8 +75,13 @@ public final class BatteryTipsCardPreferenceTest {
|
||||
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 = new PowerUsageAdvanced();
|
||||
|
||||
mPowerUsageAdvanced = spy(new PowerUsageAdvanced());
|
||||
doReturn(mContext).when(mPowerUsageAdvanced).getContext();
|
||||
mPowerUsageAdvanced.mBatteryTipsController = mBatteryTipsController;
|
||||
mPowerUsageAdvanced.mBatteryChartPreferenceController = mBatteryChartPreferenceController;
|
||||
mPowerUsageAdvanced.mBatteryUsageBreakdownController = mBatteryUsageBreakdownController;
|
||||
@@ -82,6 +89,7 @@ public final class BatteryTipsCardPreferenceTest {
|
||||
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
|
||||
@@ -99,7 +107,8 @@ public final class BatteryTipsCardPreferenceTest {
|
||||
when(mFakeView.getId()).thenReturn(R.id.main_button);
|
||||
doNothing().when(mContext).startActivity(captor.capture());
|
||||
|
||||
mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(adaptiveBrightnessAnomaly);
|
||||
mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(
|
||||
adaptiveBrightnessAnomaly, adaptiveBrightnessAnomaly);
|
||||
mBatteryTipsCardPreference.onClick(mFakeView);
|
||||
|
||||
assertThat(mBatteryTipsCardPreference.isVisible()).isFalse();
|
||||
@@ -109,25 +118,30 @@ public final class BatteryTipsCardPreferenceTest {
|
||||
.isEqualTo(DisplaySettings.class.getName());
|
||||
assertThat(intent.getIntExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY, -1))
|
||||
.isEqualTo(SettingsEnums.DISPLAY);
|
||||
verify(mFeatureFactory.metricsFeatureProvider).action(
|
||||
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW, "BrightnessAnomaly");
|
||||
verify(mFeatureFactory.metricsFeatureProvider).action(
|
||||
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT, "BrightnessAnomaly");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onClick_dismissBtn_cardDismissAndLogged() {
|
||||
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);
|
||||
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(
|
||||
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW, "ScreenTimeoutAnomaly");
|
||||
verify(mFeatureFactory.metricsFeatureProvider).action(
|
||||
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_DISMISS, "ScreenTimeoutAnomaly");
|
||||
}
|
||||
@@ -137,30 +151,40 @@ public final class BatteryTipsCardPreferenceTest {
|
||||
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);
|
||||
mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(appsAnomaly, appsAnomaly);
|
||||
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(
|
||||
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW, "AppAnomaly");
|
||||
verify(mFeatureFactory.metricsFeatureProvider).action(
|
||||
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT, "AppAnomaly");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onClick_dismissBtnOfAppsAnomaly_removeHighlightSlotIndex() {
|
||||
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);
|
||||
mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(appsAnomaly, appsAnomaly);
|
||||
mBatteryTipsCardPreference.onClick(mFakeView);
|
||||
|
||||
assertThat(mBatteryTipsCardPreference.isVisible()).isFalse();
|
||||
verify(mContext, never()).startActivity(any(Intent.class));
|
||||
verify(mBatteryChartPreferenceController).onHighlightSlotIndexUpdate(
|
||||
eq(BatteryChartViewModel.SELECTED_INDEX_INVALID),
|
||||
eq(BatteryChartViewModel.SELECTED_INDEX_INVALID));
|
||||
eq(1), eq(0));
|
||||
verify(mBatteryChartPreferenceController, never()).selectHighlightSlotIndex();
|
||||
verify(mFeatureFactory.metricsFeatureProvider).action(
|
||||
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW, "AppAnomaly");
|
||||
verify(mFeatureFactory.metricsFeatureProvider).action(
|
||||
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_DISMISS, "AppAnomaly");
|
||||
}
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
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.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -70,30 +68,18 @@ public final class BatteryTipsControllerTest {
|
||||
|
||||
@Test
|
||||
public void handleBatteryTipsCardUpdated_null_hidePreference() {
|
||||
mBatteryTipsController.handleBatteryTipsCardUpdated(/* powerAnomalyEvents= */ null);
|
||||
mBatteryTipsController.handleBatteryTipsCardUpdated(/* powerAnomalyEvents= */ null, false);
|
||||
|
||||
verify(mBatteryTipsCardPreference).setVisible(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDismissRecordKey_returnExpectedResult() {
|
||||
assertThat(BatteryTipsController.getDismissRecordKey(
|
||||
BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent()))
|
||||
.isEqualTo("KEY_BRIGHTNESS");
|
||||
assertThat(BatteryTipsController.getDismissRecordKey(
|
||||
BatteryTestUtils.createScreenTimeoutAnomalyEvent()))
|
||||
.isEqualTo("KEY_SCREEN_TIMEOUT");
|
||||
assertThat(BatteryTipsController.getDismissRecordKey(
|
||||
BatteryTestUtils.createAppAnomalyEvent()))
|
||||
.isEqualTo("KEY_APP_1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleBatteryTipsCardUpdated_adaptiveBrightnessAnomaly_showAnomaly() {
|
||||
PowerAnomalyEvent event = BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent();
|
||||
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
|
||||
|
||||
mBatteryTipsController.handleBatteryTipsCardUpdated(event);
|
||||
mBatteryTipsController.handleBatteryTipsCardUpdated(
|
||||
new AnomalyEventWrapper(mContext, event), false);
|
||||
|
||||
// Check pre-defined string
|
||||
verify(mBatteryTipsCardPreference).setTitle(
|
||||
@@ -114,7 +100,8 @@ public final class BatteryTipsControllerTest {
|
||||
PowerAnomalyEvent event = BatteryTestUtils.createScreenTimeoutAnomalyEvent();
|
||||
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
|
||||
|
||||
mBatteryTipsController.handleBatteryTipsCardUpdated(event);
|
||||
mBatteryTipsController.handleBatteryTipsCardUpdated(
|
||||
new AnomalyEventWrapper(mContext, event), false);
|
||||
|
||||
verify(mBatteryTipsCardPreference).setTitle("Reduce screen timeout to extend battery life");
|
||||
verify(mBatteryTipsCardPreference).setIconResourceId(R.drawable.ic_battery_tips_lightbulb);
|
||||
@@ -139,7 +126,8 @@ public final class BatteryTipsControllerTest {
|
||||
.build();
|
||||
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
|
||||
|
||||
mBatteryTipsController.handleBatteryTipsCardUpdated(event);
|
||||
mBatteryTipsController.handleBatteryTipsCardUpdated(
|
||||
new AnomalyEventWrapper(mContext, event), false);
|
||||
|
||||
verify(mBatteryTipsCardPreference).setTitle(testTitle);
|
||||
verify(mBatteryTipsCardPreference).setIconResourceId(R.drawable.ic_battery_tips_lightbulb);
|
||||
@@ -157,10 +145,13 @@ public final class BatteryTipsControllerTest {
|
||||
PowerAnomalyEvent event = BatteryTestUtils.createAppAnomalyEvent();
|
||||
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
|
||||
|
||||
mBatteryTipsController.handleBatteryTipsCardUpdated(event);
|
||||
AnomalyEventWrapper eventWrapper = new AnomalyEventWrapper(mContext, event);
|
||||
eventWrapper.setRelatedBatteryDiffEntry(
|
||||
new BatteryDiffEntry(mContext, "", "Chrome", 0));
|
||||
mBatteryTipsController.handleBatteryTipsCardUpdated(eventWrapper, false);
|
||||
|
||||
verify(mBatteryTipsCardPreference).setTitle(
|
||||
"Chrome used more battery than usual in foreground");
|
||||
"Chrome used more battery than usual");
|
||||
verify(mBatteryTipsCardPreference).setIconResourceId(
|
||||
R.drawable.ic_battery_tips_warning_icon);
|
||||
verify(mBatteryTipsCardPreference).setMainButtonStrokeColorResourceId(
|
||||
|
||||
@@ -69,7 +69,7 @@ public final class BatteryUsageBreakdownControllerTest {
|
||||
@Mock
|
||||
private BatteryHistEntry mBatteryHistEntry;
|
||||
@Mock
|
||||
private PowerGaugePreference mPowerGaugePreference;
|
||||
private AnomalyAppItemPreference mAnomalyAppItemPreference;
|
||||
|
||||
private Context mContext;
|
||||
private FakeFeatureFactory mFeatureFactory;
|
||||
@@ -123,13 +123,14 @@ public final class BatteryUsageBreakdownControllerTest {
|
||||
BatteryDiffEntry.sResourceCache.put(
|
||||
"fakeBatteryDiffEntryKey",
|
||||
new BatteryEntry.NameAndIcon("fakeName", /*icon=*/ null, /*iconId=*/ 1));
|
||||
doReturn(mAnomalyAppItemPreference).when(mAppListPreferenceGroup).findPreference(PREF_KEY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDestroy_clearPreferenceCacheAndPreferenceGroupRemoveAll() {
|
||||
// Ensures the testing environment is correct.
|
||||
mBatteryUsageBreakdownController.mPreferenceCache.put(
|
||||
PREF_KEY, mPowerGaugePreference);
|
||||
PREF_KEY, mAnomalyAppItemPreference);
|
||||
assertThat(mBatteryUsageBreakdownController.mPreferenceCache).hasSize(1);
|
||||
|
||||
mBatteryUsageBreakdownController.onDestroy();
|
||||
@@ -178,7 +179,6 @@ public final class BatteryUsageBreakdownControllerTest {
|
||||
doReturn(mDrawable).when(mBatteryDiffEntry).getAppIcon();
|
||||
doReturn(appLabel).when(mBatteryDiffEntry).getAppLabel();
|
||||
doReturn(PREF_KEY).when(mBatteryDiffEntry).getKey();
|
||||
doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).findPreference(PREF_KEY);
|
||||
|
||||
mBatteryUsageBreakdownController.addAllPreferences();
|
||||
|
||||
@@ -188,27 +188,25 @@ public final class BatteryUsageBreakdownControllerTest {
|
||||
@Test
|
||||
public void removeAndCacheAllUnusedPreferences_removePref_buildCacheAndRemoveAllPreference() {
|
||||
doReturn(1).when(mAppListPreferenceGroup).getPreferenceCount();
|
||||
doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).getPreference(0);
|
||||
doReturn(mAnomalyAppItemPreference).when(mAppListPreferenceGroup).getPreference(0);
|
||||
doReturn(PREF_KEY2).when(mBatteryHistEntry).getKey();
|
||||
doReturn(PREF_KEY).when(mPowerGaugePreference).getKey();
|
||||
doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).findPreference(PREF_KEY);
|
||||
doReturn(PREF_KEY).when(mAnomalyAppItemPreference).getKey();
|
||||
// Ensures the testing data is correct.
|
||||
assertThat(mBatteryUsageBreakdownController.mPreferenceCache).isEmpty();
|
||||
|
||||
mBatteryUsageBreakdownController.removeAndCacheAllUnusedPreferences();
|
||||
|
||||
assertThat(mBatteryUsageBreakdownController.mPreferenceCache.get(PREF_KEY))
|
||||
.isEqualTo(mPowerGaugePreference);
|
||||
verify(mAppListPreferenceGroup).removePreference(mPowerGaugePreference);
|
||||
.isEqualTo(mAnomalyAppItemPreference);
|
||||
verify(mAppListPreferenceGroup).removePreference(mAnomalyAppItemPreference);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeAndCacheAllUnusedPreferences_keepPref_KeepAllPreference() {
|
||||
doReturn(1).when(mAppListPreferenceGroup).getPreferenceCount();
|
||||
doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).getPreference(0);
|
||||
doReturn(mAnomalyAppItemPreference).when(mAppListPreferenceGroup).getPreference(0);
|
||||
doReturn(PREF_KEY).when(mBatteryDiffEntry).getKey();
|
||||
doReturn(PREF_KEY).when(mPowerGaugePreference).getKey();
|
||||
doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).findPreference(PREF_KEY);
|
||||
doReturn(PREF_KEY).when(mAnomalyAppItemPreference).getKey();
|
||||
// Ensures the testing data is correct.
|
||||
assertThat(mBatteryUsageBreakdownController.mPreferenceCache).isEmpty();
|
||||
|
||||
@@ -232,10 +230,10 @@ public final class BatteryUsageBreakdownControllerTest {
|
||||
@Test
|
||||
public void handlePreferenceTreeClick_forAppEntry_returnTrue() {
|
||||
mBatteryDiffEntry.mConsumerType = ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY;
|
||||
doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry();
|
||||
doReturn(mBatteryDiffEntry).when(mAnomalyAppItemPreference).getBatteryDiffEntry();
|
||||
|
||||
assertThat(mBatteryUsageBreakdownController.handlePreferenceTreeClick(
|
||||
mPowerGaugePreference)).isTrue();
|
||||
mAnomalyAppItemPreference)).isTrue();
|
||||
verify(mMetricsFeatureProvider)
|
||||
.action(
|
||||
SettingsEnums.OPEN_BATTERY_USAGE,
|
||||
@@ -248,10 +246,10 @@ public final class BatteryUsageBreakdownControllerTest {
|
||||
@Test
|
||||
public void handlePreferenceTreeClick_forSystemEntry_returnTrue() {
|
||||
mBatteryDiffEntry.mConsumerType = ConvertUtils.CONSUMER_TYPE_UID_BATTERY;
|
||||
doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry();
|
||||
doReturn(mBatteryDiffEntry).when(mAnomalyAppItemPreference).getBatteryDiffEntry();
|
||||
|
||||
assertThat(mBatteryUsageBreakdownController.handlePreferenceTreeClick(
|
||||
mPowerGaugePreference)).isTrue();
|
||||
mAnomalyAppItemPreference)).isTrue();
|
||||
verify(mMetricsFeatureProvider)
|
||||
.action(
|
||||
SettingsEnums.OPEN_BATTERY_USAGE,
|
||||
|
||||
@@ -72,6 +72,7 @@ public final class ConvertUtilsTest {
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
ConvertUtils.sUsageSource = ConvertUtils.EMPTY_USAGE_SOURCE;
|
||||
when(mContext.getPackageManager()).thenReturn(mMockPackageManager);
|
||||
|
||||
@@ -20,8 +20,8 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.isNull;
|
||||
import static org.mockito.ArgumentMatchers.notNull;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.content.Context;
|
||||
@@ -41,7 +41,9 @@ import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = ShadowDashboardFragment.class)
|
||||
@@ -50,6 +52,9 @@ public final class PowerUsageAdvancedTest {
|
||||
private Context mContext;
|
||||
private PowerUsageAdvanced mPowerUsageAdvanced;
|
||||
|
||||
private Predicate<PowerAnomalyEvent> mCardFilterPredicate;
|
||||
private Predicate<PowerAnomalyEvent> mSlotFilterPredicate;
|
||||
|
||||
@Mock
|
||||
private BatteryTipsController mBatteryTipsController;
|
||||
@Mock
|
||||
@@ -65,7 +70,7 @@ public final class PowerUsageAdvancedTest {
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
|
||||
mPowerUsageAdvanced = new PowerUsageAdvanced();
|
||||
mPowerUsageAdvanced = spy(new PowerUsageAdvanced());
|
||||
mPowerUsageAdvanced.mBatteryTipsController = mBatteryTipsController;
|
||||
mPowerUsageAdvanced.mBatteryChartPreferenceController = mBatteryChartPreferenceController;
|
||||
mPowerUsageAdvanced.mScreenOnTimeController = mScreenOnTimeController;
|
||||
@@ -74,43 +79,63 @@ public final class PowerUsageAdvancedTest {
|
||||
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(mContext).when(mPowerUsageAdvanced).getContext();
|
||||
mSlotFilterPredicate = PowerAnomalyEvent::hasWarningItemInfo;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getHighestScoreAnomalyEvent_withEmptyOrNullList_getNull() {
|
||||
assertThat(PowerUsageAdvanced.getHighestScoreAnomalyEvent(mContext, null)).isNull();
|
||||
assertThat(PowerUsageAdvanced.getHighestScoreAnomalyEvent(
|
||||
mContext, BatteryTestUtils.createEmptyPowerAnomalyEventList())).isNull();
|
||||
public void getFilterAnomalyEvent_withEmptyOrNullList_getNull() {
|
||||
prepareCardFilterPredicate(null);
|
||||
assertThat(PowerUsageAdvanced
|
||||
.getAnomalyEvent(null, mCardFilterPredicate)).isNull();
|
||||
assertThat(PowerUsageAdvanced
|
||||
.getAnomalyEvent(null, mSlotFilterPredicate)).isNull();
|
||||
assertThat(PowerUsageAdvanced.getAnomalyEvent(
|
||||
BatteryTestUtils.createEmptyPowerAnomalyEventList(), mCardFilterPredicate))
|
||||
.isNull();
|
||||
assertThat(PowerUsageAdvanced.getAnomalyEvent(
|
||||
BatteryTestUtils.createEmptyPowerAnomalyEventList(), mSlotFilterPredicate))
|
||||
.isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getHighestScoreAnomalyEvent_withoutDismissed_getHighestScoreEvent() {
|
||||
public void getFilterAnomalyEvent_withoutDismissed_getHighestScoreEvent() {
|
||||
final PowerAnomalyEventList powerAnomalyEventList =
|
||||
BatteryTestUtils.createNonEmptyPowerAnomalyEventList();
|
||||
|
||||
final PowerAnomalyEvent highestScoreEvent =
|
||||
PowerUsageAdvanced.getHighestScoreAnomalyEvent(mContext, powerAnomalyEventList);
|
||||
final PowerAnomalyEvent slotEvent =
|
||||
PowerUsageAdvanced.getAnomalyEvent(powerAnomalyEventList,
|
||||
mSlotFilterPredicate);
|
||||
prepareCardFilterPredicate(slotEvent);
|
||||
final PowerAnomalyEvent cardEvent =
|
||||
PowerUsageAdvanced.getAnomalyEvent(powerAnomalyEventList,
|
||||
mCardFilterPredicate);
|
||||
|
||||
assertThat(highestScoreEvent)
|
||||
.isEqualTo(BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent());
|
||||
assertThat(cardEvent).isEqualTo(BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent());
|
||||
assertThat(slotEvent).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getHighestScoreAnomalyEvent_withBrightnessDismissed_getScreenTimeout() {
|
||||
public void getFilterAnomalyEvent_withBrightnessDismissed_getScreenTimeout() {
|
||||
final PowerAnomalyEventList powerAnomalyEventList =
|
||||
BatteryTestUtils.createNonEmptyPowerAnomalyEventList();
|
||||
DatabaseUtils.removeDismissedPowerAnomalyKeys(mContext);
|
||||
DatabaseUtils.setDismissedPowerAnomalyKeys(mContext, PowerAnomalyKey.KEY_BRIGHTNESS.name());
|
||||
|
||||
final PowerAnomalyEvent highestScoreEvent =
|
||||
PowerUsageAdvanced.getHighestScoreAnomalyEvent(mContext, powerAnomalyEventList);
|
||||
final PowerAnomalyEvent slotEvent =
|
||||
PowerUsageAdvanced.getAnomalyEvent(powerAnomalyEventList,
|
||||
mSlotFilterPredicate);
|
||||
prepareCardFilterPredicate(slotEvent);
|
||||
final PowerAnomalyEvent cardEvent =
|
||||
PowerUsageAdvanced.getAnomalyEvent(powerAnomalyEventList,
|
||||
mCardFilterPredicate);
|
||||
|
||||
assertThat(highestScoreEvent)
|
||||
.isEqualTo(BatteryTestUtils.createScreenTimeoutAnomalyEvent());
|
||||
assertThat(cardEvent).isEqualTo(BatteryTestUtils.createScreenTimeoutAnomalyEvent());
|
||||
assertThat(slotEvent).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getHighestScoreAnomalyEvent_withAllDismissed_getNull() {
|
||||
public void getFilterAnomalyEvent_withAllDismissed_getNull() {
|
||||
final PowerAnomalyEventList powerAnomalyEventList =
|
||||
BatteryTestUtils.createNonEmptyPowerAnomalyEventList();
|
||||
DatabaseUtils.removeDismissedPowerAnomalyKeys(mContext);
|
||||
@@ -118,20 +143,26 @@ public final class PowerUsageAdvancedTest {
|
||||
DatabaseUtils.setDismissedPowerAnomalyKeys(mContext, key.name());
|
||||
}
|
||||
|
||||
final PowerAnomalyEvent highestScoreEvent =
|
||||
PowerUsageAdvanced.getHighestScoreAnomalyEvent(mContext, powerAnomalyEventList);
|
||||
final PowerAnomalyEvent slotEvent =
|
||||
PowerUsageAdvanced.getAnomalyEvent(powerAnomalyEventList,
|
||||
mSlotFilterPredicate);
|
||||
prepareCardFilterPredicate(slotEvent);
|
||||
final PowerAnomalyEvent cardEvent =
|
||||
PowerUsageAdvanced.getAnomalyEvent(powerAnomalyEventList,
|
||||
mCardFilterPredicate);
|
||||
|
||||
assertThat(highestScoreEvent).isNull();
|
||||
assertThat(cardEvent).isNull();
|
||||
assertThat(slotEvent).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDisplayAnomalyEventUpdated_withSettingsAnomalyEvent_skipHighlightSlotEffect() {
|
||||
final PowerAnomalyEvent event = BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent();
|
||||
|
||||
mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(event);
|
||||
mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(event, event);
|
||||
|
||||
assertThat(mPowerUsageAdvanced.mPowerAnomalyEvent).isEqualTo(event);
|
||||
verify(mBatteryTipsController).handleBatteryTipsCardUpdated(eq(event));
|
||||
assertThat(mPowerUsageAdvanced.mHighlightEventWrapper.get().getEventId())
|
||||
.isEqualTo(event.getEventId());
|
||||
verify(mPowerUsageAdvanced.mBatteryTipsController).setOnAnomalyConfirmListener(isNull());
|
||||
verify(mPowerUsageAdvanced.mBatteryTipsController).setOnAnomalyRejectListener(isNull());
|
||||
verify(mPowerUsageAdvanced.mBatteryChartPreferenceController).onHighlightSlotIndexUpdate(
|
||||
@@ -140,46 +171,44 @@ public final class PowerUsageAdvancedTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDisplayAnomalyEventUpdated_withAppAnomalyEvent_setHighlightSlotEffect() {
|
||||
public void onDisplayAnomalyEventUpdated_onlyAppAnomalyEvent_setHighlightSlotEffect() {
|
||||
final PowerAnomalyEvent event = BatteryTestUtils.createAppAnomalyEvent();
|
||||
|
||||
mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(event);
|
||||
mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(event, event);
|
||||
|
||||
assertThat(mPowerUsageAdvanced.mPowerAnomalyEvent).isEqualTo(event);
|
||||
verify(mBatteryTipsController).handleBatteryTipsCardUpdated(eq(event));
|
||||
assertThat(mPowerUsageAdvanced.mHighlightEventWrapper.get().getEventId())
|
||||
.isEqualTo(event.getEventId());
|
||||
verify(mBatteryTipsController).setOnAnomalyConfirmListener(isNull());
|
||||
verify(mBatteryTipsController).setOnAnomalyRejectListener(isNull());
|
||||
|
||||
assertThat(event.getWarningItemInfo().hasStartTimestamp()).isTrue();
|
||||
assertThat(event.getWarningItemInfo().hasEndTimestamp()).isTrue();
|
||||
assertThat(mPowerUsageAdvanced.mBatteryLevelData.get().getIndexByTimestamps(
|
||||
event.getWarningItemInfo().getStartTimestamp(),
|
||||
event.getWarningItemInfo().getEndTimestamp()
|
||||
)).isEqualTo(Pair.create(1, 0));
|
||||
verify(mBatteryChartPreferenceController).onHighlightSlotIndexUpdate(eq(1), eq(0));
|
||||
verify(mBatteryTipsController).setOnAnomalyConfirmListener(notNull());
|
||||
verify(mBatteryTipsController).setOnAnomalyRejectListener(notNull());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDisplayAnomalyEventUpdated_withNull_removeHighlightSlotEffect() {
|
||||
final PowerAnomalyEvent event = BatteryTestUtils.createAppAnomalyEvent();
|
||||
public void onDisplayAnomalyEventUpdated_withSettingsCardAndAppsSlotEvent_showExpected() {
|
||||
final PowerAnomalyEvent settingsEvent =
|
||||
BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent();
|
||||
final PowerAnomalyEvent appsEvent =
|
||||
BatteryTestUtils.createAppAnomalyEvent();
|
||||
|
||||
mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(event);
|
||||
mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(null);
|
||||
mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(settingsEvent, appsEvent);
|
||||
|
||||
assertThat(mPowerUsageAdvanced.mPowerAnomalyEvent).isNull();
|
||||
verify(mBatteryTipsController, times(2))
|
||||
.setOnAnomalyConfirmListener(isNull());
|
||||
verify(mBatteryTipsController, times(2))
|
||||
.setOnAnomalyRejectListener(isNull());
|
||||
verify(mBatteryTipsController).setOnAnomalyConfirmListener(notNull());
|
||||
verify(mBatteryTipsController).setOnAnomalyRejectListener(notNull());
|
||||
|
||||
verify(mBatteryChartPreferenceController)
|
||||
.onHighlightSlotIndexUpdate(eq(1), eq(0));
|
||||
verify(mBatteryChartPreferenceController).onHighlightSlotIndexUpdate(
|
||||
eq(BatteryChartViewModel.SELECTED_INDEX_INVALID),
|
||||
eq(BatteryChartViewModel.SELECTED_INDEX_INVALID));
|
||||
assertThat(mPowerUsageAdvanced.mHighlightEventWrapper.get().getEventId())
|
||||
.isEqualTo(appsEvent.getEventId());
|
||||
verify(mBatteryChartPreferenceController).onHighlightSlotIndexUpdate(eq(1), eq(0));
|
||||
verify(mBatteryTipsController).setOnAnomalyConfirmListener(isNull());
|
||||
verify(mBatteryTipsController).setOnAnomalyRejectListener(isNull());
|
||||
}
|
||||
}
|
||||
|
||||
private void prepareCardFilterPredicate(PowerAnomalyEvent slotEvent) {
|
||||
final Set<String> dismissedPowerAnomalyKeys =
|
||||
DatabaseUtils.getDismissedPowerAnomalyKeys(mContext);
|
||||
mCardFilterPredicate = event -> !dismissedPowerAnomalyKeys.contains(
|
||||
event.getDismissRecordKey())
|
||||
&& (event.equals(slotEvent) || !event.hasWarningItemInfo());
|
||||
}
|
||||
}
|
||||
@@ -247,6 +247,7 @@ public class BatteryTestUtils {
|
||||
.setEventId("BrightnessAnomaly")
|
||||
.setType(PowerAnomalyType.TYPE_SETTINGS_BANNER)
|
||||
.setKey(PowerAnomalyKey.KEY_BRIGHTNESS)
|
||||
.setDismissRecordKey(PowerAnomalyKey.KEY_BRIGHTNESS.name())
|
||||
.setScore(1.2f)
|
||||
.setWarningBannerInfo(WarningBannerInfo.newBuilder()
|
||||
.setMainButtonDestination(DisplaySettings.class.getName())
|
||||
@@ -264,6 +265,7 @@ public class BatteryTestUtils {
|
||||
.setEventId("ScreenTimeoutAnomaly")
|
||||
.setType(PowerAnomalyType.TYPE_SETTINGS_BANNER)
|
||||
.setKey(PowerAnomalyKey.KEY_SCREEN_TIMEOUT)
|
||||
.setDismissRecordKey(PowerAnomalyKey.KEY_SCREEN_TIMEOUT.name())
|
||||
.setScore(1.1f)
|
||||
.setWarningBannerInfo(WarningBannerInfo.newBuilder()
|
||||
.setMainButtonDestination(ScreenTimeoutSettings.class.getName())
|
||||
@@ -280,15 +282,12 @@ public class BatteryTestUtils {
|
||||
return PowerAnomalyEvent.newBuilder()
|
||||
.setEventId("AppAnomaly")
|
||||
.setType(PowerAnomalyType.TYPE_APPS_ITEM)
|
||||
.setKey(PowerAnomalyKey.KEY_APP)
|
||||
.setKey(PowerAnomalyKey.KEY_APP_TOTAL_HIGHER_THAN_USUAL)
|
||||
.setDismissRecordKey("KEY_APP_1")
|
||||
.setScore(2.0f)
|
||||
.setWarningItemInfo(WarningItemInfo.newBuilder()
|
||||
.setDismissRecordKey("KEY_APP_1")
|
||||
.setStartTimestamp(1694361600000L) // 2023-09-11 00:00:00
|
||||
.setEndTimestamp(1694368800000L) // 2023-09-11 02:00:00
|
||||
.setTitleString("Chrome used more battery than usual in foreground")
|
||||
.setMainButtonString("Check")
|
||||
.setCancelButtonString("Got it")
|
||||
.build())
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -18,9 +18,7 @@ package com.android.settings.network;
|
||||
|
||||
import static com.android.settings.network.SubscriptionUtil.KEY_UNIQUE_SUBSCRIPTION_DISPLAYNAME;
|
||||
import static com.android.settings.network.SubscriptionUtil.SUB_ID;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
@@ -185,7 +183,7 @@ public class SubscriptionUtilTest {
|
||||
@Ignore
|
||||
@Test
|
||||
public void getUniqueDisplayNames_identicalCarriers_fourDigitsUsed() {
|
||||
// Both subscriptoins have the same display name.
|
||||
// Both subscriptions have the same display name.
|
||||
final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
|
||||
final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
|
||||
when(info1.getSubscriptionId()).thenReturn(SUBID_1);
|
||||
@@ -215,7 +213,7 @@ public class SubscriptionUtilTest {
|
||||
@Ignore
|
||||
@Test
|
||||
public void getUniqueDisplayNames_identicalCarriersAfterTrim_fourDigitsUsed() {
|
||||
// Both subscriptoins have the same display name.
|
||||
// Both subscriptions have the same display name.
|
||||
final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
|
||||
final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
|
||||
when(info1.getSubscriptionId()).thenReturn(SUBID_1);
|
||||
@@ -244,8 +242,8 @@ public class SubscriptionUtilTest {
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
public void getUniqueDisplayNames_phoneNumberBlocked_subscriptoinIdFallback() {
|
||||
// Both subscriptoins have the same display name.
|
||||
public void getUniqueDisplayNames_phoneNumberBlocked_subscriptionIdFallback() {
|
||||
// Both subscriptions have the same display name.
|
||||
final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
|
||||
final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
|
||||
when(info1.getSubscriptionId()).thenReturn(SUBID_1);
|
||||
@@ -273,9 +271,9 @@ public class SubscriptionUtilTest {
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
public void getUniqueDisplayNames_phoneNumberIdentical_subscriptoinIdFallback() {
|
||||
public void getUniqueDisplayNames_phoneNumberIdentical_subscriptionIdFallback() {
|
||||
// TODO have three here from the same carrier
|
||||
// Both subscriptoins have the same display name.
|
||||
// Both subscriptions have the same display name.
|
||||
final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
|
||||
final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
|
||||
final SubscriptionInfo info3 = mock(SubscriptionInfo.class);
|
||||
@@ -464,8 +462,8 @@ public class SubscriptionUtilTest {
|
||||
SharedPreferences sp = mock(SharedPreferences.class);
|
||||
when(mContext.getSharedPreferences(
|
||||
KEY_UNIQUE_SUBSCRIPTION_DISPLAYNAME, Context.MODE_PRIVATE)).thenReturn(sp);
|
||||
when(sp.getString(eq(SUB_ID + SUBID_1), anyString())).thenReturn(CARRIER_1 + "6789");
|
||||
when(sp.getString(eq(SUB_ID + SUBID_2), anyString())).thenReturn(CARRIER_1 + "4321");
|
||||
when(sp.getString(eq(SUB_ID + SUBID_1), anyString())).thenReturn(CARRIER_1 + " 6789");
|
||||
when(sp.getString(eq(SUB_ID + SUBID_2), anyString())).thenReturn(CARRIER_1 + " 4321");
|
||||
|
||||
|
||||
final CharSequence nameOfSub1 =
|
||||
@@ -475,8 +473,41 @@ public class SubscriptionUtilTest {
|
||||
|
||||
assertThat(nameOfSub1).isNotNull();
|
||||
assertThat(nameOfSub2).isNotNull();
|
||||
assertEquals(CARRIER_1 + "6789", nameOfSub1.toString());
|
||||
assertEquals(CARRIER_1 + "4321", nameOfSub2.toString());
|
||||
assertEquals(CARRIER_1 + " 6789", nameOfSub1.toString());
|
||||
assertEquals(CARRIER_1 + " 4321", nameOfSub2.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getUniqueDisplayName_hasRecordAndNameIsChanged_doesNotUseRecordBeTheResult() {
|
||||
final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
|
||||
final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
|
||||
when(info1.getSubscriptionId()).thenReturn(SUBID_1);
|
||||
when(info2.getSubscriptionId()).thenReturn(SUBID_2);
|
||||
when(info1.getDisplayName()).thenReturn(CARRIER_1);
|
||||
when(info2.getDisplayName()).thenReturn(CARRIER_2);
|
||||
when(mSubMgr.getAvailableSubscriptionInfoList()).thenReturn(
|
||||
Arrays.asList(info1, info2));
|
||||
|
||||
SharedPreferences sp = mock(SharedPreferences.class);
|
||||
SharedPreferences.Editor editor = mock(SharedPreferences.Editor.class);
|
||||
when(mContext.getSharedPreferences(
|
||||
KEY_UNIQUE_SUBSCRIPTION_DISPLAYNAME, Context.MODE_PRIVATE)).thenReturn(sp);
|
||||
when(sp.edit()).thenReturn(editor);
|
||||
when(editor.remove(anyString())).thenReturn(editor);
|
||||
|
||||
when(sp.getString(eq(SUB_ID + SUBID_1), anyString())).thenReturn(CARRIER_1 + " 6789");
|
||||
when(sp.getString(eq(SUB_ID + SUBID_2), anyString())).thenReturn(CARRIER_1 + " 4321");
|
||||
|
||||
|
||||
final CharSequence nameOfSub1 =
|
||||
SubscriptionUtil.getUniqueSubscriptionDisplayName(info1, mContext);
|
||||
final CharSequence nameOfSub2 =
|
||||
SubscriptionUtil.getUniqueSubscriptionDisplayName(info2, mContext);
|
||||
|
||||
assertThat(nameOfSub1).isNotNull();
|
||||
assertThat(nameOfSub2).isNotNull();
|
||||
assertEquals(CARRIER_1 + " 6789", nameOfSub1.toString());
|
||||
assertEquals(CARRIER_2.toString(), nameOfSub2.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -501,4 +532,60 @@ public class SubscriptionUtilTest {
|
||||
|
||||
assertTrue(SubscriptionUtil.isSimHardwareVisible(mContext));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isValidCachedDisplayName_matchesRule1_returnTrue() {
|
||||
String originalName = "originalName";
|
||||
String cacheString = "originalName 1234";
|
||||
|
||||
assertThat(SubscriptionUtil.isValidCachedDisplayName(cacheString, originalName)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isValidCachedDisplayName_matchesRule2_returnTrue() {
|
||||
String originalName = "original Name";
|
||||
String cacheString = originalName + " " + 1234;
|
||||
|
||||
assertThat(SubscriptionUtil.isValidCachedDisplayName(cacheString, originalName)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isValidCachedDisplayName_nameIsEmpty1_returnFalse() {
|
||||
String originalName = "original Name";
|
||||
String cacheString = "";
|
||||
|
||||
assertThat(SubscriptionUtil.isValidCachedDisplayName(cacheString, originalName)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isValidCachedDisplayName_nameIsEmpty2_returnFalse() {
|
||||
String originalName = "";
|
||||
String cacheString = "originalName 1234";
|
||||
|
||||
assertThat(SubscriptionUtil.isValidCachedDisplayName(cacheString, originalName)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isValidCachedDisplayName_nameIsDifferent_returnFalse() {
|
||||
String originalName = "original Name";
|
||||
String cacheString = "originalName 1234";
|
||||
|
||||
assertThat(SubscriptionUtil.isValidCachedDisplayName(cacheString, originalName)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isValidCachedDisplayName_noNumber_returnFalse() {
|
||||
String originalName = "original Name";
|
||||
String cacheString = originalName;
|
||||
|
||||
assertThat(SubscriptionUtil.isValidCachedDisplayName(cacheString, originalName)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isValidCachedDisplayName_noSpace_returnFalse() {
|
||||
String originalName = "original Name";
|
||||
String cacheString = originalName;
|
||||
|
||||
assertThat(SubscriptionUtil.isValidCachedDisplayName(cacheString, originalName)).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user